changeset 16682:1c8f054f6278

8173393: Module system implementation refresh (2/2017) Reviewed-by: dfuchs, psandoz, mchung, alanb Contributed-by: alan.bateman@oracle.com, mandy.chung@oracle.com, claes.redestad@oracle.com, alex.buckley@oracle.com, mark.reinhold@oracle.com, john.r.rose@oracle.com
author alanb
date Fri, 10 Feb 2017 09:04:39 +0000
parents 847d7a6aef45
children d35044f37cdb
files make/src/classes/build/tools/jigsaw/GenGraphs.java make/src/classes/build/tools/jigsaw/ModuleSummary.java src/java.base/share/classes/java/lang/Class.java src/java.base/share/classes/java/lang/ClassLoader.java src/java.base/share/classes/java/lang/IllegalCallerException.java src/java.base/share/classes/java/lang/Package.java src/java.base/share/classes/java/lang/SecurityManager.java src/java.base/share/classes/java/lang/StackStreamFactory.java src/java.base/share/classes/java/lang/StackTraceElement.java src/java.base/share/classes/java/lang/StackWalker.java src/java.base/share/classes/java/lang/System.java src/java.base/share/classes/java/lang/invoke/MethodHandles.java src/java.base/share/classes/java/lang/module/Configuration.java src/java.base/share/classes/java/lang/module/FindException.java src/java.base/share/classes/java/lang/module/InvalidModuleDescriptorException.java src/java.base/share/classes/java/lang/module/ModuleDescriptor.java src/java.base/share/classes/java/lang/module/ModuleFinder.java src/java.base/share/classes/java/lang/module/ModuleReader.java src/java.base/share/classes/java/lang/module/ModuleReference.java src/java.base/share/classes/java/lang/module/ResolutionException.java src/java.base/share/classes/java/lang/module/ResolvedModule.java src/java.base/share/classes/java/lang/module/Resolver.java src/java.base/share/classes/java/lang/module/package-info.java src/java.base/share/classes/java/lang/reflect/AccessibleObject.java src/java.base/share/classes/java/lang/reflect/Constructor.java src/java.base/share/classes/java/lang/reflect/Field.java src/java.base/share/classes/java/lang/reflect/InaccessibleObjectException.java src/java.base/share/classes/java/lang/reflect/Layer.java src/java.base/share/classes/java/lang/reflect/LayerInstantiationException.java src/java.base/share/classes/java/lang/reflect/Method.java src/java.base/share/classes/java/lang/reflect/Module.java src/java.base/share/classes/java/lang/reflect/Proxy.java src/java.base/share/classes/java/lang/reflect/package-info.java src/java.base/share/classes/java/net/URLClassLoader.java src/java.base/share/classes/java/security/SecureClassLoader.java src/java.base/share/classes/java/security/Security.java src/java.base/share/classes/java/util/ResourceBundle.java src/java.base/share/classes/java/util/ServiceLoader.java src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java src/java.base/share/classes/java/util/spi/ResourceBundleControlProvider.java src/java.base/share/classes/java/util/spi/ResourceBundleProvider.java src/java.base/share/classes/jdk/internal/jmod/JmodFile.java src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java src/java.base/share/classes/jdk/internal/loader/ResourceHelper.java src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java src/java.base/share/classes/jdk/internal/module/Builder.java src/java.base/share/classes/jdk/internal/module/Checks.java src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java src/java.base/share/classes/jdk/internal/module/ModuleInfo.java src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java src/java.base/share/classes/jdk/internal/module/ModulePatcher.java src/java.base/share/classes/jdk/internal/module/ModulePath.java src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java src/java.base/share/classes/jdk/internal/module/ModuleReferences.java src/java.base/share/classes/jdk/internal/module/Modules.java src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java src/java.base/share/classes/jdk/internal/reflect/Reflection.java src/java.base/share/classes/sun/invoke/util/VerifyAccess.java src/java.base/share/classes/sun/launcher/LauncherHelper.java src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnector.java src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java src/jdk.jartool/share/classes/sun/tools/jar/Main.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java test/ProblemList.txt test/java/io/FilePermission/ReadFileOnPath.java test/java/lang/Class/forName/modules/TestLayer.java test/java/lang/Class/forName/modules/src/m3/p3/NoAccess.java test/java/lang/Class/getPackageName/Basic.java test/java/lang/StackWalker/CallerFromMain.java test/java/lang/invoke/AccessControlTest.java test/java/lang/invoke/DropLookupModeTest.java test/java/lang/invoke/MethodHandles/privateLookupIn/Driver.java test/java/lang/invoke/MethodHandles/privateLookupIn/Unnamed.java test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java test/java/lang/invoke/modules/Driver.java test/java/lang/invoke/modules/ModuleAccessControlTest.java test/java/lang/invoke/modules/Unnamed.java test/java/lang/invoke/modules/m1/module-info.java test/java/lang/invoke/modules/m1/p1/Main.java test/java/lang/invoke/modules/m1/p1/Type1.java test/java/lang/invoke/modules/m1/p2/Type2.java test/java/lang/invoke/modules/m2/module-info.java test/java/lang/invoke/modules/m2/q1/Type1.java test/java/lang/invoke/modules/m2/q2/Type2.java test/java/lang/invoke/modules/src/m1/module-info.java test/java/lang/invoke/modules/src/m1/p1/Main.java test/java/lang/invoke/modules/src/m1/p1/Type1.java test/java/lang/invoke/modules/src/m1/p2/Type2.java test/java/lang/invoke/modules/src/m2/module-info.java test/java/lang/invoke/modules/src/m2/q1/Type1.java test/java/lang/invoke/modules/src/m2/q2/Type2.java test/java/lang/module/AutomaticModulesTest.java test/java/lang/module/ConfigurationTest.java test/java/lang/module/ModuleDescriptorTest.java test/java/lang/module/ModuleFinderTest.java test/java/lang/module/ModuleNamesTest.java test/java/lang/module/ModuleReader/ModuleReaderTest.java test/java/lang/module/ModuleReferenceTest.java test/java/lang/module/MultiReleaseJarTest.java test/java/lang/reflect/AccessibleObject/CanAccessTest.java test/java/lang/reflect/AccessibleObject/ModuleSetAccessibleTest.java test/java/lang/reflect/AccessibleObject/TrySetAccessibleTest.java test/java/lang/reflect/Layer/BasicLayerTest.java test/java/lang/reflect/Layer/LayerAndLoadersTest.java test/java/lang/reflect/Layer/LayerControllerTest.java test/java/lang/reflect/Module/AnnotationsTest.java test/java/lang/reflect/Module/BasicModuleTest.java test/java/lang/reflect/Module/WithSecurityManager.java test/java/lang/reflect/Module/addXXX/Driver.java test/java/lang/reflect/Module/addXXX/m1/module-info.java test/java/lang/reflect/Module/addXXX/m1/p1/C.java test/java/lang/reflect/Module/addXXX/m2/module-info.java test/java/lang/reflect/Module/addXXX/m2/p2/C.java test/java/lang/reflect/Module/addXXX/m2/p2/internal/C.java test/java/lang/reflect/Module/addXXX/m3/module-info.java test/java/lang/reflect/Module/addXXX/m3/p3/C.java test/java/lang/reflect/Module/addXXX/m4/module-info.java test/java/lang/reflect/Module/addXXX/m4/p4/C.java test/java/lang/reflect/Module/addXXX/test/module-info.java test/java/lang/reflect/Module/addXXX/test/test/C.java test/java/lang/reflect/Module/addXXX/test/test/Main.java test/java/lang/reflect/Module/addXXX/test/test/Service.java test/java/lang/reflect/Proxy/ProxyClassAccessTest.java test/java/lang/reflect/Proxy/ProxyLayerTest.java test/java/security/modules/ModularTest.java test/java/util/ServiceLoader/modules/BadProvidersTest.java test/java/util/ServiceLoader/modules/Basic.java test/jdk/internal/reflect/CallerSensitive/CheckCSMs.java test/jdk/modules/etc/VerifyModuleDelegation.java test/jdk/modules/scenarios/container/src/container/container/Main.java test/sun/management/jdp/JdpJmxRemoteDynamicPortTest.java test/tools/jar/mmrjar/Basic.java test/tools/jar/modularJar/Basic.java test/tools/jlink/JLinkNegativeTest.java test/tools/jmod/hashes/HashesTest.java test/tools/launcher/modules/patch/systemmodules/src1/java.base/jdk/internal/modules/SystemModules.java
diffstat 147 files changed, 6029 insertions(+), 3266 deletions(-) [+]
line wrap: on
line diff
--- a/make/src/classes/build/tools/jigsaw/GenGraphs.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/make/src/classes/build/tools/jigsaw/GenGraphs.java	Fri Feb 10 09:04:39 2017 +0000
@@ -153,9 +153,9 @@
      */
     void genDotFile(String name, Set<String> roots) throws IOException {
         Configuration cf =
-            Configuration.empty().resolveRequires(ModuleFinder.ofSystem(),
-                                                  ModuleFinder.of(),
-                                                  roots);
+            Configuration.empty().resolve(ModuleFinder.ofSystem(),
+                                          ModuleFinder.of(),
+                                          roots);
 
         Set<ModuleDescriptor> mds = cf.modules().stream()
                 .map(ResolvedModule::reference)
--- a/make/src/classes/build/tools/jigsaw/ModuleSummary.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/make/src/classes/build/tools/jigsaw/ModuleSummary.java	Fri Feb 10 09:04:39 2017 +0000
@@ -291,9 +291,9 @@
 
     static Configuration resolve(Set<String> roots) {
         return Configuration.empty()
-            .resolveRequires(ModuleFinder.ofSystem(),
-                             ModuleFinder.of(),
-                             roots);
+            .resolve(ModuleFinder.ofSystem(),
+                     ModuleFinder.of(),
+                     roots);
     }
 
     static class HtmlDocument {
--- a/src/java.base/share/classes/java/lang/Class.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/Class.java	Fri Feb 10 09:04:39 2017 +0000
@@ -425,6 +425,7 @@
      *         </ul>
      *
      * @since 9
+     * @spec JPMS
      */
     @CallerSensitive
     public static Class<?> forName(Module module, String name) {
@@ -819,6 +820,7 @@
      * @return the module that this class or interface is a member of
      *
      * @since 9
+     * @spec JPMS
      */
     public Module getModule() {
         return module;
@@ -924,6 +926,8 @@
      * this method returns {@code null}.
      *
      * @return the package of this class.
+     * @revised 9
+     * @spec JPMS
      */
     public Package getPackage() {
         if (isPrimitive() || isArray()) {
@@ -951,20 +955,30 @@
      * declaring class} of the {@link #getEnclosingMethod enclosing method} or
      * {@link #getEnclosingConstructor enclosing constructor}.
      *
-     * <p> This method returns {@code null} if this class represents an array type,
-     * a primitive type or void.
+     * <p> If this class represents an array type then this method returns the
+     * package name of the element type. If this class represents a primitive
+     * type or void then the package name "{@code java.lang}" is returned.
      *
      * @return the fully qualified package name
      *
      * @since 9
+     * @spec JPMS
      * @jls 6.7  Fully Qualified Names
      */
     public String getPackageName() {
         String pn = this.packageName;
-        if (pn == null && !isArray() && !isPrimitive()) {
-            String cn = getName();
-            int dot = cn.lastIndexOf('.');
-            pn = (dot != -1) ? cn.substring(0, dot).intern() : "";
+        if (pn == null) {
+            Class<?> c = this;
+            while (c.isArray()) {
+                c = c.getComponentType();
+            }
+            if (c.isPrimitive()) {
+                pn = "java.lang";
+            } else {
+                String cn = c.getName();
+                int dot = cn.lastIndexOf('.');
+                pn = (dot != -1) ? cn.substring(0, dot).intern() : "";
+            }
             this.packageName = pn;
         }
         return pn;
@@ -2491,10 +2505,16 @@
      * Finds a resource with a given name.
      *
      * <p> If this class is in a named {@link Module Module} then this method
-     * will attempt to find the resource in the module by means of the absolute
-     * resource name, subject to the rules for encapsulation specified in the
-     * {@code Module} {@link Module#getResourceAsStream getResourceAsStream}
-     * method.
+     * will attempt to find the resource in the module. This is done by
+     * delegating to the module's class loader {@link
+     * ClassLoader#findResource(String,String) findResource(String,String)}
+     * method, invoking it with the module name and the absolute name of the
+     * resource. Resources in named modules are subject to the rules for
+     * encapsulation specified in the {@code Module} {@link
+     * Module#getResourceAsStream getResourceAsStream} method and so this
+     * method returns {@code null} when the resource is a
+     * non-"{@code .class}" resource in a package that is not open to the
+     * caller's module.
      *
      * <p> Otherwise, if this class is not in a named module then the rules for
      * searching resources associated with a given class are implemented by the
@@ -2503,9 +2523,8 @@
      * the bootstrap class loader, the method delegates to {@link
      * ClassLoader#getSystemResourceAsStream}.
      *
-     * <p> Before finding a resource in the caller's module or delegation to a
-     * class loader, an absolute resource name is constructed from the given
-     * resource name using this algorithm:
+     * <p> Before delegation, an absolute resource name is constructed from the
+     * given resource name using this algorithm:
      *
      * <ul>
      *
@@ -2532,7 +2551,11 @@
      *          least the caller module, or access to the resource is denied
      *          by the security manager.
      * @throws  NullPointerException If {@code name} is {@code null}
+     *
+     * @see Module#getResourceAsStream(String)
      * @since  1.1
+     * @revised 9
+     * @spec JPMS
      */
     @CallerSensitive
     public InputStream getResourceAsStream(String name) {
@@ -2585,10 +2608,16 @@
      * Finds a resource with a given name.
      *
      * <p> If this class is in a named {@link Module Module} then this method
-     * will attempt to find the resource in the module by means of the absolute
-     * resource name, subject to the rules for encapsulation specified in the
-     * {@code Module} {@link Module#getResourceAsStream getResourceAsStream}
-     * method.
+     * will attempt to find the resource in the module. This is done by
+     * delegating to the module's class loader {@link
+     * ClassLoader#findResource(String,String) findResource(String,String)}
+     * method, invoking it with the module name and the absolute name of the
+     * resource. Resources in named modules are subject to the rules for
+     * encapsulation specified in the {@code Module} {@link
+     * Module#getResourceAsStream getResourceAsStream} method and so this
+     * method returns {@code null} when the resource is a
+     * non-"{@code .class}" resource in a package that is not open to the
+     * caller's module.
      *
      * <p> Otherwise, if this class is not in a named module then the rules for
      * searching resources associated with a given class are implemented by the
@@ -2627,6 +2656,8 @@
      *         manager.
      * @throws NullPointerException If {@code name} is {@code null}
      * @since  1.1
+     * @revised 9
+     * @spec JPMS
      */
     @CallerSensitive
     public URL getResource(String name) {
--- a/src/java.base/share/classes/java/lang/ClassLoader.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/ClassLoader.java	Fri Feb 10 09:04:39 2017 +0000
@@ -207,6 +207,8 @@
  * @jls 13.1 The Form of a Binary
  * @see      #resolveClass(Class)
  * @since 1.0
+ * @revised 9
+ * @spec JPMS
  */
 public abstract class ClassLoader {
 
@@ -380,12 +382,12 @@
      *         method doesn't allow creation of a new class loader.
      *
      * @since  9
+     * @spec JPMS
      */
     protected ClassLoader(String name, ClassLoader parent) {
         this(checkCreateClassLoader(name), name, parent);
     }
 
-
     /**
      * Creates a new class loader using the specified parent class loader for
      * delegation.
@@ -440,6 +442,7 @@
      * this class loader is not named.
      *
      * @since 9
+     * @spec JPMS
      */
     public String getName() {
         return name;
@@ -710,6 +713,7 @@
      *         if the class could not be found.
      *
      * @since 9
+     * @spec JPMS
      */
     protected Class<?> findClass(String moduleName, String name) {
         if (moduleName == null) {
@@ -834,6 +838,8 @@
      * @see  java.security.SecureClassLoader
      *
      * @since  1.1
+     * @revised 9
+     * @spec JPMS
      */
     protected final Class<?> defineClass(String name, byte[] b, int off, int len)
         throws ClassFormatError
@@ -967,6 +973,9 @@
      *          certificates than this class, or if {@code name} begins with
      *          "{@code java.}" and this class loader is not the platform
      *          class loader or its ancestor.
+     *
+     * @revised 9
+     * @spec JPMS
      */
     protected final Class<?> defineClass(String name, byte[] b, int off, int len,
                                          ProtectionDomain protectionDomain)
@@ -1041,6 +1050,8 @@
      * @see      #defineClass(String, byte[], int, int, ProtectionDomain)
      *
      * @since  1.5
+     * @revised 9
+     * @spec JPMS
      */
     protected final Class<?> defineClass(String name, java.nio.ByteBuffer b,
                                          ProtectionDomain protectionDomain)
@@ -1264,11 +1275,11 @@
      * Class loader implementations that support the loading from modules
      * should override this method.
      *
-     * @apiNote This method is the basis for the {@code Class} {@link
-     * Class#getResource getResource} and {@link Class#getResourceAsStream
-     * getResourceAsStream} methods. It is not subject to the rules for
-     * encapsulation specified by {@code Module} {@link
-     * Module#getResourceAsStream getResourceAsStream}.
+     * @apiNote This method is the basis for the {@link
+     * Class#getResource Class.getResource}, {@link Class#getResourceAsStream
+     * Class.getResourceAsStream}, and {@link Module#getResourceAsStream
+     * Module.getResourceAsStream} methods. It is not subject to the rules for
+     * encapsulation specified by {@code Module.getResourceAsStream}.
      *
      * @implSpec The default implementation attempts to find the resource by
      * invoking {@link #findResource(String)} when the {@code moduleName} is
@@ -1292,6 +1303,7 @@
      *
      * @see java.lang.module.ModuleReader#find(String)
      * @since 9
+     * @spec JPMS
      */
     protected URL findResource(String moduleName, String name) throws IOException {
         if (moduleName == null) {
@@ -1342,6 +1354,8 @@
      * @throws  NullPointerException If {@code name} is {@code null}
      *
      * @since  1.1
+     * @revised 9
+     * @spec JPMS
      */
     public URL getResource(String name) {
         Objects.requireNonNull(name);
@@ -1403,6 +1417,8 @@
      * @see  #findResources(String)
      *
      * @since  1.2
+     * @revised 9
+     * @spec JPMS
      */
     public Enumeration<URL> getResources(String name) throws IOException {
         Objects.requireNonNull(name);
@@ -1499,6 +1515,8 @@
      *          denied by the security manager.
      *
      * @since  1.2
+     * @revised 9
+     * @spec JPMS
      */
     protected URL findResource(String name) {
         return null;
@@ -1531,6 +1549,8 @@
      *          If I/O errors occur
      *
      * @since  1.2
+     * @revised 9
+     * @spec JPMS
      */
     protected Enumeration<URL> findResources(String name) throws IOException {
         return Collections.emptyEnumeration();
@@ -1601,6 +1621,8 @@
      *          denied by the security manager.
      *
      * @since  1.1
+     * @revised 9
+     * @spec JPMS
      */
     public static URL getSystemResource(String name) {
         return getSystemClassLoader().getResource(name);
@@ -1636,6 +1658,8 @@
      *          If I/O errors occur
      *
      * @since  1.2
+     * @revised 9
+     * @spec JPMS
      */
     public static Enumeration<URL> getSystemResources(String name)
         throws IOException
@@ -1667,6 +1691,8 @@
      * @throws  NullPointerException If {@code name} is {@code null}
      *
      * @since  1.1
+     * @revised 9
+     * @spec JPMS
      */
     public InputStream getResourceAsStream(String name) {
         Objects.requireNonNull(name);
@@ -1699,6 +1725,8 @@
      *          denied by the security manager.
      *
      * @since  1.1
+     * @revised 9
+     * @spec JPMS
      */
     public static InputStream getSystemResourceAsStream(String name) {
         URL url = getSystemResource(name);
@@ -1749,6 +1777,7 @@
      *
      * @see Module#isNamed()
      * @since 9
+     * @spec JPMS
      */
     public final Module getUnnamedModule() {
         return unnamedModule;
@@ -1772,6 +1801,7 @@
      *          {@link RuntimePermission}{@code ("getClassLoader")}
      *
      * @since 9
+     * @spec JPMS
      */
     @CallerSensitive
     public static ClassLoader getPlatformClassLoader() {
@@ -1847,6 +1877,8 @@
      *          {@link Throwable#getCause()} method.
      *
      * @revised  1.4
+     * @revised 9
+     * @spec JPMS
      */
     @CallerSensitive
     public static ClassLoader getSystemClassLoader() {
@@ -2101,6 +2133,8 @@
      *          defined by this class loader
      *
      * @since  1.2
+     * @revised 9
+     * @spec JPMS
      *
      * @see <a href="../../../technotes/guides/jar/jar.html#versioning">
      *      The JAR File Specification: Package Versioning</a>
@@ -2138,6 +2172,7 @@
      *          if {@code name} is {@code null}.
      *
      * @since  9
+     * @spec JPMS
      */
     public final Package getDefinedPackage(String name) {
         Objects.requireNonNull(name, "name cannot be null");
@@ -2160,6 +2195,7 @@
      *         or an zero length array if no package has been defined by this class loader.
      *
      * @since  9
+     * @spec JPMS
      */
     public final Package[] getDefinedPackages() {
         return packages().toArray(Package[]::new);
@@ -2196,6 +2232,8 @@
      * a {@code Package} for the specified class loader.
      *
      * @since  1.2
+     * @revised 9
+     * @spec JPMS
      */
     @Deprecated(since="9")
     protected Package getPackage(String name) {
@@ -2220,6 +2258,8 @@
      *          class loader and its ancestors
      *
      * @since  1.2
+     * @revised 9
+     * @spec JPMS
      */
     protected Package[] getPackages() {
         Stream<Package> pkgs = packages();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/IllegalCallerException.java	Fri Feb 10 09:04:39 2017 +0000
@@ -0,0 +1,76 @@
+/*
+ * 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 java.lang;
+
+/**
+ * Thrown to indicate that a method has been called by an inappropriate caller.
+ *
+ * @since 9
+ * @spec JPMS
+ * @see StackWalker#getCallerClass
+ */
+public class IllegalCallerException extends RuntimeException {
+    /**
+     * Constructs an IllegalCallerException with no detail message.
+     */
+    public IllegalCallerException() {
+        super();
+    }
+
+    /**
+     * Constructs an IllegalCallerException with the specified detail
+     * message.
+     *
+     * @param s the String that contains a detailed message (can be null)
+     */
+    public IllegalCallerException(String s) {
+        super(s);
+    }
+
+    /**
+     * Constructs a new exception with the specified detail message and
+     * cause.
+     *
+     * @param  message the detail message (can be null)
+     * @param  cause the cause (can be null)
+     */
+    public IllegalCallerException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructs a new exception with the specified cause and a detail
+     * message of {@code (cause==null ? null : cause.toString())} (which
+     * typically contains the class and detail message of {@code cause}).
+     *
+     * @param  cause the cause (can be null)
+     */
+    public IllegalCallerException(Throwable cause) {
+        super(cause);
+    }
+
+    static final long serialVersionUID = -2349421918363102232L;
+}
--- a/src/java.base/share/classes/java/lang/Package.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/Package.java	Fri Feb 10 09:04:39 2017 +0000
@@ -111,6 +111,8 @@
  * @see ClassLoader#definePackage(String, String, String, String, String, String, String, URL)
  *
  * @since 1.2
+ * @revised 9
+ * @spec JPMS
  */
 public class Package extends NamedPackage implements java.lang.reflect.AnnotatedElement {
     /**
@@ -207,6 +209,9 @@
      * is returned if it is not known.
      * @return the vendor that implemented this package, {@code null}
      * is returned if it is not known.
+     *
+     * @revised 9
+     * @spec JPMS
      */
     public String getImplementationVendor() {
         return versionInfo.implVendor;
@@ -334,6 +339,9 @@
      * a {@code Package} for the specified class loader.
      *
      * @see ClassLoader#getDefinedPackage
+     *
+     * @revised 9
+     * @spec JPMS
      */
     @CallerSensitive
     @Deprecated(since="9")
@@ -356,6 +364,9 @@
      *          class loader and its ancestors
      *
      * @see ClassLoader#getDefinedPackages
+     *
+     * @revised 9
+     * @spec JPMS
      */
     @CallerSensitive
     public static Package[] getPackages() {
--- a/src/java.base/share/classes/java/lang/SecurityManager.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/SecurityManager.java	Fri Feb 10 09:04:39 2017 +0000
@@ -1458,6 +1458,18 @@
     }
 
     /**
+     * Called by java.security.Security
+     */
+    static void invalidatePackageAccessCache() {
+        synchronized (packageAccessLock) {
+            packageAccessValid = false;
+        }
+        synchronized (packageDefinitionLock) {
+            packageDefinitionValid = false;
+        }
+    }
+
+    /**
      * Returns true if the module's loader is the boot or platform loader.
      */
     private static boolean isBootOrPlatformModule(Module m) {
--- a/src/java.base/share/classes/java/lang/StackStreamFactory.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/StackStreamFactory.java	Fri Feb 10 09:04:39 2017 +0000
@@ -684,7 +684,7 @@
                 frames[n++] = caller;
             }
             if (frames[1] == null) {
-                throw new IllegalStateException("no caller frame");
+                throw new IllegalCallerException("no caller frame");
             }
             return n;
         }
--- a/src/java.base/share/classes/java/lang/StackTraceElement.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/StackTraceElement.java	Fri Feb 10 09:04:39 2017 +0000
@@ -92,6 +92,8 @@
      * @throws NullPointerException if {@code declaringClass} or
      *         {@code methodName} is null
      * @since 1.5
+     * @revised 9
+     * @spec JPMS
      */
     public StackTraceElement(String declaringClass, String methodName,
                              String fileName, int lineNumber) {
@@ -128,6 +130,7 @@
      *         or {@code methodName} is {@code null}
      *
      * @since 9
+     * @spec JPMS
      */
     public StackTraceElement(String classLoaderName,
                              String moduleName, String moduleVersion,
@@ -187,6 +190,7 @@
      *         point represented by this stack trace element; {@code null}
      *         if the module name is not available.
      * @since 9
+     * @spec JPMS
      * @see java.lang.reflect.Module#getName()
      */
     public String getModuleName() {
@@ -201,6 +205,7 @@
      *         point represented by this stack trace element; {@code null}
      *         if the module version is not available.
      * @since 9
+     * @spec JPMS
      * @see java.lang.module.ModuleDescriptor.Version
      */
     public String getModuleVersion() {
@@ -216,6 +221,7 @@
      *         if the class loader is not named.
      *
      * @since 9
+     * @spec JPMS
      * @see java.lang.ClassLoader#getName()
      */
     public String getClassLoaderName() {
@@ -329,6 +335,8 @@
      * {@link java.lang.StackWalker.StackFrame}, where an implementation may
      * choose to omit some element in the returned string.
      *
+     * @revised 9
+     * @spec JPMS
      * @see    Throwable#printStackTrace()
      */
     public String toString() {
@@ -376,6 +384,9 @@
      * @return true if the specified object is another
      *         {@code StackTraceElement} instance representing the same
      *         execution point as this instance.
+     *
+     * @revised 9
+     * @spec JPMS
      */
     public boolean equals(Object obj) {
         if (obj==this)
--- a/src/java.base/share/classes/java/lang/StackWalker.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/StackWalker.java	Fri Feb 10 09:04:39 2017 +0000
@@ -465,8 +465,8 @@
     }
 
     /**
-     * Gets the {@code Class} object of the caller invoking the method
-     * that calls this {@code getCallerClass} method.
+     * Gets the {@code Class} object of the caller who invoked the method
+     * that invoked {@code getCallerClass}.
      *
      * <p> Reflection frames, {@link java.lang.invoke.MethodHandle}, and
      * hidden frames are filtered regardless of the
@@ -474,19 +474,21 @@
      * and {@link Option#SHOW_HIDDEN_FRAMES SHOW_HIDDEN_FRAMES} options
      * this {@code StackWalker} has been configured with.
      *
+     * <p> This method should be called when a caller frame is present.  If
+     * it is called from the bottom most frame on the stack,
+     * {@code IllegalCallerException} will be thrown.
+     *
      * <p> This method throws {@code UnsupportedOperationException}
      * if this {@code StackWalker} is not configured with the
      * {@link Option#RETAIN_CLASS_REFERENCE RETAIN_CLASS_REFERENCE} option.
-     * This method should be called when a caller frame is present.  If
-     * it is called from the last frame on the stack,
-     * {@code IllegalStateException} will be thrown.
      *
      * @apiNote
      * For example, {@code Util::getResourceBundle} loads a resource bundle
-     * on behalf of the caller.  It calls this {@code getCallerClass} method
-     * to find the method calling {@code Util::getResourceBundle} and uses the caller's
-     * class loader to load the resource bundle. The caller class in this example
-     * is the {@code MyTool} class.
+     * on behalf of the caller.  It invokes {@code getCallerClass} to identify
+     * the class whose method called {@code Util::getResourceBundle}.
+     * Then, it obtains the class loader of that class, and uses
+     * the class loader to load the resource bundle. The caller class
+     * in this example is {@code MyTool}.
      *
      * <pre>{@code
      * class Util {
@@ -517,17 +519,17 @@
      * }</pre>
      *
      * When the {@code getCallerClass} method is called from a method that
-     * is the last frame on the stack,
+     * is the bottom most frame on the stack,
      * for example, {@code static public void main} method launched by the
      * {@code java} launcher, or a method invoked from a JNI attached thread,
-     * {@code IllegalStateException} is thrown.
+     * {@code IllegalCallerException} is thrown.
      *
      * @return {@code Class} object of the caller's caller invoking this method.
      *
      * @throws UnsupportedOperationException if this {@code StackWalker}
      *         is not configured with {@link Option#RETAIN_CLASS_REFERENCE
      *         Option.RETAIN_CLASS_REFERENCE}.
-     * @throws IllegalStateException if there is no caller frame, i.e.
+     * @throws IllegalCallerException if there is no caller frame, i.e.
      *         when this {@code getCallerClass} method is called from a method
      *         which is the last frame on the stack.
      */
--- a/src/java.base/share/classes/java/lang/System.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/System.java	Fri Feb 10 09:04:39 2017 +0000
@@ -1942,10 +1942,6 @@
      * the application classpath or modulepath.
      */
     private static void initPhase3() {
-        // Initialize publicLookup early, to avoid bootstrapping circularities
-        // with security manager using java.lang.invoke infrastructure.
-        java.lang.invoke.MethodHandles.publicLookup();
-
         // set security manager
         String cn = System.getProperty("java.security.manager");
         if (cn != null) {
@@ -2053,6 +2049,9 @@
             public String fastUUID(long lsb, long msb) {
                 return Long.fastUUID(lsb, msb);
             }
+            public void invalidatePackageAccessCache() {
+                SecurityManager.invalidatePackageAccessCache();
+            }
         });
     }
 }
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Fri Feb 10 09:04:39 2017 +0000
@@ -25,8 +25,6 @@
 
 package java.lang.invoke;
 
-import jdk.internal.org.objectweb.asm.ClassWriter;
-import jdk.internal.org.objectweb.asm.Opcodes;
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.Reflection;
 import jdk.internal.vm.annotation.ForceInline;
@@ -111,13 +109,17 @@
 
     /**
      * Returns a {@link Lookup lookup object} which is trusted minimally.
-     * It can only be used to create method handles to public members in
+     * The lookup has the {@code PUBLIC} and {@code UNCONDITIONAL} modes.
+     * It can only be used to create method handles to public members of
      * public classes in packages that are exported unconditionally.
      * <p>
-     * For now, the {@linkplain Lookup#lookupClass lookup class} of this lookup
-     * object is in an unnamed module.
-     * Consequently, the lookup context of this lookup object will be the bootstrap
-     * class loader, which means it cannot find user classes.
+     * As a matter of pure convention, the {@linkplain Lookup#lookupClass lookup class}
+     * of this lookup object will be {@link java.lang.Object}.
+     *
+     * @apiNote The use of Object is conventional, and because the lookup modes are
+     * limited, there is no special access provided to the internals of Object, its package
+     * or its module. Consequently, the lookup context of this lookup object will be the
+     * bootstrap class loader, which means it cannot find user classes.
      *
      * <p style="font-size:smaller;">
      * <em>Discussion:</em>
@@ -129,17 +131,12 @@
      * Also, it cannot access
      * <a href="MethodHandles.Lookup.html#callsens">caller sensitive methods</a>.
      * @return a lookup object which is trusted minimally
+     *
+     * @revised 9
+     * @spec JPMS
      */
     public static Lookup publicLookup() {
-        // During VM startup then only classes in the java.base module can be
-        // loaded and linked. This is because java.base exports aren't setup until
-        // the module system is initialized, hence types in the unnamed module
-        // (or any named module) can't link to java/lang/Object.
-        if (!jdk.internal.misc.VM.isModuleSystemInited()) {
-            return new Lookup(Object.class, Lookup.PUBLIC);
-        } else {
-            return LookupHelper.PUBLIC_LOOKUP;
-        }
+        return Lookup.PUBLIC_LOOKUP;
     }
 
     /**
@@ -172,6 +169,7 @@
      * @throws IllegalAccessException if the access check specified above fails
      * @throws SecurityException if denied by the security manager
      * @since 9
+     * @spec JPMS
      * @see Lookup#dropLookupMode
      */
     public static Lookup privateLookupIn(Class<?> targetClass, Lookup lookup) throws IllegalAccessException {
@@ -183,11 +181,11 @@
             throw new IllegalArgumentException(targetClass + " is an array class");
         Module targetModule = targetClass.getModule();
         Module callerModule = lookup.lookupClass().getModule();
-        if (callerModule != targetModule && targetModule.isNamed()) {
-            if (!callerModule.canRead(targetModule))
-                throw new IllegalAccessException(callerModule + " does not read " + targetModule);
+        if (!callerModule.canRead(targetModule))
+            throw new IllegalAccessException(callerModule + " does not read " + targetModule);
+        if (targetModule.isNamed()) {
             String pn = targetClass.getPackageName();
-            assert pn != null && pn.length() > 0 : "unnamed package cannot be in named module";
+            assert pn.length() > 0 : "unnamed package cannot be in named module";
             if (!targetModule.isOpen(pn, callerModule))
                 throw new IllegalAccessException(targetModule + " does not open " + pn + " to " + callerModule);
         }
@@ -601,6 +599,8 @@
      * so that there can be a secure foundation for lookups.
      * Nearly all other methods in the JSR 292 API rely on lookup
      * objects to check access requests.
+     *
+     * @revised 9
      */
     public static final
     class Lookup {
@@ -647,15 +647,33 @@
          *  lookup class and public types in packages exported by other modules
          *  to the module of the lookup class.
          *  @since 9
+         *  @spec JPMS
          */
         public static final int MODULE = PACKAGE << 1;
 
-        private static final int ALL_MODES = (PUBLIC | PRIVATE | PROTECTED | PACKAGE | MODULE);
+        /** A single-bit mask representing {@code unconditional} access
+         *  which may contribute to the result of {@link #lookupModes lookupModes}.
+         *  The value is {@code 0x20}, which does not correspond meaningfully to
+         *  any particular {@linkplain java.lang.reflect.Modifier modifier bit}.
+         *  A {@code Lookup} with this lookup mode assumes {@linkplain
+         *  java.lang.reflect.Module#canRead(java.lang.reflect.Module) readability}.
+         *  In conjunction with the {@code PUBLIC} modifier bit, a {@code Lookup}
+         *  with this lookup mode can access all public members of public types
+         *  of all modules where the type is in a package that is {@link
+         *  java.lang.reflect.Module#isExported(String) exported unconditionally}.
+         *  @since 9
+         *  @spec JPMS
+         *  @see #publicLookup()
+         */
+        public static final int UNCONDITIONAL = PACKAGE << 2;
+
+        private static final int ALL_MODES = (PUBLIC | PRIVATE | PROTECTED | PACKAGE | MODULE | UNCONDITIONAL);
+        private static final int FULL_POWER_MODES = (ALL_MODES & ~UNCONDITIONAL);
         private static final int TRUSTED   = -1;
 
         private static int fixmods(int mods) {
-            mods &= (ALL_MODES - PACKAGE - MODULE);
-            return (mods != 0) ? mods : (PACKAGE | MODULE);
+            mods &= (ALL_MODES - PACKAGE - MODULE - UNCONDITIONAL);
+            return (mods != 0) ? mods : (PACKAGE | MODULE | UNCONDITIONAL);
         }
 
         /** Tells which class is performing the lookup.  It is this class against
@@ -682,13 +700,14 @@
          *  {@linkplain #PRIVATE PRIVATE (0x02)},
          *  {@linkplain #PROTECTED PROTECTED (0x04)},
          *  {@linkplain #PACKAGE PACKAGE (0x08)},
-         *  and {@linkplain #MODULE MODULE (0x10)}.
+         *  {@linkplain #MODULE MODULE (0x10)},
+         *  and {@linkplain #UNCONDITIONAL UNCONDITIONAL (0x20)}.
          *  <p>
          *  A freshly-created lookup object
-         *  on the {@linkplain java.lang.invoke.MethodHandles#lookup() caller's class}
-         *  has all possible bits set, since the caller class can access all its own members,
-         *  all public types in the caller's module, and all public types in packages exported
-         *  by other modules to the caller's module.
+         *  on the {@linkplain java.lang.invoke.MethodHandles#lookup() caller's class} has
+         *  all possible bits set, except {@code UNCONDITIONAL}. The lookup can be used to
+         *  access all members of the caller's class, all public types in the caller's module,
+         *  and all public types in packages exported by other modules to the caller's module.
          *  A lookup object on a new lookup class
          *  {@linkplain java.lang.invoke.MethodHandles.Lookup#in created from a previous lookup object}
          *  may have some mode bits set to zero.
@@ -701,6 +720,9 @@
          *  @return the lookup modes, which limit the kinds of access performed by this lookup object
          *  @see #in
          *  @see #dropLookupMode
+         *
+         *  @revised 9
+         *  @spec JPMS
          */
         public int lookupModes() {
             return allowedModes & ALL_MODES;
@@ -712,9 +734,9 @@
          * which in turn is called by a method not in this package.
          */
         Lookup(Class<?> lookupClass) {
-            this(lookupClass, ALL_MODES);
+            this(lookupClass, FULL_POWER_MODES);
             // make sure we haven't accidentally picked up a privileged class:
-            checkUnprivilegedlookupClass(lookupClass, ALL_MODES);
+            checkUnprivilegedlookupClass(lookupClass, FULL_POWER_MODES);
         }
 
         private Lookup(Class<?> lookupClass, int allowedModes) {
@@ -730,19 +752,20 @@
          * However, the resulting {@code Lookup} object is guaranteed
          * to have no more access capabilities than the original.
          * In particular, access capabilities can be lost as follows:<ul>
-         * <li>If the lookup class for this {@code Lookup} is not in a named module,
-         * and the new lookup class is in a named module {@code M}, then no members in
-         * {@code M}'s non-exported packages will be accessible.
-         * <li>If the lookup for this {@code Lookup} is in a named module, and the
-         * new lookup class is in a different module {@code M}, then no members, not even
-         * public members in {@code M}'s exported packages, will be accessible.
-         * <li>If the new lookup class differs from the old one,
-         * protected members will not be accessible by virtue of inheritance.
-         * (Protected members may continue to be accessible because of package sharing.)
+         * <li>If the old lookup class is in a {@link Module#isNamed() named} module, and
+         * the new lookup class is in a different module {@code M}, then no members, not
+         * even public members in {@code M}'s exported packages, will be accessible.
+         * The exception to this is when this lookup is {@link #publicLookup()
+         * publicLookup}, in which case {@code PUBLIC} access is not lost.
+         * <li>If the old lookup class is in an unnamed module, and the new lookup class
+         * is a different module then {@link #MODULE MODULE} access is lost.
+         * <li>If the new lookup class differs from the old one then {@code UNCONDITIONAL} is lost.
          * <li>If the new lookup class is in a different package
          * than the old one, protected and default (package) members will not be accessible.
          * <li>If the new lookup class is not within the same package member
-         * as the old one, private members will not be accessible.
+         * as the old one, private members will not be accessible, and protected members
+         * will not be accessible by virtue of inheritance.
+         * (Protected members may continue to be accessible because of package sharing.)
          * <li>If the new lookup class is not accessible to the old lookup class,
          * then no members, not even public members, will be accessible.
          * (In all other cases, public members will continue to be accessible.)
@@ -757,32 +780,34 @@
          * @return a lookup object which reports the desired lookup class, or the same object
          * if there is no change
          * @throws NullPointerException if the argument is null
+         *
+         * @revised 9
+         * @spec JPMS
          */
         public Lookup in(Class<?> requestedLookupClass) {
             Objects.requireNonNull(requestedLookupClass);
             if (allowedModes == TRUSTED)  // IMPL_LOOKUP can make any lookup at all
-                return new Lookup(requestedLookupClass, ALL_MODES);
+                return new Lookup(requestedLookupClass, FULL_POWER_MODES);
             if (requestedLookupClass == this.lookupClass)
                 return this;  // keep same capabilities
-
-            int newModes = (allowedModes & (ALL_MODES & ~PROTECTED));
+            int newModes = (allowedModes & FULL_POWER_MODES);
             if (!VerifyAccess.isSameModule(this.lookupClass, requestedLookupClass)) {
-                // Allowed to teleport from an unnamed to a named module but resulting
-                // Lookup has no access to module private members
-                if (this.lookupClass.getModule().isNamed()) {
+                // Need to drop all access when teleporting from a named module to another
+                // module. The exception is publicLookup where PUBLIC is not lost.
+                if (this.lookupClass.getModule().isNamed()
+                    && (this.allowedModes & UNCONDITIONAL) == 0)
                     newModes = 0;
-                } else {
-                    newModes &= ~MODULE;
-                }
+                else
+                    newModes &= ~(MODULE|PACKAGE|PRIVATE|PROTECTED);
             }
             if ((newModes & PACKAGE) != 0
                 && !VerifyAccess.isSamePackage(this.lookupClass, requestedLookupClass)) {
-                newModes &= ~(PACKAGE|PRIVATE);
+                newModes &= ~(PACKAGE|PRIVATE|PROTECTED);
             }
             // Allow nestmate lookups to be created without special privilege:
             if ((newModes & PRIVATE) != 0
                 && !VerifyAccess.isSamePackageMember(this.lookupClass, requestedLookupClass)) {
-                newModes &= ~PRIVATE;
+                newModes &= ~(PRIVATE|PROTECTED);
             }
             if ((newModes & PUBLIC) != 0
                 && !VerifyAccess.isClassAccessible(requestedLookupClass, this.lookupClass, allowedModes)) {
@@ -801,28 +826,29 @@
          * finds members, but with a lookup mode that has lost the given lookup mode.
          * The lookup mode to drop is one of {@link #PUBLIC PUBLIC}, {@link #MODULE
          * MODULE}, {@link #PACKAGE PACKAGE}, {@link #PROTECTED PROTECTED} or {@link #PRIVATE PRIVATE}.
-         * {@link #PROTECTED PROTECTED} is always dropped and so the resulting lookup
-         * mode will never have this access capability. When dropping {@code PACKAGE}
-         * then the resulting lookup will not have {@code PACKAGE} or {@code PRIVATE}
-         * access. When dropping {@code MODULE} then the resulting lookup will not
-         * have {@code MODULE}, {@code PACKAGE}, or {@code PRIVATE} access. If {@code
-         * PUBLIC} is dropped then the resulting lookup has no access.
+         * {@link #PROTECTED PROTECTED} and {@link #UNCONDITIONAL UNCONDITIONAL} are always
+         * dropped and so the resulting lookup mode will never have these access capabilities.
+         * When dropping {@code PACKAGE} then the resulting lookup will not have {@code PACKAGE}
+         * or {@code PRIVATE} access. When dropping {@code MODULE} then the resulting lookup will
+         * not have {@code MODULE}, {@code PACKAGE}, or {@code PRIVATE} access. If {@code PUBLIC}
+         * is dropped then the resulting lookup has no access.
          * @param modeToDrop the lookup mode to drop
          * @return a lookup object which lacks the indicated mode, or the same object if there is no change
          * @throws IllegalArgumentException if {@code modeToDrop} is not one of {@code PUBLIC},
-         * {@code MODULE}, {@code PACKAGE}, {@code PROTECTED} or {@code PRIVATE}
+         * {@code MODULE}, {@code PACKAGE}, {@code PROTECTED}, {@code PRIVATE} or {@code UNCONDITIONAL}
+         * @see MethodHandles#privateLookupIn
          * @since 9
-         * @see MethodHandles#privateLookupIn
          */
         public Lookup dropLookupMode(int modeToDrop) {
             int oldModes = lookupModes();
-            int newModes = oldModes & ~(modeToDrop | PROTECTED);
+            int newModes = oldModes & ~(modeToDrop | PROTECTED | UNCONDITIONAL);
             switch (modeToDrop) {
                 case PUBLIC: newModes &= ~(ALL_MODES); break;
                 case MODULE: newModes &= ~(PACKAGE | PRIVATE); break;
                 case PACKAGE: newModes &= ~(PRIVATE); break;
                 case PROTECTED:
-                case PRIVATE: break;
+                case PRIVATE:
+                case UNCONDITIONAL: break;
                 default: throw new IllegalArgumentException(modeToDrop + " is not a valid mode to drop");
             }
             if (newModes == oldModes) return this;  // return self if no change
@@ -835,6 +861,12 @@
         /** Package-private version of lookup which is trusted. */
         static final Lookup IMPL_LOOKUP = new Lookup(Object.class, TRUSTED);
 
+        /** Version of lookup which is trusted minimally.
+         *  It can only be used to create method handles to publicly accessible
+         *  members in packages that are exported unconditionally.
+         */
+        static final Lookup PUBLIC_LOOKUP = new Lookup(Object.class, (PUBLIC|UNCONDITIONAL));
+
         private static void checkUnprivilegedlookupClass(Class<?> lookupClass, int allowedModes) {
             String name = lookupClass.getName();
             if (name.startsWith("java.lang.invoke."))
@@ -845,7 +877,7 @@
             // TODO replace with a more formal and less fragile mechanism
             // that does not bluntly restrict classes under packages within
             // java.base from looking up MethodHandles or VarHandles.
-            if (allowedModes == ALL_MODES && lookupClass.getClassLoader() == null) {
+            if (allowedModes == FULL_POWER_MODES && lookupClass.getClassLoader() == null) {
                 if ((name.startsWith("java.") &&
                      !name.equals("java.lang.Thread") &&
                      !name.startsWith("java.util.concurrent.")) ||
@@ -866,6 +898,7 @@
          * <ul>
          * <li>If no access is allowed, the suffix is "/noaccess".
          * <li>If only public access to types in exported packages is allowed, the suffix is "/public".
+         * <li>If only public access and unconditional access are allowed, the suffix is "/publicLookup".
          * <li>If only public and module access are allowed, the suffix is "/module".
          * <li>If only public, module and package access are allowed, the suffix is "/package".
          * <li>If only public, module, package, and private access are allowed, the suffix is "/private".
@@ -884,6 +917,9 @@
          * because it requires a direct subclass relationship between
          * caller and callee.)
          * @see #in
+         *
+         * @revised 9
+         * @spec JPMS
          */
         @Override
         public String toString() {
@@ -893,13 +929,15 @@
                 return cname + "/noaccess";
             case PUBLIC:
                 return cname + "/public";
+            case PUBLIC|UNCONDITIONAL:
+                return cname  + "/publicLookup";
             case PUBLIC|MODULE:
                 return cname + "/module";
             case PUBLIC|MODULE|PACKAGE:
                 return cname + "/package";
-            case ALL_MODES & ~PROTECTED:
+            case FULL_POWER_MODES & ~PROTECTED:
                 return cname + "/private";
-            case ALL_MODES:
+            case FULL_POWER_MODES:
                 return cname;
             case TRUSTED:
                 return "/trusted";  // internal only; not exported
@@ -1580,6 +1618,7 @@
             if (refKind == REF_invokeSpecial)
                 refKind = REF_invokeVirtual;
             assert(method.isMethod());
+            @SuppressWarnings("deprecation")
             Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
             return lookup.getDirectMethodNoSecurityManager(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method));
         }
@@ -1662,6 +1701,7 @@
         public MethodHandle unreflectConstructor(Constructor<?> c) throws IllegalAccessException {
             MemberName ctor = new MemberName(c);
             assert(ctor.isConstructor());
+            @SuppressWarnings("deprecation")
             Lookup lookup = c.isAccessible() ? IMPL_LOOKUP : this;
             return lookup.getDirectConstructorNoSecurityManager(ctor.getDeclaringClass(), ctor);
         }
@@ -1692,6 +1732,7 @@
             assert(isSetter
                     ? MethodHandleNatives.refKindIsSetter(field.getReferenceKind())
                     : MethodHandleNatives.refKindIsGetter(field.getReferenceKind()));
+            @SuppressWarnings("deprecation")
             Lookup lookup = f.isAccessible() ? IMPL_LOOKUP : this;
             return lookup.getDirectFieldNoSecurityManager(field.getReferenceKind(), f.getDeclaringClass(), field);
         }
@@ -2033,9 +2074,9 @@
                                (defc == refc ||
                                 Modifier.isPublic(refc.getModifiers())));
             if (!classOK && (allowedModes & PACKAGE) != 0) {
-                classOK = (VerifyAccess.isClassAccessible(defc, lookupClass(), ALL_MODES) &&
+                classOK = (VerifyAccess.isClassAccessible(defc, lookupClass(), FULL_POWER_MODES) &&
                            (defc == refc ||
-                            VerifyAccess.isClassAccessible(refc, lookupClass(), ALL_MODES)));
+                            VerifyAccess.isClassAccessible(refc, lookupClass(), FULL_POWER_MODES)));
             }
             if (!classOK)
                 return "class is not public";
@@ -2348,53 +2389,6 @@
     }
 
     /**
-     * Helper class used to lazily create PUBLIC_LOOKUP with a lookup class
-     * in an <em>unnamed module</em>.
-     *
-     * @see Lookup#publicLookup
-     */
-    private static class LookupHelper {
-        private static final String UNNAMED = "Unnamed";
-        private static final String OBJECT  = "java/lang/Object";
-
-        private static Class<?> createClass() {
-            try {
-                ClassWriter cw = new ClassWriter(0);
-                cw.visit(Opcodes.V1_8,
-                         Opcodes.ACC_FINAL + Opcodes.ACC_SUPER,
-                         UNNAMED,
-                         null,
-                         OBJECT,
-                         null);
-                cw.visitSource(UNNAMED, null);
-                cw.visitEnd();
-                byte[] bytes = cw.toByteArray();
-                ClassLoader loader = new ClassLoader(null) {
-                    @Override
-                    protected Class<?> findClass(String cn) throws ClassNotFoundException {
-                        if (cn.equals(UNNAMED))
-                            return super.defineClass(UNNAMED, bytes, 0, bytes.length);
-                        throw new ClassNotFoundException(cn);
-                    }
-                };
-                return loader.loadClass(UNNAMED);
-            } catch (Exception e) {
-                throw new InternalError(e);
-            }
-        }
-
-        private static final Class<?> PUBLIC_LOOKUP_CLASS = createClass();
-
-        /**
-         * Lookup that is trusted minimally. It can only be used to create
-         * method handles to publicly accessible members in exported packages.
-         *
-         * @see MethodHandles#publicLookup
-         */
-        static final Lookup PUBLIC_LOOKUP = new Lookup(PUBLIC_LOOKUP_CLASS, Lookup.PUBLIC);
-    }
-
-    /**
      * Produces a method handle constructing arrays of a desired type.
      * The return type of the method handle will be the array type.
      * The type of its sole argument will be {@code int}, which specifies the size of the array.
--- a/src/java.base/share/classes/java/lang/module/Configuration.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/module/Configuration.java	Fri Feb 10 09:04:39 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, 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
@@ -42,126 +42,48 @@
 import java.util.stream.Stream;
 
 /**
- * The configuration that is the result of resolution or resolution with
- * service binding.
+ * A configuration that is the result of <a href="package-summary.html#resolution">
+ * resolution</a> or resolution with <a href="package-summary.html#servicebinding">
+ * service binding</a>.
  *
- * <h2><a name="resolution">Resolution</a></h2>
+ * <p> A configuration encapsulates the <em>readability graph</em> that is the
+ * output of resolution. A readability graph is a directed graph where the nodes
+ * are of type {@link ResolvedModule} and the edges represent the readability
+ * amongst the modules. {@code Configuration} defines the {@link #modules()
+ * modules()} method to get the set of resolved modules in the graph. {@code
+ * ResolvedModule} defines the {@link ResolvedModule#reads() reads()} method to
+ * get the set of modules that a resolved module reads. The modules that are
+ * read may be in the same configuration or may be in {@link #parents() parent}
+ * configurations. </p>
  *
- * <p> Resolution is the process of computing the transitive closure of a set
- * of root modules over a set of observable modules by resolving the
- * dependences expressed by {@code requires} clauses.
+ * <p> Configuration defines the {@link #resolve(ModuleFinder,List,ModuleFinder,Collection)
+ * resolve} method to resolve a collection of root modules, and the {@link
+ * #resolveAndBind(ModuleFinder,List,ModuleFinder,Collection) resolveAndBind}
+ * method to do resolution with service binding. There are instance and
+ * static variants of both methods. The instance methods create a configuration
+ * with the receiver as the parent configuration. The static methods are for
+ * more advanced cases where there can be more than one parent configuration. </p>
  *
- * The <em>dependence graph</em> is augmented with edges that take account of
- * implicitly declared dependences ({@code requires transitive}) to create a
- * <em>readability graph</em>. A {@code Configuration} encapsulates the
- * resulting graph of {@link ResolvedModule resolved modules}.
- *
- * <p> Suppose we have the following observable modules: </p>
- * <pre> {@code
- *     module m1 { requires m2; }
- *     module m2 { requires transitive m3; }
- *     module m3 { }
- *     module m4 { }
- * } </pre>
- *
- * <p> If the module {@code m1} is resolved then the resulting configuration
- * contains three modules ({@code m1}, {@code m2}, {@code m3}). The edges in
- * its readability graph are: </p>
- * <pre> {@code
- *     m1 --> m2  (meaning m1 reads m2)
- *     m1 --> m3
- *     m2 --> m3
- * } </pre>
- *
- * <p> Resolution is an additive process. When computing the transitive closure
- * then the dependence relation may include dependences on modules in parent
- * configurations. The result is a <em>relative configuration</em> that is
- * relative to one or more parent configurations and where the readability graph
- * may have edges from modules in the configuration to modules in parent
- * configurations.
- *
- * </p>
- *
- * <p> Suppose we have the following observable modules: </p>
- * <pre> {@code
- *     module m1 { requires m2; requires java.xml; }
- *     module m2 { }
- * } </pre>
- *
- * <p> If module {@code m1} is resolved with the configuration for the {@link
- * java.lang.reflect.Layer#boot() boot} layer as the parent then the resulting
- * configuration contains two modules ({@code m1}, {@code m2}). The edges in
- * its readability graph are:
- * <pre> {@code
- *     m1 --> m2
- *     m1 --> java.xml
- * } </pre>
- * where module {@code java.xml} is in the parent configuration. For
- * simplicity, this example omits the implicitly declared dependence on the
- * {@code java.base} module.
- *
- * <a name="automaticmoduleresolution"></a>
- * <p> {@link ModuleDescriptor#isAutomatic() Automatic} modules receive special
- * treatment during resolution. Each automatic module is resolved so that it
- * reads all other modules in the configuration and all parent configurations.
- * Each automatic module is also resolved as if it {@code requires transitive}
- * all other automatic modules in the configuration (and all automatic modules
- * in parent configurations). </p>
-
- * <h2><a name="servicebinding">Service binding</a></h2>
- *
- * <p> Service binding is the process of augmenting a graph of resolved modules
- * from the set of observable modules induced by the service-use dependence
- * ({@code uses} and {@code provides} clauses). Any module that was not
- * previously in the graph requires resolution to compute its transitive
- * closure. Service binding is an iterative process in that adding a module
- * that satisfies some service-use dependence may introduce new service-use
- * dependences. </p>
- *
- * <p> Suppose we have the following observable modules: </p>
- * <pre> {@code
- *     module m1 { exports p; uses p.S; }
- *     module m2 { requires m1; provides p.S with p2.S2; }
- *     module m3 { requires m1; requires m4; provides p.S with p3.S3; }
- *     module m4 { }
- * } </pre>
- *
- * <p> If the module {@code m1} is resolved then the resulting graph of modules
- * has one module ({@code m1}). If the graph is augmented with modules induced
- * by the service-use dependence relation then the configuration will contain
- * four modules ({@code m1}, {@code m2}, {@code m3}, {@code m4}). The edges in
- * its readability graph are: </p>
- * <pre> {@code
- *     m2 --> m1
- *     m3 --> m1
- *     m3 --> m4
- * } </pre>
- * <p> The edges in the conceptual service-use graph are: </p>
- * <pre> {@code
- *     m1 --> m2  (meaning m1 uses a service that is provided by m2)
- *     m1 --> m3
- * } </pre>
- *
- * <p> If this configuration is instantiated as a {@code Layer}, and if code in
- * module {@code m1} uses {@link java.util.ServiceLoader ServiceLoader} to
- * iterate over implementations of {@code p.S.class}, then it will iterate over
- * an instance of {@code p2.S2} and {@code p3.S3}. </p>
+ * <p> Each {@link java.lang.reflect.Layer layer} of modules in the Java virtual
+ * machine is created from a configuration. The configuration for the {@link
+ * java.lang.reflect.Layer#boot() boot} layer is obtained by invoking {@code
+ * Layer.boot().configuration()}. The configuration for the boot layer will
+ * often be the parent when creating new configurations. </p>
  *
  * <h3> Example </h3>
  *
- * <p> The following example uses the {@code resolveRequires} method to resolve
- * a module named <em>myapp</em> with the configuration for the boot layer as
- * the parent configuration. It prints the name of each resolved module and
- * the names of the modules that each module reads. </p>
+ * <p> The following example uses the {@link
+ * #resolve(ModuleFinder,ModuleFinder,Collection) resolve} method to resolve a
+ * module named <em>myapp</em> with the configuration for the boot layer as the
+ * parent configuration. It prints the name of each resolved module and the
+ * names of the modules that each module reads. </p>
  *
  * <pre>{@code
  *    ModuleFinder finder = ModuleFinder.of(dir1, dir2, dir3);
  *
  *    Configuration parent = Layer.boot().configuration();
  *
- *    Configuration cf = parent.resolveRequires(finder,
- *                                              ModuleFinder.of(),
- *                                              Set.of("myapp"));
+ *    Configuration cf = parent.resolve(finder, ModuleFinder.of(), Set.of("myapp"));
  *    cf.modules().forEach(m -> {
  *        System.out.format("%s -> %s%n",
  *            m.name(),
@@ -172,6 +94,7 @@
  * }</pre>
  *
  * @since 9
+ * @spec JPMS
  * @see java.lang.reflect.Layer
  */
 public final class Configuration {
@@ -186,11 +109,23 @@
     private final Set<ResolvedModule> modules;
     private final Map<String, ResolvedModule> nameToModule;
 
+    // module constraints on target
+    private final String osName;
+    private final String osArch;
+    private final String osVersion;
+
+    String osName() { return osName; }
+    String osArch() { return osArch; }
+    String osVersion() { return osVersion; }
+
     private Configuration() {
         this.parents = Collections.emptyList();
         this.graph = Collections.emptyMap();
         this.modules = Collections.emptySet();
         this.nameToModule = Collections.emptyMap();
+        this.osName = null;
+        this.osArch = null;
+        this.osVersion = null;
     }
 
     private Configuration(List<Configuration> parents,
@@ -214,27 +149,30 @@
         this.graph = g;
         this.modules = Set.of(moduleArray);
         this.nameToModule = Map.ofEntries(nameEntries);
+
+        this.osName = resolver.osName();
+        this.osArch = resolver.osArch();
+        this.osVersion = resolver.osVersion();
     }
 
-
     /**
      * 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
-     * #resolveRequires(ModuleFinder,List,ModuleFinder,Collection) resolveRequires}
+     * #resolve(ModuleFinder,List,ModuleFinder,Collection) resolve}
      * method when invoked with this configuration as the parent. In other words,
      * if this configuration is {@code cf} then this method is equivalent to
      * invoking:
      * <pre> {@code
-     *     Configuration.resolveRequires(before, List.of(cf), after, roots);
+     *     Configuration.resolve(before, List.of(cf), after, roots);
      * }</pre>
      *
      * @param  before
      *         The <em>before</em> module finder to find modules
      * @param  after
-     *         The <em>after</em> module finder to locate modules when a
-     *         module cannot be located by the {@code before} module finder
-     *         and the module is not in this configuration
+     *         The <em>after</em> module finder to locate modules when not
+     *         located by the {@code before} module finder or in parent
+     *         configurations
      * @param  roots
      *         The possibly-empty collection of module names of the modules
      *         to resolve
@@ -242,16 +180,20 @@
      * @return The configuration that is the result of resolving the given
      *         root modules
      *
+     * @throws FindException
+     *         If resolution fails for any of the observability-related reasons
+     *         specified by the static {@code resolve} method
      * @throws ResolutionException
-     *         If resolution or the post-resolution checks fail
+     *         If any of the post-resolution consistency checks specified by
+     *         the  static {@code resolve} method fail
      * @throws SecurityException
      *         If locating a module is denied by the security manager
      */
-    public Configuration resolveRequires(ModuleFinder before,
-                                         ModuleFinder after,
-                                         Collection<String> roots)
+    public Configuration resolve(ModuleFinder before,
+                                 ModuleFinder after,
+                                 Collection<String> roots)
     {
-        return resolveRequires(before, List.of(this), after, roots);
+        return resolve(before, List.of(this), after, roots);
     }
 
 
@@ -259,12 +201,12 @@
      * Resolves a collection of root modules, with service binding, and with
      * this configuration as its parent, to create a new configuration.
      * This method works exactly as specified by the static {@link
-     * #resolveRequiresAndUses(ModuleFinder,List,ModuleFinder,Collection)
-     * resolveRequiresAndUses} method when invoked with this configuration
+     * #resolveAndBind(ModuleFinder,List,ModuleFinder,Collection)
+     * resolveAndBind} method when invoked with this configuration
      * as the parent. In other words, if this configuration is {@code cf} then
      * this method is equivalent to invoking:
      * <pre> {@code
-     *     Configuration.resolveRequiresAndUses(before, List.of(cf), after, roots);
+     *     Configuration.resolveAndBind(before, List.of(cf), after, roots);
      * }</pre>
      *
      *
@@ -272,25 +214,29 @@
      *         The <em>before</em> module finder to find modules
      * @param  after
      *         The <em>after</em> module finder to locate modules when not
-     *         located by the {@code before} module finder and this
-     *         configuration
+     *         located by the {@code before} module finder or in parent
+     *         configurations
      * @param  roots
      *         The possibly-empty collection of module names of the modules
      *         to resolve
      *
-     * @return The configuration that is the result of resolving the given
-     *         root modules
+     * @return The configuration that is the result of resolving, with service
+     *         binding, the given root modules
      *
+     * @throws FindException
+     *         If resolution fails for any of the observability-related reasons
+     *         specified by the static {@code resolve} method
      * @throws ResolutionException
-     *         If resolution or the post-resolution checks fail
+     *         If any of the post-resolution consistency checks specified by
+     *         the  static {@code resolve} method fail
      * @throws SecurityException
      *         If locating a module is denied by the security manager
      */
-    public Configuration resolveRequiresAndUses(ModuleFinder before,
-                                                ModuleFinder after,
-                                                Collection<String> roots)
+    public Configuration resolveAndBind(ModuleFinder before,
+                                        ModuleFinder after,
+                                        Collection<String> roots)
     {
-        return resolveRequiresAndUses(before, List.of(this), after, roots);
+        return resolveAndBind(before, List.of(this), after, roots);
     }
 
 
@@ -301,14 +247,14 @@
      *
      * This method is used to create the configuration for the boot layer.
      */
-    static Configuration resolveRequiresAndUses(ModuleFinder finder,
-                                                Collection<String> roots,
-                                                boolean check,
-                                                PrintStream traceOutput)
+    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.resolveRequires(roots).resolveUses();
+        resolver.resolve(roots).bind();
 
         return new Configuration(parents, resolver, check);
     }
@@ -328,11 +274,11 @@
      *
      * <p> When all modules have been resolved then the resulting dependency
      * graph is checked to ensure that it does not contain cycles. A
-     * readability graph is constructed and in conjunction with the module
+     * readability graph is constructed, and in conjunction with the module
      * exports and service use, checked for consistency. </p>
      *
-     * <p> Resolution and the (post-resolution) consistency checks may fail for
-     * following reasons: </p>
+     * <p> Resolution may fail with {@code FindException} for the following
+     * <em>observability-related</em> reasons: </p>
      *
      * <ul>
      *     <li><p> A root module, or a direct or transitive dependency, is not
@@ -343,6 +289,20 @@
      *     descriptor ({@code module-info.class}) or two versions of the same
      *     module are found in the same directory. </p></li>
      *
+     *     <li><p> A module with the required name is found but the module
+     *     requires a different {@link ModuleDescriptor#osName() operating
+     *     system}, {@link ModuleDescriptor#osArch() architecture}, or {@link
+     *     ModuleDescriptor#osVersion() version} to other modules that have
+     *     been resolved for the new configuration or modules in the parent
+     *     configurations. </p></li>
+     *
+     * </ul>
+     *
+     * <p> Post-resolution consistency checks may fail with {@code
+     * ResolutionException} for the following reasons: </p>
+     *
+     * <ul>
+     *
      *     <li><p> A cycle is detected, say where module {@code m1} requires
      *     module {@code m2} and {@code m2} requires {@code m1}. </p></li>
      *
@@ -356,20 +316,11 @@
      *     module {@code M} nor exported to {@code M} by any module that
      *     {@code M} reads. </p></li>
      *
-     *     <li><p> A module {@code M} declares that it
-     *     "{@code provides ... with q.T}" but package {@code q} is not in
-     *     module {@code M}. </p></li>
+     * </ul>
      *
-     *     <li><p> Two or more modules in the configuration are specific to
-     *     different {@link ModuleDescriptor#osName() operating systems},
-     *     {@link ModuleDescriptor#osArch() architectures}, or {@link
-     *     ModuleDescriptor#osVersion() versions}. </p></li>
-     *
-     *     <li><p> Other implementation specific checks, for example referential
-     *     integrity checks to ensure that different versions of tighly coupled
-     *     modules cannot be combined in the same configuration. </p></li>
-     *
-     * </ul>
+     * @implNote In the implementation then observability of modules may depend
+     * on referential integrity checks that ensure different builds of tightly
+     * coupled modules are not combined in the same configuration.
      *
      * @param  before
      *         The <em>before</em> module finder to find modules
@@ -386,17 +337,22 @@
      * @return The configuration that is the result of resolving the given
      *         root modules
      *
+     * @throws FindException
+     *         If resolution fails for an observability-related reason
      * @throws ResolutionException
-     *         If resolution or the post-resolution checks fail
+     *         If a post-resolution consistency checks fails
      * @throws IllegalArgumentException
-     *         If the list of parents is empty
+     *         If the list of parents is empty, or the list has two or more
+     *         parents with modules for different target operating systems,
+     *         architectures, or versions
+     *
      * @throws SecurityException
      *         If locating a module is denied by the security manager
      */
-    public static Configuration resolveRequires(ModuleFinder before,
-                                                List<Configuration> parents,
-                                                ModuleFinder after,
-                                                Collection<String> roots)
+    public static Configuration resolve(ModuleFinder before,
+                                        List<Configuration> parents,
+                                        ModuleFinder after,
+                                        Collection<String> roots)
     {
         Objects.requireNonNull(before);
         Objects.requireNonNull(after);
@@ -407,7 +363,7 @@
             throw new IllegalArgumentException("'parents' is empty");
 
         Resolver resolver = new Resolver(before, parentList, after, null);
-        resolver.resolveRequires(roots);
+        resolver.resolve(roots);
 
         return new Configuration(parentList, resolver, true);
     }
@@ -417,24 +373,24 @@
      * configuration.
      *
      * <p> This method works exactly as specified by {@link
-     * #resolveRequires(ModuleFinder,List,ModuleFinder,Collection)
-     * resolveRequires} except that the graph of resolved modules is augmented
+     * #resolve(ModuleFinder,List,ModuleFinder,Collection)
+     * resolve} except that the graph of resolved modules is augmented
      * with modules induced by the service-use dependence relation. </p>
      *
      * <p> More specifically, the root modules are resolved as if by calling
-     * {@code resolveRequires}. The resolved modules, and all modules in the
+     * {@code resolve}. The resolved modules, and all modules in the
      * parent configurations, with {@link ModuleDescriptor#uses() service
      * dependences} are then examined. All modules found by the given module
      * finders that {@link ModuleDescriptor#provides() provide} an
      * implementation of one or more of the service types are added to the
      * module graph and then resolved as if by calling the {@code
-     * resolveRequires} method. Adding modules to the module graph may
-     * introduce new service-use dependences and so the process works
-     * iteratively until no more modules are added. </p>
+     * resolve} method. Adding modules to the module graph may introduce new
+     * service-use dependences and so the process works iteratively until no
+     * more modules are added. </p>
      *
-     * <p> As service binding involves resolution then it may fail with {@link
-     * ResolutionException} for exactly the same reasons specified in
-     * {@code resolveRequires}.  </p>
+     * <p> As service binding involves resolution then it may fail with {@code
+     * FindException} or {@code ResolutionException} for exactly the same
+     * reasons specified in {@code resolve}. </p>
      *
      * @param  before
      *         The <em>before</em> module finder to find modules
@@ -448,20 +404,26 @@
      *         The possibly-empty collection of module names of the modules
      *         to resolve
      *
-     * @return The configuration that is the result of resolving the given
-     *         root modules
+     * @return The configuration that is the result of resolving, with service
+     *         binding, the given root modules
      *
+     * @throws FindException
+     *         If resolution fails for any of the observability-related reasons
+     *         specified by the static {@code resolve} method
      * @throws ResolutionException
-     *         If resolution or the post-resolution checks fail
+     *         If any of the post-resolution consistency checks specified by
+     *         the  static {@code resolve} method fail
      * @throws IllegalArgumentException
-     *         If the list of parents is empty
+     *         If the list of parents is empty, or the list has two or more
+     *         parents with modules for different target operating systems,
+     *         architectures, or versions
      * @throws SecurityException
      *         If locating a module is denied by the security manager
      */
-    public static Configuration resolveRequiresAndUses(ModuleFinder before,
-                                                       List<Configuration> parents,
-                                                       ModuleFinder after,
-                                                       Collection<String> roots)
+    public static Configuration resolveAndBind(ModuleFinder before,
+                                               List<Configuration> parents,
+                                               ModuleFinder after,
+                                               Collection<String> roots)
     {
         Objects.requireNonNull(before);
         Objects.requireNonNull(after);
@@ -472,7 +434,7 @@
             throw new IllegalArgumentException("'parents' is empty");
 
         Resolver resolver = new Resolver(before, parentList, after, null);
-        resolver.resolveRequires(roots).resolveUses();
+        resolver.resolve(roots).bind();
 
         return new Configuration(parentList, resolver, true);
     }
--- a/src/java.base/share/classes/java/lang/module/FindException.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/module/FindException.java	Fri Feb 10 09:04:39 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 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
@@ -26,10 +26,14 @@
 package java.lang.module;
 
 /**
- * Thrown by module finders when finding a module fails.
+ * Thrown by a {@link ModuleFinder ModuleFinder} when an error occurs finding
+ * a module. Also thrown by {@link
+ * Configuration#resolve(ModuleFinder,java.util.List,ModuleFinder,java.util.Collection)
+ * Configuration.resolve} when resolution fails for observability-related
+ * reasons.
  *
- * @see ModuleFinder
  * @since 9
+ * @spec JPMS
  */
 
 public class FindException extends RuntimeException {
--- a/src/java.base/share/classes/java/lang/module/InvalidModuleDescriptorException.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/module/InvalidModuleDescriptorException.java	Fri Feb 10 09:04:39 2017 +0000
@@ -31,6 +31,7 @@
  *
  * @see ModuleDescriptor#read
  * @since 9
+ * @spec JPMS
  */
 public class InvalidModuleDescriptorException extends RuntimeException {
     private static final long serialVersionUID = 4863390386809347380L;
--- a/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java	Fri Feb 10 09:04:39 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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,6 +32,7 @@
 import java.nio.ByteBuffer;
 import java.nio.file.Path;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.EnumSet;
@@ -56,18 +57,37 @@
 /**
  * A module descriptor.
  *
- * <p> A {@code ModuleDescriptor} is typically created from the binary form
- * of a module declaration. Alternatively, the {@link ModuleDescriptor.Builder}
- * class can be used to create a {@code ModuleDescriptor} from its components.
- * The {@link #module module}, {@link #openModule openModule}, and {@link
- * #automaticModule automaticModule} methods create builders for building
- * different kinds of modules. </p>
+ * <p> A module descriptor describes a named module and defines methods to
+ * obtain each of its components. The module descriptor for a named module
+ * in the Java virtual machine is obtained by invoking the {@link
+ * java.lang.reflect.Module Module}'s {@link java.lang.reflect.Module#getDescriptor
+ * getDescriptor} method. Module descriptors can also be created using the
+ * {@link ModuleDescriptor.Builder} class or by reading the binary form of a
+ * module declaration ({@code module-info.class}) using the {@link
+ * #read(InputStream,Supplier) read} methods defined here. </p>
+ *
+ * <p> A module descriptor describes a <em>normal</em>, open, or automatic
+ * module. <em>Normal</em> modules and open modules describe their {@link
+ * #requires() dependences}, {@link #exports() exported-packages}, the services
+ * that they {@link #uses() use} or {@link #provides() provide}, and other
+ * components. <em>Normal</em> modules may {@link #opens() open} specific
+ * packages. The module descriptor for an open modules does not declare any
+ * open packages (its {@code opens} method returns an empty set) but when
+ * instantiated in the Java virtual machine then it is treated as if all
+ * packages are open. The module descriptor for an automatic module does not
+ * declare any dependences (except for the mandatory dependency on {@code
+ * java.base}), and does not declare any exported or open packages. Automatic
+ * module receive special treatment during resolution so that they read all
+ * other modules in the configuration. When an automatic module is instantiated
+ * in the Java virtual machine then it reads every unnamed module and is
+ * treated as if all packages are exported and open. </p>
  *
  * <p> {@code ModuleDescriptor} objects are immutable and safe for use by
  * multiple concurrent threads.</p>
  *
+ * @see java.lang.reflect.Module
  * @since 9
- * @see java.lang.reflect.Module
+ * @spec JPMS
  */
 
 public class ModuleDescriptor
@@ -75,10 +95,45 @@
 {
 
     /**
+     * A modifier on a module.
+     *
+     * @see ModuleDescriptor#modifiers()
+     * @since 9
+     */
+    public static enum Modifier {
+        /**
+         * An open module. An open module does not declare any open packages
+         * but the resulting module is treated as if all packages are open.
+         */
+        OPEN,
+
+        /**
+         * An automatic module. An automatic module is treated as if it exports
+         * and opens all packages.
+         *
+         * @apiNote This modifier does not correspond to a module flag in the
+         * binary form of a module declaration ({@code module-info.class}).
+         */
+        AUTOMATIC,
+
+        /**
+         * The module was not explicitly or implicitly declared.
+         */
+        SYNTHETIC,
+
+        /**
+         * The module was implicitly declared.
+         */
+        MANDATED;
+    }
+
+
+    /**
      * <p> A dependence upon a module </p>
      *
      * @see ModuleDescriptor#requires()
      * @since 9
+     * @spec JPMS
      */
 
     public final static class Requires
@@ -88,7 +143,9 @@
         /**
          * A modifier on a module dependence.
          *
+         * @see Requires#modifiers()
          * @since 9
+         * @spec JPMS
          */
         public static enum Modifier {
 
@@ -171,14 +228,18 @@
          * Compares this module dependence to another.
          *
          * <p> Two {@code Requires} objects are compared by comparing their
-         * module name lexicographically.  Where the module names are equal then
-         * the sets of modifiers are compared based on a value computed from the
-         * ordinal of each modifier. Where the module names are equal and the
-         * set of modifiers are equal then the version of the modules recorded
-         * at compile-time are compared. When comparing the versions recorded
-         * at compile-time then a dependence that has a recorded version is
-         * considered to succeed a dependence that does not have a recorded
-         * version. </p>
+         * module names lexicographically. Where the module names are equal
+         * then the sets of modifiers are compared in the same way that
+         * module modifiers are compared (see {@link ModuleDescriptor#compareTo
+         * ModuleDescriptor.compareTo}). Where the module names are equal and
+         * the set of modifiers are equal then the version of the modules
+         * recorded at compile-time are compared. When comparing the versions
+         * recorded at compile-time then a dependence that has a recorded
+         * version is considered to succeed a dependence that does not have a
+         * recorded version. </p>
+         *
+         * @param  that
+         *         The module dependence to compare
          *
          * @return A negative integer, zero, or a positive integer if this module
          *         dependence is less than, equal to, or greater than the given
@@ -186,39 +247,22 @@
          */
         @Override
         public int compareTo(Requires that) {
+            if (this == that) return 0;
+
             int c = this.name().compareTo(that.name());
-            if (c != 0)
-                return c;
+            if (c != 0) return c;
 
             // modifiers
-            c = Long.compare(this.modsValue(), that.modsValue());
-            if (c != 0)
-                return c;
+            long v1 = modsValue(this.modifiers());
+            long v2 = modsValue(that.modifiers());
+            c = Long.compare(v1, v2);
+            if (c != 0) return c;
 
             // compiledVersion
-            if (this.compiledVersion != null) {
-                if (that.compiledVersion != null)
-                    c = this.compiledVersion.compareTo(that.compiledVersion);
-                else
-                    c = 1;
-            } else {
-                if (that.compiledVersion != null)
-                    c = -1;
-            }
+            c = compare(this.compiledVersion, that.compiledVersion);
+            if (c != 0) return c;
 
-            return c;
-        }
-
-        /**
-         * Return a value for the modifiers to allow sets of modifiers to be
-         * compared.
-         */
-        private long modsValue() {
-            long value = 0;
-            for (Modifier m : mods) {
-                value += 1 << m.ordinal();
-            }
-            return value;
+            return 0;
         }
 
         /**
@@ -266,9 +310,9 @@
         }
 
         /**
-         * Returns a string describing module dependence.
+         * Returns a string describing this module dependence.
          *
-         * @return A string describing module dependence
+         * @return A string describing this module dependence
          */
         @Override
         public String toString() {
@@ -285,18 +329,23 @@
 
 
     /**
-     * <p> A module export, may be qualified or unqualified. </p>
+     * <p> A package exported by a module, may be qualified or unqualified. </p>
      *
      * @see ModuleDescriptor#exports()
      * @since 9
+     * @spec JPMS
      */
 
-    public final static class Exports {
+    public final static class Exports
+        implements Comparable<Exports>
+    {
 
         /**
-         * A modifier on a module export.
+         * A modifier on an exported package.
          *
+         * @see Exports#modifiers()
          * @since 9
+         * @spec JPMS
          */
         public static enum Modifier {
 
@@ -381,6 +430,52 @@
         }
 
         /**
+         * Compares this module export to another.
+         *
+         * <p> Two {@code Exports} objects are compared by comparing the package
+         * names lexicographically. Where the packages names are equal then the
+         * sets of modifiers are compared in the same way that module modifiers
+         * are compared (see {@link ModuleDescriptor#compareTo
+         * ModuleDescriptor.compareTo}). Where the package names are equal and
+         * the set of modifiers are equal then the set of target modules are
+         * compared. This is done by sorting the names of the target modules
+         * in ascending order, and according to their natural ordering, and then
+         * comparing the corresponding elements lexicographically. Where the
+         * sets differ in size, and the larger set contains all elements of the
+         * smaller set, then the larger set is considered to succeed the smaller
+         * set. </p>
+         *
+         * @param  that
+         *         The module export to compare
+         *
+         * @return A negative integer, zero, or a positive integer if this module
+         *         export is less than, equal to, or greater than the given
+         *         export dependence
+         */
+        @Override
+        public int compareTo(Exports that) {
+            if (this == that) return 0;
+
+            int c = source.compareTo(that.source);
+            if (c != 0)
+                return c;
+
+            // modifiers
+            long v1 = modsValue(this.modifiers());
+            long v2 = modsValue(that.modifiers());
+            c = Long.compare(v1, v2);
+            if (c != 0)
+                return c;
+
+            // targets
+            c = compare(targets, that.targets);
+            if (c != 0)
+                return c;
+
+            return 0;
+        }
+
+        /**
          * Computes a hash code for this module export.
          *
          * <p> The hash code is based upon the modifiers, the package name,
@@ -425,9 +520,9 @@
         }
 
         /**
-         * Returns a string describing module export.
+         * Returns a string describing the exported package.
          *
-         * @return A string describing module export
+         * @return A string describing the exported package
          */
         @Override
         public String toString() {
@@ -441,8 +536,7 @@
 
 
     /**
-     * <p> Represents a module <em>opens</em> directive, may be qualified or
-     * unqualified. </p>
+     * <p> A package opened by a module, may be qualified or unqualified. </p>
      *
      * <p> The <em>opens</em> directive in a module declaration declares a
      * package to be open to allow all types in the package, and all their
@@ -452,26 +546,30 @@
      *
      * @see ModuleDescriptor#opens()
      * @since 9
+     * @spec JPMS
      */
 
-    public final static class Opens {
-
+    public final static class Opens
+        implements Comparable<Opens>
+    {
         /**
-         * A modifier on a module <em>opens</em> directive.
+         * A modifier on an open package.
          *
+         * @see Opens#modifiers()
          * @since 9
+         * @spec JPMS
          */
         public static enum Modifier {
 
             /**
-             * The opens was not explicitly or implicitly declared in the
-             * source of the module declaration.
+             * The open package was not explicitly or implicitly declared in
+             * the source of the module declaration.
              */
             SYNTHETIC,
 
             /**
-             * The opens was implicitly declared in the source of the module
-             * declaration.
+             * The open package was implicitly declared in the source of the
+             * module declaration.
              */
             MANDATED;
 
@@ -544,6 +642,52 @@
         }
 
         /**
+         * Compares this module opens to another.
+         *
+         * <p> Two {@code Opens} objects are compared by comparing the package
+         * names lexicographically. Where the packages names are equal then the
+         * sets of modifiers are compared in the same way that module modifiers
+         * are compared (see {@link ModuleDescriptor#compareTo
+         * ModuleDescriptor.compareTo}). Where the package names are equal and
+         * the set of modifiers are equal then the set of target modules are
+         * compared. This is done by sorting the names of the target modules
+         * in ascending order, and according to their natural ordering, and then
+         * comparing the corresponding elements lexicographically. Where the
+         * sets differ in size, and the larger set contains all elements of the
+         * smaller set, then the larger set is considered to succeed the smaller
+         * set. </p>
+         *
+         * @param  that
+         *         The module opens to compare
+         *
+         * @return A negative integer, zero, or a positive integer if this module
+         *         opens is less than, equal to, or greater than the given
+         *         module opens
+         */
+        @Override
+        public int compareTo(Opens that) {
+            if (this == that) return 0;
+
+            int c = source.compareTo(that.source);
+            if (c != 0)
+                return c;
+
+            // modifiers
+            long v1 = modsValue(this.modifiers());
+            long v2 = modsValue(that.modifiers());
+            c = Long.compare(v1, v2);
+            if (c != 0)
+                return c;
+
+            // targets
+            c = compare(targets, that.targets);
+            if (c != 0)
+                return c;
+
+            return 0;
+        }
+
+        /**
          * Computes a hash code for this module opens.
          *
          * <p> The hash code is based upon the modifiers, the package name,
@@ -588,9 +732,9 @@
         }
 
         /**
-         * Returns a string describing module opens.
+         * Returns a string describing the open package.
          *
-         * @return A string describing module opens
+         * @return A string describing the open package
          */
         @Override
         public String toString() {
@@ -608,10 +752,12 @@
      *
      * @see ModuleDescriptor#provides()
      * @since 9
+     * @spec JPMS
      */
 
-    public final static class Provides {
-
+    public final static class Provides
+        implements Comparable<Provides>
+    {
         private final String service;
         private final List<String> providers;
 
@@ -642,6 +788,46 @@
         public List<String> providers() { return providers; }
 
         /**
+         * Compares this provides to another.
+         *
+         * <p> Two {@code Provides} objects are compared by comparing the fully
+         * qualified class name of the service type lexicographically. Where the
+         * class names are equal then the list of the provider class names are
+         * compared by comparing the corresponding elements of both lists
+         * lexicographically and in sequence. Where the lists differ in size,
+         * {@code N} is the size of the shorter list, and the first {@code N}
+         * corresponding elements are equal, then the longer list is considered
+         * to succeed the shorter list. </p>
+         *
+         * @param  that
+         *         The {@code Provides} to compare
+         *
+         * @return A negative integer, zero, or a positive integer if this provides
+         *         is less than, equal to, or greater than the given provides
+         */
+        public int compareTo(Provides that) {
+            if (this == that) return 0;
+
+            int c = service.compareTo(that.service);
+            if (c != 0) return c;
+
+            // compare provider class names in sequence
+            int size1 = this.providers.size();
+            int size2 = that.providers.size();
+            for (int index=0; index<Math.min(size1, size2); index++) {
+                String e1 = this.providers.get(index);
+                String e2 = that.providers.get(index);
+                c = e1.compareTo(e2);
+                if (c != 0) return c;
+            }
+            if (size1 == size2) {
+                return 0;
+            } else {
+                return (size1 > size2) ? 1 : -1;
+            }
+        }
+
+        /**
          * Computes a hash code for this provides.
          *
          * <p> The hash code is based upon the service type and the set of
@@ -699,7 +885,7 @@
      *
      * <p> A version string has three components: The version number itself, an
      * optional pre-release version, and an optional build version.  Each
-     * component is sequence of tokens; each token is either a non-negative
+     * component is a sequence of tokens; each token is either a non-negative
      * integer or a string.  Tokens are separated by the punctuation characters
      * {@code '.'}, {@code '-'}, or {@code '+'}, or by transitions from a
      * sequence of digits to a sequence of characters that are neither digits
@@ -740,6 +926,7 @@
      *
      * @see ModuleDescriptor#version()
      * @since 9
+     * @spec JPMS
      */
 
     public final static class Version
@@ -1009,36 +1196,26 @@
 
     }
 
-
+
     private final String name;
     private final Version version;
-    private final boolean open;
-
-    // Indicates if synthesised for a JAR file found on the module path
-    private final boolean automatic;
-
-    // Not generated from a module-info.java
-    private final boolean synthetic;
-
+    private final Set<Modifier> modifiers;
+    private final boolean open;  // true if modifiers contains OPEN
+    private final boolean automatic;  // true if modifiers contains AUTOMATIC
     private final Set<Requires> requires;
     private final Set<Exports> exports;
     private final Set<Opens> opens;
     private final Set<String> uses;
     private final Set<Provides> provides;
-
-    // Added post-compilation by tools
     private final Set<String> packages;
     private final String mainClass;
     private final String osName;
     private final String osArch;
     private final String osVersion;
 
-
     private ModuleDescriptor(String name,
                              Version version,
-                             boolean open,
-                             boolean automatic,
-                             boolean synthetic,
+                             Set<Modifier> modifiers,
                              Set<Requires> requires,
                              Set<Exports> exports,
                              Set<Opens> opens,
@@ -1052,10 +1229,9 @@
     {
         this.name = name;
         this.version = version;
-        this.open = open;
-        this.automatic = automatic;
-        this.synthetic = synthetic;
-
+        this.modifiers = emptyOrUnmodifiableSet(modifiers);
+        this.open = modifiers.contains(Modifier.OPEN);
+        this.automatic = modifiers.contains(Modifier.AUTOMATIC);
         assert (requires.stream().map(Requires::name).distinct().count()
                 == requires.size());
         this.requires = emptyOrUnmodifiableSet(requires);
@@ -1072,40 +1248,12 @@
     }
 
     /**
-     * Clones the given module descriptor with an augmented set of packages
-     */
-    ModuleDescriptor(ModuleDescriptor md, Set<String> pkgs) {
-        this.name = md.name;
-        this.version = md.version;
-        this.open = md.open;
-        this.automatic = md.automatic;
-        this.synthetic = md.synthetic;
-
-        this.requires = md.requires;
-        this.exports = md.exports;
-        this.opens = md.opens;
-        this.uses = md.uses;
-        this.provides = md.provides;
-
-        Set<String> packages = new HashSet<>(md.packages);
-        packages.addAll(pkgs);
-        this.packages = emptyOrUnmodifiableSet(packages);
-
-        this.mainClass = md.mainClass;
-        this.osName = md.osName;
-        this.osArch = md.osArch;
-        this.osVersion = md.osVersion;
-    }
-
-    /**
      * Creates a module descriptor from its components.
      * The arguments are pre-validated and sets are unmodifiable sets.
      */
     ModuleDescriptor(String name,
                      Version version,
-                     boolean open,
-                     boolean automatic,
-                     boolean synthetic,
+                     Set<Modifier> modifiers,
                      Set<Requires> requires,
                      Set<Exports> exports,
                      Set<Opens> opens,
@@ -1120,9 +1268,9 @@
                      boolean unused) {
         this.name = name;
         this.version = version;
-        this.open = open;
-        this.automatic = automatic;
-        this.synthetic = synthetic;
+        this.modifiers = modifiers;
+        this.open = modifiers.contains(Modifier.OPEN);
+        this.automatic = modifiers.contains(Modifier.AUTOMATIC);
         this.requires = requires;
         this.exports = exports;
         this.opens = opens;
@@ -1137,7 +1285,7 @@
     }
 
     /**
-     * <p> The module name. </p>
+     * <p> Returns the module name. </p>
      *
      * @return The module name
      */
@@ -1146,11 +1294,19 @@
     }
 
     /**
+     * <p> Returns the set of module modifiers. </p>
+     *
+     * @return A possibly-empty unmodifiable set of modifiers
+     */
+    public Set<Modifier> modifiers() {
+        return modifiers;
+    }
+
+    /**
      * <p> Returns {@code true} if this is an open module. </p>
      *
-     * <p> An open module does not declare any open packages (the {@link #opens()
-     * opens} method returns an empty set) but the resulting module is treated
-     * as if all packages are open. </p>
+     * <p> This method is equivalent to testing if the set of {@link #modifiers
+     * modifiers} contains the {@link Modifier#OPEN OPEN} modifier. </p>
      *
      * @return  {@code true} if this is an open module
      */
@@ -1161,12 +1317,8 @@
     /**
      * <p> Returns {@code true} if this is an automatic module. </p>
      *
-     * <p> An automatic module is defined implicitly rather than explicitly
-     * and therefore does not have a module declaration. JAR files located on
-     * the application module path, or by the {@link ModuleFinder} returned by
-     * {@link ModuleFinder#of(java.nio.file.Path[]) ModuleFinder.of}, are
-     * treated as automatic modules if they do have not have a module
-     * declaration. </p>
+     * <p> This method is equivalent to testing if the set of {@link #modifiers
+     * modifiers} contains the {@link Modifier#OPEN AUTOMATIC} modifier. </p>
      *
      * @return  {@code true} if this is an automatic module
      */
@@ -1175,20 +1327,13 @@
     }
 
     /**
-     * <p> Returns {@code true} if this module descriptor was not generated
-     * from an explicit module declaration ({@code module-info.java})
-     * or an implicit module declaration (an {@link #isAutomatic() automatic}
-     * module). </p>
+     * <p> Returns the set of {@code Requires} objects representing the module
+     * dependences. </p>
      *
-     * @return  {@code true} if this module descriptor was not generated by
-     *          an explicit or implicit module declaration
-     */
-    public boolean isSynthetic() {
-        return synthetic;
-    }
-
-    /**
-     * <p> The dependences of this module. </p>
+     * <p> The set includes a dependency on "{@code java.base}" when this
+     * module is not named "{@code java.base}". If this module is an automatic
+     * module then it does not have a dependency on any module other than
+     * "{@code java.base}". </p>
      *
      * @return  A possibly-empty unmodifiable set of {@link Requires} objects
      */
@@ -1197,7 +1342,11 @@
     }
 
     /**
-     * <p> The module exports. </p>
+     * <p> Returns the set of {@code Exports} objects representing the exported
+     * packages. </p>
+     *
+     * <p> If this module is an automatic module then the set of exports
+     * is empty. </p>
      *
      * @return  A possibly-empty unmodifiable set of exported packages
      */
@@ -1206,16 +1355,11 @@
     }
 
     /**
-     * <p> The module <em>opens</em> directives. </p>
+     * <p> Returns the set of {@code Opens} objects representing the open
+     * packages. </p>
      *
-     * <p> Each {@code Opens} object in the set represents a package (and
-     * the set of target module names when qualified) where all types in the
-     * package, and all their members, not just public types and their public
-     * members, can be reflected on when using APIs that bypass or suppress
-     * default Java language access control checks. </p>
-     *
-     * <p> This method returns an empty set when invoked on {@link #isOpen()
-     * open} module. </p>
+     * <p> If this module is an open module or an automatic module then the
+     * set of open packages is empty. </p>
      *
      * @return  A possibly-empty unmodifiable set of open packages
      */
@@ -1224,7 +1368,10 @@
     }
 
     /**
-     * <p> The service dependences of this module. </p>
+     * <p> Returns the set of service dependences. </p>
+     *
+     * <p> If this module is an automatic module then the set of service
+     * dependences is empty. </p>
      *
      * @return  A possibly-empty unmodifiable set of the fully qualified class
      *          names of the service types used
@@ -1234,7 +1381,8 @@
     }
 
     /**
-     * <p> The services that this module provides. </p>
+     * <p> Returns the set of {@code Provides} objects representing the
+     * services that the module provides. </p>
      *
      * @return The possibly-empty unmodifiable set of the services that this
      *         module provides
@@ -1244,7 +1392,7 @@
     }
 
     /**
-     * Returns this module's version.
+     * <p> Returns the module version. </p>
      *
      * @return This module's version
      */
@@ -1253,10 +1401,10 @@
     }
 
     /**
-     * Returns a string containing this module's name and, if present, its
-     * version.
+     * <p> Returns a string containing the module name and, if present, its
+     * version. </p>
      *
-     * @return A string containing this module's name and, if present, its
+     * @return A string containing the module name and, if present, its
      *         version.
      */
     public String toNameAndVersion() {
@@ -1268,51 +1416,51 @@
     }
 
     /**
-     * Returns the module's main class.
+     * <p> Returns the module main class. </p>
      *
-     * @return The fully qualified class name of this module's main class
+     * @return The fully qualified class name of the module's main class
      */
     public Optional<String> mainClass() {
         return Optional.ofNullable(mainClass);
     }
 
     /**
-     * Returns the operating system name if this module is operating system
+     * Returns the operating system name if the module is operating system
      * specific.
      *
      * @return The operating system name or an empty {@code Optional}
-     *         if this module is not operating system specific
+     *         if the module is not operating system specific
      */
     public Optional<String> osName() {
         return Optional.ofNullable(osName);
     }
 
     /**
-     * Returns the operating system architecture if this module is operating
+     * Returns the operating system architecture if the module is operating
      * system architecture specific.
      *
      * @return The operating system architecture or an empty {@code Optional}
-     *         if this module is not operating system architecture specific
+     *         if the module is not operating system architecture specific
      */
     public Optional<String> osArch() {
         return Optional.ofNullable(osArch);
     }
 
     /**
-     * Returns the operating system version if this module is operating
+     * Returns the operating system version if the module is operating
      * system version specific.
      *
      * @return The operating system version or an empty {@code Optional}
-     *         if this module is not operating system version specific
+     *         if the module is not operating system version specific
      */
     public Optional<String> osVersion() {
         return Optional.ofNullable(osVersion);
     }
 
     /**
-     * Returns the names of all packages in this module.
+     * Returns the set of packages in the module.
      *
-     * @return A possibly-empty unmodifiable set of all packages in the module
+     * @return A possibly-empty unmodifiable set of the packages in the module
      */
     public Set<String> packages() {
         return packages;
@@ -1320,37 +1468,53 @@
 
 
     /**
-     * A builder used for building {@link ModuleDescriptor} objects.
+     * A builder for building {@link ModuleDescriptor} objects.
      *
-     * <p> {@code ModuleDescriptor} defines the {@link #module module}, {@link
-     * #openModule openModule}, and {@link #automaticModule automaticModule}
-     * methods to create builders for building different kinds of modules. </p>
+     * <p> {@code ModuleDescriptor} defines the {@link #newModule newModule},
+     * {@link #newOpenModule newOpenModule}, and {@link #newAutomaticModule
+     * newAutomaticModule} methods to create builders for building
+     * <em>normal</em>, open, and automatic modules. </p>
+     *
+     * <p> The set of packages in the module are accumulated by the {@code
+     * Builder} as the {@link ModuleDescriptor.Builder#exports(String) exports},
+     * {@link ModuleDescriptor.Builder#opens(String) opens},
+     * {@link ModuleDescriptor.Builder#packages(Set) packages},
+     * {@link ModuleDescriptor.Builder#provides(String,List) provides}, and
+     * {@link ModuleDescriptor.Builder#mainClass(String) mainClass} methods are
+     * invoked. </p>
+     *
+     * <p> The module names, package names, and class names that are parameters
+     * specified to the builder methods are the module names, package names,
+     * and qualified names of classes (in named packages) as defined in the
+     * <cite>The Java&trade; Language Specification</cite>. </p>
      *
      * <p> Example usage: </p>
-     * <pre>{@code    ModuleDescriptor descriptor = ModuleDescriptor.module("m1")
-     *         .exports("p")
-     *         .requires("m2")
+     * <pre>{@code    ModuleDescriptor descriptor = ModuleDescriptor.newModule("stats.core")
+     *         .requires("java.base")
+     *         .exports("org.acme.stats.core.clustering")
+     *         .exports("org.acme.stats.core.regression")
+     *         .packages(Set.of("org.acme.stats.core.internal"))
      *         .build();
      * }</pre>
      *
      * @apiNote A {@code Builder} checks the components and invariants as
-     * components are added to the builder. The rational for this is to detect
+     * components are added to the builder. The rationale for this is to detect
      * errors as early as possible and not defer all validation to the
-     * {@link #build build} method. A {@code Builder} cannot be used to create
-     * a {@link ModuleDescriptor#isSynthetic() synthetic} module.
+     * {@link #build build} method.
      *
      * @since 9
+     * @spec JPMS
      */
     public static final class Builder {
         final String name;
-        final boolean strict; // true if module names are checked
+        final boolean strict;
+        final Set<Modifier> modifiers;
         final boolean open;
-        final boolean synthetic;
-        boolean automatic;
+        final boolean automatic;
+        final Set<String> packages = new HashSet<>();
         final Map<String, Requires> requires = new HashMap<>();
         final Map<String, Exports> exports = new HashMap<>();
         final Map<String, Opens> opens = new HashMap<>();
-        final Set<String> concealedPackages = new HashSet<>();
         final Set<String> uses = new HashSet<>();
         final Map<String, Provides> provides = new HashMap<>();
         Version version;
@@ -1362,35 +1526,25 @@
         /**
          * Initializes a new builder with the given module name.
          *
-         * @param strict
-         *        Indicates whether module names are checked or not
+         * If {@code strict} is {@code true} then module, package, and class
+         * names are checked to ensure they are legal names. In addition, the
+         * {@link #build buid} method will add "{@code requires java.base}" if
+         * the dependency is not declared.
          */
-        Builder(String name, boolean strict, boolean open, boolean synthetic) {
+        Builder(String name, boolean strict, Set<Modifier> modifiers) {
             this.name = (strict) ? requireModuleName(name) : name;
             this.strict = strict;
-            this.open = open;
-            this.synthetic = synthetic;
-        }
-
-        /* package */ Builder automatic(boolean automatic) {
-            this.automatic = automatic;
-            return this;
+            this.modifiers = modifiers;
+            this.open = modifiers.contains(Modifier.OPEN);
+            this.automatic = modifiers.contains(Modifier.AUTOMATIC);
+            assert !open || !automatic;
         }
 
         /**
-         * Returns the set of packages that are exported (unconditionally or
-         * unconditionally).
+         * Returns a snapshot of the packages in the module.
          */
-        /* package */ Set<String> exportedPackages() {
-            return exports.keySet();
-        }
-
-        /**
-         * Returns the set of packages that are opened (unconditionally or
-         * unconditionally).
-         */
-        /* package */Set<String> openPackages() {
-            return opens.keySet();
+        /* package */ Set<String> packages() {
+            return Collections.unmodifiableSet(packages);
         }
 
         /**
@@ -1406,8 +1560,12 @@
          *         initialized to build
          * @throws IllegalStateException
          *         If the dependence on the module has already been declared
+         *         or this builder is for an automatic module
          */
         public Builder requires(Requires req) {
+            if (automatic)
+                throw new IllegalStateException("Automatic modules cannot declare"
+                                                + " dependences");
             String mn = req.name();
             if (name.equals(mn))
                 throw new IllegalArgumentException("Dependence on self");
@@ -1433,11 +1591,12 @@
          * @return This builder
          *
          * @throws IllegalArgumentException
-         *         If the module name is {@code null}, is not a legal Java
-         *         identifier, or is equal to the module name that this builder
+         *         If the module name is {@code null}, is not a legal module
+         *         name, or is equal to the module name that this builder
          *         was initialized to build
          * @throws IllegalStateException
          *         If the dependence on the module has already been declared
+         *         or this builder is for an automatic module
          */
         public Builder requires(Set<Requires.Modifier> ms,
                                 String mn,
@@ -1448,6 +1607,23 @@
             return requires(new Requires(ms, mn, compiledVersion));
         }
 
+        /* package */Builder requires(Set<Requires.Modifier> ms,
+                                      String mn,
+                                      String compiledVersion) {
+            Version v = null;
+            try {
+                v = Version.parse(compiledVersion);
+            } catch (IllegalArgumentException e) {
+                // for now, drop un-parsable version when non-strict
+                if (strict) throw e;
+            }
+            if (v == null) {
+                return requires(ms, mn);
+            } else {
+                return requires(ms, mn, v);
+            }
+        }
+
         /**
          * Adds a dependence on a module with the given (and possibly empty)
          * set of modifiers.
@@ -1460,11 +1636,12 @@
          * @return This builder
          *
          * @throws IllegalArgumentException
-         *         If the module name is {@code null}, is not a legal Java
-         *         identifier, or is equal to the module name that this builder
+         *         If the module name is {@code null}, is not a legal module
+         *         name, or is equal to the module name that this builder
          *         was initialized to build
          * @throws IllegalStateException
          *         If the dependence on the module has already been declared
+         *         or this builder is for an automatic module
          */
         public Builder requires(Set<Requires.Modifier> ms, String mn) {
             if (strict)
@@ -1481,18 +1658,19 @@
          * @return This builder
          *
          * @throws IllegalArgumentException
-         *         If the module name is {@code null}, is not a legal Java
-         *         identifier, or is equal to the module name that this builder
+         *         If the module name is {@code null}, is not a legal module
+         *         name, or is equal to the module name that this builder
          *         was initialized to build
          * @throws IllegalStateException
          *         If the dependence on the module has already been declared
+         *         or this builder is for an automatic module
          */
         public Builder requires(String mn) {
             return requires(EnumSet.noneOf(Requires.Modifier.class), mn);
         }
 
         /**
-         * Adds an export.
+         * Adds an exported package.
          *
          * @param  e
          *         The export
@@ -1500,29 +1678,27 @@
          * @return This builder
          *
          * @throws IllegalStateException
-         *         If the package is already declared as a package with the
-         *         {@link #contains contains} method or the package is already
-         *         declared as exported
+         *         If the {@link Exports#source package} is already declared as
+         *         exported or this builder is for an automatic module
          */
         public Builder exports(Exports e) {
-            // can't be exported and concealed
+            if (automatic) {
+                throw new IllegalStateException("Automatic modules cannot declare"
+                                                 + " exported packages");
+            }
             String source = e.source();
-            if (concealedPackages.contains(source)) {
-                throw new IllegalStateException("Package " + source
-                                                 + " already declared");
-            }
             if (exports.containsKey(source)) {
                 throw new IllegalStateException("Exported package " + source
                                                  + " already declared");
             }
-
             exports.put(source, e);
+            packages.add(source);
             return this;
         }
 
         /**
-         * Adds an export, with the given (and possibly empty) set of modifiers,
-         * to export a package to a set of target modules.
+         * Adds an exported package with the given (and possibly empty) set of
+         * modifiers. The package is exported to a set of target modules.
          *
          * @param  ms
          *         The set of modifiers
@@ -1534,33 +1710,34 @@
          * @return This builder
          *
          * @throws IllegalArgumentException
-         *         If the package name or any of the target modules is {@code
-         *         null} or is not a legal Java identifier, or the set of
-         *         targets is empty
+         *         If the package name is {@code null} or is not a legal
+         *         package name, the set of target modules is empty, or the set
+         *         of target modules contains a name that is not a legal module
+         *         name
          * @throws IllegalStateException
-         *         If the package is already declared as a package with the
-         *         {@link #contains contains} method or the package is already
-         *         declared as exported
+         *         If the package is already declared as exported
+         *         or this builder is for an automatic module
          */
         public Builder exports(Set<Exports.Modifier> ms,
                                String pn,
                                Set<String> targets)
         {
-            Exports e = new Exports(ms, requirePackageName(pn), targets);
+            Exports e = new Exports(ms, pn, targets);
 
             // check targets
             targets = e.targets();
             if (targets.isEmpty())
                 throw new IllegalArgumentException("Empty target set");
-            if (strict)
+            if (strict) {
+                requirePackageName(e.source());
                 targets.stream().forEach(Checks::requireModuleName);
-
+            }
             return exports(e);
         }
 
         /**
-         * Adds an unqualified export with the given (and possibly empty) set
-         * of modifiers.
+         * Adds an exported package with the given (and possibly empty) set of
+         * modifiers. The package is exported to all modules.
          *
          * @param  ms
          *         The set of modifiers
@@ -1570,20 +1747,23 @@
          * @return This builder
          *
          * @throws IllegalArgumentException
-         *         If the package name is {@code null} or is not a legal Java
-         *         identifier
+         *         If the package name is {@code null} or is not a legal
+         *         package name
          * @throws IllegalStateException
-         *         If the package is already declared as a package with the
-         *         {@link #contains contains} method or the package is already
-         *         declared as exported
+         *         If the package is already declared as exported
+         *         or this builder is for an automatic module
          */
         public Builder exports(Set<Exports.Modifier> ms, String pn) {
-            Exports e = new Exports(ms, requirePackageName(pn), Collections.emptySet());
+            if (strict) {
+                requirePackageName(pn);
+            }
+            Exports e = new Exports(ms, pn, Collections.emptySet());
             return exports(e);
         }
 
         /**
-         * Adds an export to export a package to a set of target modules.
+         * Adds an exported package. The package is exported to a set of target
+         * modules.
          *
          * @param  pn
          *         The package name
@@ -1593,20 +1773,20 @@
          * @return This builder
          *
          * @throws IllegalArgumentException
-         *         If the package name or any of the target modules is {@code
-         *         null} or is not a legal Java identifier, or the set of
-         *         targets is empty
+         *         If the package name is {@code null} or is not a legal
+         *         package name, the set of target modules is empty, or the set
+         *         of target modules contains a name that is not a legal module
+         *         name
          * @throws IllegalStateException
-         *         If the package is already declared as a package with the
-         *         {@link #contains contains} method or the package is already
-         *         declared as exported
+         *         If the package is already declared as exported
+         *         or this builder is for an automatic module
          */
         public Builder exports(String pn, Set<String> targets) {
             return exports(Collections.emptySet(), pn, targets);
         }
 
         /**
-         * Adds an unqualified export.
+         * Adds an exported package. The package is exported to all modules.
          *
          * @param  pn
          *         The package name
@@ -1614,19 +1794,18 @@
          * @return This builder
          *
          * @throws IllegalArgumentException
-         *         If the package name is {@code null} or is not a legal Java
-         *         identifier
+         *         If the package name is {@code null} or is not a legal
+         *         package name
          * @throws IllegalStateException
-         *         If the package is already declared as a package with the
-         *         {@link #contains contains} method or the package is already
-         *         declared as exported
+         *         If the package is already declared as exported
+         *         or this builder is for an automatic module
          */
         public Builder exports(String pn) {
             return exports(Collections.emptySet(), pn);
         }
 
         /**
-         * Adds an <em>opens</em> directive.
+         * Adds an open package.
          *
          * @param  obj
          *         The {@code Opens} object
@@ -1634,35 +1813,28 @@
          * @return This builder
          *
          * @throws IllegalStateException
-         *         If the package is already declared as a package with the
-         *         {@link #contains contains} method, the package is already
-         *         declared as open, or this is a builder for an open module
+         *         If the package is already declared as open, or this is a
+         *         builder for an open module or automatic module
          */
         public Builder opens(Opens obj) {
-            if (open) {
-                throw new IllegalStateException("open modules cannot declare"
-                                                + " open packages");
+            if (open || automatic) {
+                throw new IllegalStateException("Open or automatic modules cannot"
+                                                + " declare open packages");
             }
-
-            // can't be open and concealed
             String source = obj.source();
-            if (concealedPackages.contains(source)) {
-                throw new IllegalStateException("Package " + source
-                                                + " already declared");
-            }
             if (opens.containsKey(source)) {
                 throw new IllegalStateException("Open package " + source
                                                 + " already declared");
             }
-
             opens.put(source, obj);
+            packages.add(source);
             return this;
         }
 
 
         /**
-         * Adds an <em>opens</em> directive, with the given (and possibly empty)
-         * set of modifiers, to open a package to a set of target modules.
+         * Adds an open package with the given (and possibly empty) set of
+         * modifiers. The package is open to a set of target modules.
          *
          * @param  ms
          *         The set of modifiers
@@ -1674,33 +1846,34 @@
          * @return This builder
          *
          * @throws IllegalArgumentException
-         *         If the package name or any of the target modules is {@code
-         *         null} or is not a legal Java identifier, or the set of
-         *         targets is empty
+         *         If the package name is {@code null} or is not a legal
+         *         package name, the set of target modules is empty, or the set
+         *         of target modules contains a name that is not a legal module
+         *         name
          * @throws IllegalStateException
-         *         If the package is already declared as a package with the
-         *         {@link #contains contains} method, the package is already
-         *         declared as open, or this is a builder for an open module
+         *         If the package is already declared as open, or this is a
+         *         builder for an open module or automatic module
          */
         public Builder opens(Set<Opens.Modifier> ms,
                              String pn,
                              Set<String> targets)
         {
-            Opens e = new Opens(ms, requirePackageName(pn), targets);
+            Opens opens = new Opens(ms, pn, targets);
 
             // check targets
-            targets = e.targets();
+            targets = opens.targets();
             if (targets.isEmpty())
                 throw new IllegalArgumentException("Empty target set");
-            if (strict)
+            if (strict) {
+                requirePackageName(opens.source());
                 targets.stream().forEach(Checks::requireModuleName);
-
-            return opens(e);
+            }
+            return opens(opens);
         }
 
         /**
-         * Adds an <em>opens</em> directive to open a package with the given (and
-         * possibly empty) set of modifiers.
+         * Adds an open package with the given (and possibly empty) set of
+         * modifiers. The package is open to all modules.
          *
          * @param  ms
          *         The set of modifiers
@@ -1710,21 +1883,22 @@
          * @return This builder
          *
          * @throws IllegalArgumentException
-         *         If the package name is {@code null} or is not a legal Java
-         *         identifier
+         *         If the package name is {@code null} or is not a legal
+         *         package name
          * @throws IllegalStateException
-         *         If the package is already declared as a package with the
-         *         {@link #contains contains} method, the package is already
-         *         declared as open, or this is a builder for an open module
+         *         If the package is already declared as open, or this is a
+         *         builder for an open module or automatic module
          */
         public Builder opens(Set<Opens.Modifier> ms, String pn) {
-            Opens e = new Opens(ms, requirePackageName(pn), Collections.emptySet());
+            if (strict) {
+                requirePackageName(pn);
+            }
+            Opens e = new Opens(ms, pn, Collections.emptySet());
             return opens(e);
         }
 
         /**
-         * Adds an <em>opens</em> directive to open a package to a set of target
-         * modules.
+         * Adds an open package. The package is open to a set of target modules.
          *
          * @param  pn
          *         The package name
@@ -1734,20 +1908,20 @@
          * @return This builder
          *
          * @throws IllegalArgumentException
-         *         If the package name or any of the target modules is {@code
-         *         null} or is not a legal Java identifier, or the set of
-         *         targets is empty
+         *         If the package name is {@code null} or is not a legal
+         *         package name, the set of target modules is empty, or the set
+         *         of target modules contains a name that is not a legal module
+         *         name
          * @throws IllegalStateException
-         *         If the package is already declared as a package with the
-         *         {@link #contains contains} method, the package is already
-         *         declared as open, or this is a builder for an open module
+         *         If the package is already declared as open, or this is a
+         *         builder for an open module or automatic module
          */
         public Builder opens(String pn, Set<String> targets) {
             return opens(Collections.emptySet(), pn, targets);
         }
 
         /**
-         * Adds an <em>opens</em> directive to open a package.
+         * Adds an open package. The package is open to all modules.
          *
          * @param  pn
          *         The package name
@@ -1755,12 +1929,11 @@
          * @return This builder
          *
          * @throws IllegalArgumentException
-         *         If the package name is {@code null} or is not a legal Java
-         *         identifier
+         *         If the package name is {@code null} or is not a legal
+         *         package name
          * @throws IllegalStateException
-         *         If the package is already declared as a package with the
-         *         {@link #contains contains} method, the package is already
-         *         declared as open, or this is a builder for an open module
+         *         If the package is already declared as open, or this is a
+         *         builder for an open module or automatic module
          */
         public Builder opens(String pn) {
             return opens(Collections.emptySet(), pn);
@@ -1775,12 +1948,16 @@
          * @return This builder
          *
          * @throws IllegalArgumentException
-         *         If the service type is {@code null} or is not a legal Java
-         *         identifier
+         *         If the service type is {@code null} or not a qualified name of
+         *         a class in a named package
          * @throws IllegalStateException
          *         If a dependency on the service type has already been declared
+         *         or this is a builder for an an automatic module
          */
         public Builder uses(String service) {
+            if (automatic)
+                throw new IllegalStateException("Automatic modules can not declare"
+                                                + " service dependences");
             if (uses.contains(requireServiceTypeName(service)))
                 throw new IllegalStateException("Dependence upon service "
                                                 + service + " already declared");
@@ -1789,7 +1966,9 @@
         }
 
         /**
-         * Provides a service with one or more implementations.
+         * Provides a service with one or more implementations. The package for
+         * each {@link Provides#providers provider} (or provider factory) is
+         * added to the module if not already added.
          *
          * @param  p
          *         The provides
@@ -1801,16 +1980,18 @@
          *         declared
          */
         public Builder provides(Provides p) {
-            String st = p.service();
-            if (provides.containsKey(st))
+            String service = p.service();
+            if (provides.containsKey(service))
                 throw new IllegalStateException("Providers of service "
-                                                + st + " already declared");
-            provides.put(st, p);
+                                                + service + " already declared");
+            provides.put(service, p);
+            p.providers().forEach(name -> packages.add(packageName(name)));
             return this;
         }
 
         /**
-         * Provides implementations of a service.
+         * Provides implementations of a service. The package for each provider
+         * (or provider factory) is added to the module if not already added.
          *
          * @param  service
          *         The service type
@@ -1821,103 +2002,59 @@
          *
          * @throws IllegalArgumentException
          *         If the service type or any of the provider class names is
-         *         {@code null} or is not a legal Java identifier, or the list
-         *         of provider class names is empty
+         *         {@code null} or not a qualified name of a class in a named
+         *         package, or the list of provider class names is empty
          * @throws IllegalStateException
          *         If the providers for the service type have already been
          *         declared
          */
         public Builder provides(String service, List<String> providers) {
-            if (provides.containsKey(service))
-                throw new IllegalStateException("Providers of service "
-                                                + service + " already declared by " + name);
-
-            Provides p = new Provides(requireServiceTypeName(service), providers);
+            Provides p = new Provides(service, providers);
 
             // check providers after the set has been copied.
             List<String> providerNames = p.providers();
             if (providerNames.isEmpty())
                 throw new IllegalArgumentException("Empty providers set");
-            providerNames.forEach(Checks::requireServiceProviderName);
-            provides.put(service, p);
-            return this;
+            if (strict) {
+                requireServiceTypeName(p.service());
+                providerNames.forEach(Checks::requireServiceProviderName);
+            } else {
+                // Disallow service/providers in unnamed package
+                String pn = packageName(service);
+                if (pn.isEmpty()) {
+                    throw new IllegalArgumentException(service
+                                                       + ": unnamed package");
+                }
+                for (String name : providerNames) {
+                    pn = packageName(name);
+                    if (pn.isEmpty()) {
+                        throw new IllegalArgumentException(name
+                                                           + ": unnamed package");
+                    }
+                }
+            }
+            return provides(p);
         }
 
         /**
-         * Provides an implementation of a service.
-         *
-         * @param  service
-         *         The service type
-         * @param  provider
-         *         The provider or provider factory class name
-         *
-         * @return This builder
-         *
-         * @throws IllegalArgumentException
-         *         If the service type or the provider class name is {@code
-         *         null} or is not a legal Java identifier
-         * @throws IllegalStateException
-         *         If the providers for the service type have already been
-         *         declared
-         */
-        public Builder provides(String service, String provider) {
-            if (provider == null)
-                throw new IllegalArgumentException("'provider' is null");
-            return provides(service, List.of(provider));
-        }
-
-        /**
-         * Adds a (possible empty) set of packages to the module
+         * Adds packages to the module. All packages in the set of package names
+         * that are not in the module are added to module.
          *
          * @param  pns
-         *         The set of package names
+         *         The (possibly empty) set of package names
          *
          * @return This builder
          *
          * @throws IllegalArgumentException
          *         If any of the package names is {@code null} or is not a
-         *         legal Java identifier
-         * @throws IllegalStateException
-         *         If any of packages are already declared as packages in
-         *         the module. This includes packages that are already
-         *         declared as exported or open packages.
+         *         legal package name
          */
-        public Builder contains(Set<String> pns) {
-            pns.forEach(this::contains);
-            return this;
-        }
-
-        /**
-         * Adds a package to the module.
-         *
-         * @param  pn
-         *         The package name
-         *
-         * @return This builder
-         *
-         * @throws IllegalArgumentException
-         *         If the package name is {@code null}, or is not a legal Java
-         *         identifier
-         * @throws IllegalStateException
-         *         If the package is already declared as a package in the
-         *         module. This includes the package already declared as an
-         *         exported or open package.
-         */
-        public Builder contains(String pn) {
-            Checks.requirePackageName(pn);
-            if (concealedPackages.contains(pn)) {
-                throw new IllegalStateException("Package " + pn
-                                                + " already declared");
+        public Builder packages(Set<String> pns) {
+            if (strict) {
+                pns = new HashSet<>(pns);
+                pns.forEach(Checks::requirePackageName);
             }
-            if (exports.containsKey(pn)) {
-                throw new IllegalStateException("Exported package "
-                                                + pn + " already declared");
-            }
-            if (opens.containsKey(pn)) {
-                throw new IllegalStateException("Open package "
-                                                 + pn + " already declared");
-            }
-            concealedPackages.add(pn);
+            this.packages.addAll(pns);
             return this;
         }
 
@@ -1937,22 +2074,35 @@
         /**
          * Sets the module version.
          *
-         * @param  v
+         * @param  vs
          *         The version string to parse
          *
          * @return This builder
          *
          * @throws IllegalArgumentException
-         *         If {@code v} is null or cannot be parsed as a version string
+         *         If {@code vs} is {@code null} or cannot be parsed as a
+         *         version string
          *
          * @see Version#parse(String)
          */
-        public Builder version(String v) {
-            return version(Version.parse(v));
+        public Builder version(String vs) {
+            Version v;
+            if (strict) {
+                v = Version.parse(vs);
+            } else {
+                try {
+                    v = Version.parse(vs);
+                } catch (IllegalArgumentException ignore) {
+                    // for now, ignore when non-strict
+                    return this;
+                }
+            }
+            return version(v);
         }
 
         /**
-         * Sets the module main class.
+         * Sets the module main class. The package for the main class is added
+         * to the module if not already added.
          *
          * @param  mc
          *         The module main class
@@ -1960,10 +2110,24 @@
          * @return This builder
          *
          * @throws IllegalArgumentException
-         *         If {@code mainClass} is null or is not a legal Java identifier
+         *         If {@code mainClass} is {@code null} or not a qualified
+         *         name of a class in a named package
          */
         public Builder mainClass(String mc) {
-            mainClass = requireBinaryName("main class name", mc);
+            String pn;
+            if (strict) {
+                mc = requireQualifiedClassName("main class name", mc);
+                pn = packageName(mc);
+                assert !pn.isEmpty();
+            } else {
+                // Disallow main class in unnamed package
+                pn = packageName(mc);
+                if (pn.isEmpty()) {
+                    throw new IllegalArgumentException(mc + ": unnamed package");
+                }
+            }
+            mainClass = mc;
+            packages.add(pn);
             return this;
         }
 
@@ -1976,7 +2140,7 @@
          * @return This builder
          *
          * @throws IllegalArgumentException
-         *         If {@code name} is null or the empty String
+         *         If {@code name} is {@code null} or the empty String
          */
         public Builder osName(String name) {
             if (name == null || name.isEmpty())
@@ -1994,7 +2158,7 @@
          * @return This builder
          *
          * @throws IllegalArgumentException
-         *         If {@code name} is null or the empty String
+         *         If {@code name} is {@code null} or the empty String
          */
         public Builder osArch(String arch) {
             if (arch == null || arch.isEmpty())
@@ -2012,7 +2176,7 @@
          * @return This builder
          *
          * @throws IllegalArgumentException
-         *         If {@code name} is null or the empty String
+         *         If {@code name} is {@code null} or the empty String
          */
         public Builder osVersion(String version) {
             if (version == null || version.isEmpty())
@@ -2024,26 +2188,34 @@
         /**
          * Builds and returns a {@code ModuleDescriptor} from its components.
          *
+         * <p> The module will require "{@code java.base}" even if the dependence
+         * has not been declared (the exception is when building a module named
+         * "{@code java.base}" as it cannot require itself). The dependence on
+         * "{@code java.base}" will have the {@link
+         * java.lang.module.ModuleDescriptor.Requires.Modifier#MANDATED MANDATED}
+         * modifier if the dependence was not declared. </p>
+         *
          * @return The module descriptor
          */
         public ModuleDescriptor build() {
             Set<Requires> requires = new HashSet<>(this.requires.values());
-
-            Set<String> packages = new HashSet<>();
-            packages.addAll(exports.keySet());
-            packages.addAll(opens.keySet());
-            packages.addAll(concealedPackages);
-
             Set<Exports> exports = new HashSet<>(this.exports.values());
             Set<Opens> opens = new HashSet<>(this.opens.values());
 
+            // add dependency on java.base
+            if (strict
+                    && !name.equals("java.base")
+                    && !this.requires.containsKey("java.base")) {
+                requires.add(new Requires(Set.of(Requires.Modifier.MANDATED),
+                                          "java.base",
+                                          null));
+            }
+
             Set<Provides> provides = new HashSet<>(this.provides.values());
 
             return new ModuleDescriptor(name,
                                         version,
-                                        open,
-                                        automatic,
-                                        synthetic,
+                                        modifiers,
                                         requires,
                                         exports,
                                         opens,
@@ -2062,16 +2234,20 @@
      * Compares this module descriptor to another.
      *
      * <p> Two {@code ModuleDescriptor} objects are compared by comparing their
-     * module name lexicographically.  Where the module names are equal then
-     * the versions, if present, are compared. </p>
-     *
-     * @apiNote For now, the natural ordering is not consistent with equals.
-     * If two module descriptors have equal module names, equal versions if
-     * present, but their corresponding components are not equal, then they
-     * will be considered equal by this method.
+     * module names lexicographically. Where the module names are equal then the
+     * module versions are compared. When comparing the module versions then a
+     * module descriptor with a version is considered to succeed a module
+     * descriptor that does not have a version. Where the module names are equal
+     * and the versions are equal (or not present in both), then the set of
+     * modifiers are compared. Sets of modifiers are compared by comparing
+     * a <em>binary value</em> computed for each set. If a modifier is present
+     * in the set then the bit at the position of its ordinal is {@code 1}
+     * in the binary value, otherwise {@code 0}. If the two set of modifiers
+     * are also equal then the other components of the module descriptors are
+     * compared in a manner that is consistent with {@code equals}. </p>
      *
      * @param  that
-     *         The object to which this module descriptor is to be compared
+     *         The module descriptor to compare
      *
      * @return A negative integer, zero, or a positive integer if this module
      *         descriptor is less than, equal to, or greater than the given
@@ -2079,16 +2255,50 @@
      */
     @Override
     public int compareTo(ModuleDescriptor that) {
+        if (this == that) return 0;
+
         int c = this.name().compareTo(that.name());
         if (c != 0) return c;
-        if (version == null) {
-            if (that.version == null)
-                return 0;
-            return -1;
-        }
-        if (that.version == null)
-            return +1;
-        return version.compareTo(that.version);
+
+        c = compare(this.version, that.version);
+        if (c != 0) return c;
+
+        long v1 = modsValue(this.modifiers());
+        long v2 = modsValue(that.modifiers());
+        c = Long.compare(v1, v2);
+        if (c != 0) return c;
+
+        c = compare(this.requires, that.requires);
+        if (c != 0) return c;
+
+        c = compare(this.packages, that.packages);
+        if (c != 0) return c;
+
+        c = compare(this.exports, that.exports);
+        if (c != 0) return c;
+
+        c = compare(this.opens, that.opens);
+        if (c != 0) return c;
+
+        c = compare(this.uses, that.uses);
+        if (c != 0) return c;
+
+        c = compare(this.provides, that.provides);
+        if (c != 0) return c;
+
+        c = compare(this.mainClass, that.mainClass);
+        if (c != 0) return c;
+
+        c = compare(this.osName, that.osName);
+        if (c != 0) return c;
+
+        c = compare(this.osArch, that.osArch);
+        if (c != 0) return c;
+
+        c = compare(this.osVersion, that.osVersion);
+        if (c != 0) return c;
+
+        return 0;
     }
 
     /**
@@ -2115,10 +2325,9 @@
             return false;
         ModuleDescriptor that = (ModuleDescriptor)ob;
         return (name.equals(that.name)
-                && open == that.open
-                && automatic == that.automatic
-                && synthetic == that.synthetic
+                && modifiers.equals(that.modifiers)
                 && requires.equals(that.requires)
+                && Objects.equals(packages, that.packages)
                 && exports.equals(that.exports)
                 && opens.equals(that.opens)
                 && uses.equals(that.uses)
@@ -2127,12 +2336,9 @@
                 && Objects.equals(mainClass, that.mainClass)
                 && Objects.equals(osName, that.osName)
                 && Objects.equals(osArch, that.osArch)
-                && Objects.equals(osVersion, that.osVersion)
-                && Objects.equals(packages, that.packages));
+                && Objects.equals(osVersion, that.osVersion));
     }
 
-    private transient int hash;  // cached hash code
-
     /**
      * Computes a hash code for this module descriptor.
      *
@@ -2147,10 +2353,9 @@
         int hc = hash;
         if (hc == 0) {
             hc = name.hashCode();
-            hc = hc * 43 + Boolean.hashCode(open);
-            hc = hc * 43 + Boolean.hashCode(automatic);
-            hc = hc * 43 + Boolean.hashCode(synthetic);
+            hc = hc * 43 + Objects.hashCode(modifiers);
             hc = hc * 43 + requires.hashCode();
+            hc = hc * 43 + Objects.hashCode(packages);
             hc = hc * 43 + exports.hashCode();
             hc = hc * 43 + opens.hashCode();
             hc = hc * 43 + uses.hashCode();
@@ -2160,18 +2365,18 @@
             hc = hc * 43 + Objects.hashCode(osName);
             hc = hc * 43 + Objects.hashCode(osArch);
             hc = hc * 43 + Objects.hashCode(osVersion);
-            hc = hc * 43 + Objects.hashCode(packages);
             if (hc == 0)
                 hc = -1;
             hash = hc;
         }
         return hc;
     }
+    private transient int hash;  // cached hash code
 
     /**
-     * Returns a string describing this descriptor.
+     * <p> Returns a string describing the module. </p>
      *
-     * @return A string describing this descriptor
+     * @return A string describing the module
      */
     @Override
     public String toString() {
@@ -2201,31 +2406,50 @@
      *
      * @param  name
      *         The module name
+     * @param  ms
+     *         The set of module modifiers
      *
      * @return A new builder
      *
      * @throws IllegalArgumentException
-     *         If the module name is {@code null} or is not a legal Java
-     *         identifier
+     *         If the module name is {@code null} or is not a legal module
+     *         name, or the set of modifiers contains {@link
+     *         Modifier#AUTOMATIC AUTOMATIC} with other modifiers
      */
-    public static Builder module(String name) {
-        return new Builder(name, true, false, false);
+    public static Builder newModule(String name, Set<Modifier> ms) {
+        Set<Modifier> mods = new HashSet<>(ms);
+        if (mods.contains(Modifier.AUTOMATIC) && mods.size() > 1)
+            throw new IllegalArgumentException("AUTOMATIC cannot be used with"
+                                               + " other modifiers");
+
+        return new Builder(name, true, mods);
+    }
+
+    /**
+     * Instantiates a builder to build a module descriptor for a <em>normal</em>
+     * module. This method is equivalent to invoking {@link #newModule(String,Set)
+     * newModule} with an empty set of {@link ModuleDescriptor.Modifier modifiers}.
+     *
+     * @param  name
+     *         The module name
+     *
+     * @return A new builder
+     *
+     * @throws IllegalArgumentException
+     *         If the module name is {@code null} or is not a legal module
+     *         name
+     */
+    public static Builder newModule(String name) {
+        return new Builder(name, true, Set.of());
     }
 
     /**
      * Instantiates a builder to build a module descriptor for an open module.
-     * An open module does not declare any open packages but the resulting
-     * module is treated as if all packages are open.
+     * This method is equivalent to invoking {@link #newModule(String,Set)
+     * newModule} with the {@link ModuleDescriptor.Modifier#OPEN OPEN} modifier.
      *
-     * <p> As an example, the following creates a module descriptor for an open
-     * name "{@code m}" containing two packages, one of which is exported. </p>
-     * <pre>{@code
-     *     ModuleDescriptor descriptor = ModuleDescriptor.openModule("m")
-     *         .requires("java.base")
-     *         .exports("p")
-     *         .contains("q")
-     *         .build();
-     * }</pre>
+     * <p> The builder for an open module cannot be used to declare any open
+     * packages. </p>
      *
      * @param  name
      *         The module name
@@ -2233,19 +2457,22 @@
      * @return A new builder that builds an open module
      *
      * @throws IllegalArgumentException
-     *         If the module name is {@code null} or is not a legal Java
-     *         identifier
+     *         If the module name is {@code null} or is not a legal module
+     *         name
      */
-    public static Builder openModule(String name) {
-        return new Builder(name, true, true, false);
+    public static Builder newOpenModule(String name) {
+        return new Builder(name, true, Set.of(Modifier.OPEN));
     }
 
     /**
      * Instantiates a builder to build a module descriptor for an automatic
-     * module. Automatic modules receive special treatment during resolution
-     * (see {@link Configuration}) so that they read all other modules. When
-     * Instantiated in the Java virtual machine as a {@link java.lang.reflect.Module}
-     * then the Module reads every unnamed module in the Java virtual machine.
+     * module. This method is equivalent to invoking {@link #newModule(String,Set)
+     * newModule} with the {@link ModuleDescriptor.Modifier#AUTOMATIC AUTOMATIC}
+     * modifier.
+     *
+     * <p> The builder for an automatic module cannot be used to declare module
+     * or service dependences. It also cannot be used to declare any exported
+     * or open packages. </p>
      *
      * @param  name
      *         The module name
@@ -2253,13 +2480,13 @@
      * @return A new builder that builds an automatic module
      *
      * @throws IllegalArgumentException
-     *         If the module name is {@code null} or is not a legal Java
-     *         identifier
+     *         If the module name is {@code null} or is not a legal module
+     *         name
      *
      * @see ModuleFinder#of(Path[])
      */
-    public static Builder automaticModule(String name) {
-        return new Builder(name, true, false, false).automatic(true);
+    public static Builder newAutomaticModule(String name) {
+        return new Builder(name, true, Set.of(Modifier.AUTOMATIC));
     }
 
 
@@ -2269,8 +2496,12 @@
      *
      * <p> If the descriptor encoded in the input stream does not indicate a
      * set of packages in the module then the {@code packageFinder} will be
-     * invoked. If the {@code packageFinder} throws an {@link UncheckedIOException}
-     * then {@link IOException} cause will be re-thrown. </p>
+     * invoked. The set of packages that the {@code packageFinder} returns
+     * must include all the packages that the module exports, opens, as well
+     * as the packages of the service implementations that the module provides,
+     * and the package of the main class (if the module has a main class). If
+     * the {@code packageFinder} throws an {@link UncheckedIOException} then
+     * {@link IOException} cause will be re-thrown. </p>
      *
      * <p> If there are bytes following the module descriptor then it is
      * implementation specific as to whether those bytes are read, ignored,
@@ -2292,7 +2523,9 @@
      * @return The module descriptor
      *
      * @throws InvalidModuleDescriptorException
-     *         If an invalid module descriptor is detected
+     *         If an invalid module descriptor is detected or the set of
+     *         packages returned by the {@code packageFinder} does not include
+     *         all of the packages obtained from the module descriptor
      * @throws IOException
      *         If an I/O error occurs reading from the input stream or {@code
      *         UncheckedIOException} is thrown by the package finder
@@ -2305,8 +2538,12 @@
     }
 
     /**
-     * Reads the binary form of a module declaration from an input stream
-     * as a module descriptor.
+     * Reads the binary form of a module declaration from an input stream as a
+     * module descriptor. This method works exactly as specified by the 2-arg
+     * {@link #read(InputStream,Supplier) read} method with the exception that
+     * a packager finder is not used to find additional packages when the
+     * module descriptor read from the stream does not indicate the set of
+     * packages.
      *
      * @param  in
      *         The input stream
@@ -2327,7 +2564,13 @@
      * as a module descriptor.
      *
      * <p> If the descriptor encoded in the byte buffer does not indicate a
-     * set of packages then the {@code packageFinder} will be invoked. </p>
+     * set of packages in the module then the {@code packageFinder} will be
+     * invoked. The set of packages that the {@code packageFinder} returns
+     * must include all the packages that the module exports, opens, as well
+     * as the packages of the service implementations that the module provides,
+     * and the package of the main class (if the module has a main class). If
+     * the {@code packageFinder} throws an {@link UncheckedIOException} then
+     * {@link IOException} cause will be re-thrown. </p>
      *
      * <p> The module descriptor is read from the buffer stating at index
      * {@code p}, where {@code p} is the buffer's {@link ByteBuffer#position()
@@ -2353,7 +2596,9 @@
      * @return The module descriptor
      *
      * @throws InvalidModuleDescriptorException
-     *         If an invalid module descriptor is detected
+     *         If an invalid module descriptor is detected or the set of
+     *         packages returned by the {@code packageFinder} does not include
+     *         all of the packages obtained from the module descriptor
      */
     public static ModuleDescriptor read(ByteBuffer bb,
                                         Supplier<Set<String>> packageFinder)
@@ -2362,8 +2607,11 @@
     }
 
     /**
-     * Reads the binary form of a module declaration from a byte buffer
-     * as a module descriptor.
+     * Reads the binary form of a module declaration from a byte buffer as a
+     * module descriptor. This method works exactly as specified by the 2-arg
+     * {@link #read(ByteBuffer,Supplier) read} method with the exception that a
+     * packager finder is not used to find additional packages when the module
+     * descriptor encoded in the buffer does not indicate the set of packages.
      *
      * @param  bb
      *         The byte buffer
@@ -2398,6 +2646,11 @@
         }
     }
 
+    private static String packageName(String cn) {
+        int index = cn.lastIndexOf('.');
+        return (index == -1) ? "" : cn.substring(0, index);
+    }
+
     /**
      * Returns a string containing the given set of modifiers and label.
      */
@@ -2407,6 +2660,36 @@
                 .collect(Collectors.joining(" "));
     }
 
+    private static <T extends Object & Comparable<? super T>>
+    int compare(T obj1, T obj2) {
+        if (obj1 != null) {
+            return (obj2 != null) ? obj1.compareTo(obj2) : 1;
+        } else {
+            return (obj2 == null) ? 0 : -1;
+        }
+    }
+
+    /**
+     * Compares two sets of {@code Comparable} objects.
+     */
+    @SuppressWarnings("unchecked")
+    private static <T extends Object & Comparable<? super T>>
+    int compare(Set<T> s1, Set<T> s2) {
+        T[] a1 = (T[]) s1.toArray();
+        T[] a2 = (T[]) s2.toArray();
+        Arrays.sort(a1);
+        Arrays.sort(a2);
+        return Arrays.compare(a1, a2);
+    }
+
+    private static <E extends Enum<E>> long modsValue(Set<E> set) {
+        long value = 0;
+        for (Enum<E> e : set) {
+            value += 1 << e.ordinal();
+        }
+        return value;
+    }
+
     static {
         /**
          * Setup the shared secret to allow code in other packages access
@@ -2417,19 +2700,21 @@
                 @Override
                 public Builder newModuleBuilder(String mn,
                                                 boolean strict,
-                                                boolean open,
-                                                boolean synthetic) {
-                    return new Builder(mn, strict, open, synthetic);
+                                                Set<ModuleDescriptor.Modifier> modifiers) {
+                    return new Builder(mn, strict, modifiers);
                 }
 
                 @Override
-                public Set<String> exportedPackages(ModuleDescriptor.Builder builder) {
-                    return builder.exportedPackages();
+                public Set<String> packages(ModuleDescriptor.Builder builder) {
+                    return builder.packages();
                 }
 
                 @Override
-                public Set<String> openPackages(ModuleDescriptor.Builder builder) {
-                    return builder.openPackages();
+                public void requires(ModuleDescriptor.Builder builder,
+                                     Set<Requires.Modifier> ms,
+                                     String mn,
+                                     String compiledVersion) {
+                    builder.requires(ms, mn, compiledVersion);
                 }
 
                 @Override
@@ -2467,22 +2752,9 @@
                 }
 
                 @Override
-                public Version newVersion(String v) {
-                    return new Version(v);
-                }
-
-                @Override
-                public ModuleDescriptor newModuleDescriptor(ModuleDescriptor md,
-                                                            Set<String> pkgs) {
-                    return new ModuleDescriptor(md, pkgs);
-                }
-
-                @Override
                 public ModuleDescriptor newModuleDescriptor(String name,
                                                             Version version,
-                                                            boolean open,
-                                                            boolean automatic,
-                                                            boolean synthetic,
+                                                            Set<ModuleDescriptor.Modifier> modifiers,
                                                             Set<Requires> requires,
                                                             Set<Exports> exports,
                                                             Set<Opens> opens,
@@ -2496,9 +2768,7 @@
                                                             int hashCode) {
                     return new ModuleDescriptor(name,
                                                 version,
-                                                open,
-                                                automatic,
-                                                synthetic,
+                                                modifiers,
                                                 requires,
                                                 exports,
                                                 opens,
@@ -2514,12 +2784,12 @@
                 }
 
                 @Override
-                public Configuration resolveRequiresAndUses(ModuleFinder finder,
-                                                            Collection<String> roots,
-                                                            boolean check,
-                                                            PrintStream traceOutput)
+                public Configuration resolveAndBind(ModuleFinder finder,
+                                                    Collection<String> roots,
+                                                    boolean check,
+                                                    PrintStream traceOutput)
                 {
-                    return Configuration.resolveRequiresAndUses(finder, roots, check, traceOutput);
+                    return Configuration.resolveAndBind(finder, roots, check, traceOutput);
                 }
             });
     }
--- a/src/java.base/share/classes/java/lang/module/ModuleFinder.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/module/ModuleFinder.java	Fri Feb 10 09:04:39 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, 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
@@ -42,14 +42,15 @@
 import java.util.Optional;
 import java.util.Set;
 
+import jdk.internal.module.ModuleBootstrap;
 import jdk.internal.module.ModulePath;
 import jdk.internal.module.SystemModuleFinder;
 import sun.security.action.GetPropertyAction;
 
 /**
  * A finder of modules. A {@code ModuleFinder} is used to find modules during
- * <a href="Configuration.html#resolution">resolution</a> or
- * <a href="Configuration.html#servicebinding">service binding</a>.
+ * <a href="package-summary.html#resolution">resolution</a> or
+ * <a href="package-summary.html#servicebinding">service binding</a>.
  *
  * <p> A {@code ModuleFinder} can only find one module with a given name. A
  * {@code ModuleFinder} that finds modules in a sequence of directories, for
@@ -85,6 +86,7 @@
  * <p> A {@code ModuleFinder} is not required to be thread safe. </p>
  *
  * @since 9
+ * @spec JPMS
  */
 
 public interface ModuleFinder {
@@ -124,8 +126,8 @@
      * to find that module. </p>
      *
      * @apiNote This is important to have for methods such as {@link
-     * Configuration#resolveRequiresAndUses resolveRequiresAndUses} that need
-     * to scan the module path to find modules that provide a specific service.
+     * Configuration#resolveAndBind resolveAndBind} that need to scan the
+     * module path to find modules that provide a specific service.
      *
      * @return The set of all module references that this finder locates
      *
@@ -172,7 +174,8 @@
         } else {
             Path mlib = Paths.get(home, "modules");
             if (Files.isDirectory(mlib)) {
-                return of(mlib);
+                // exploded build may be patched
+                return ModulePath.of(ModuleBootstrap.patcher(), mlib);
             } else {
                 throw new InternalError("Unable to detect the run-time image");
             }
@@ -198,13 +201,9 @@
      *
      * <p> If an element is a path to a directory of modules then each entry in
      * the directory is a packaged module or the top-level directory of an
-     * exploded module. The module finder's {@link #find(String) find} or
-     * {@link #findAll() findAll} methods throw {@link FindException} if a
-     * directory containing more than one module with the same name is
-     * encountered. </p>
-     *
-     * <p> If an element in the array is a path to a directory, and that
-     * directory contains a file named {@code module-info.class}, then the
+     * exploded module. It it an error if a directory contains more than one
+     * module with the same name. If an element is a path to a directory, and
+     * that directory contains a file named {@code module-info.class}, then the
      * directory is treated as an exploded module rather than a directory of
      * modules. </p>
      *
@@ -214,9 +213,8 @@
      * entry in a {@link java.util.jar.JarFile#isMultiRelease() multi-release}
      * JAR file) is a modular JAR and is an <em>explicit module</em>.
      * A JAR file that does not have a {@code module-info.class} in the
-     * top-level directory is an {@link ModuleDescriptor#isAutomatic automatic}
-     * module. The {@link ModuleDescriptor} for an automatic module is created as
-     * follows:
+     * top-level directory is created as an automatic module. The components
+     * for the automatic module are derived as follows:
      *
      * <ul>
      *
@@ -248,46 +246,48 @@
      *
      *     </ul></li>
      *
-     *     <li><p> It {@link ModuleDescriptor#requires() requires} {@code
-     *     java.base}. </p></li>
-     *
-     *     <li><p> The set of packages in the module is derived from the names
-     *     of non-directory entries in the JAR file. A candidate package name
-     *     is derived from an entry using the characters up to, but not
-     *     including, the last forward slash. All remaining forward slashes are
-     *     replaced with dot ({@code "."}). If the resulting string is a valid
-     *     Java identifier then it is assumed to be a package name. For example,
-     *     if the JAR file contains an entry "{@code p/q/Foo.class}" then the
-     *     package name derived is "{@code p.q}". All packages are {@link
-     *     ModuleDescriptor#exports() exported}. </p></li>
+     *     <li><p> The set of packages in the module is derived from the
+     *     non-directory entries in the JAR file that have names ending in
+     *     "{@code .class}". A candidate package name is derived from the name
+     *     using the characters up to, but not including, the last forward slash.
+     *     All remaining forward slashes are replaced with dot ({@code "."}). If
+     *     the resulting string is a legal package name then it is assumed to be
+     *     a package name. For example, if the JAR file contains the entry
+     *     "{@code p/q/Foo.class}" then the package name derived is
+     *     "{@code p.q}".</p></li>
      *
      *     <li><p> The contents of entries starting with {@code
      *     META-INF/services/} are assumed to be service configuration files
      *     (see {@link java.util.ServiceLoader}). If the name of a file
-     *     (that follows {@code META-INF/services/}) is a legal Java identifier
-     *     then it is assumed to be the fully-qualified binary name of a
-     *     service type. The entries in the file are assumed to be the
-     *     fully-qualified binary names of provider classes. </p></li>
+     *     (that follows {@code META-INF/services/}) is a legal class name
+     *     then it is assumed to be the fully-qualified class name of a service
+     *     type. The entries in the file are assumed to be the fully-qualified
+     *     class names of provider classes. </p></li>
      *
      *     <li><p> If the JAR file has a {@code Main-Class} attribute in its
-     *     main manifest then its value is the {@link
+     *     main manifest then its value is the module {@link
      *     ModuleDescriptor#mainClass() main class}. </p></li>
      *
      * </ul>
      *
      * <p> If a {@code ModuleDescriptor} cannot be created (by means of the
      * {@link ModuleDescriptor.Builder ModuleDescriptor.Builder} API) for an
-     * automatic module then {@code FindException} is thrown. This can arise,
-     * for example, when a legal Java identifier name cannot be derived from
-     * the file name of the JAR file or where the JAR file contains a {@code
-     * .class} in the top-level directory of the JAR file. </p>
+     * automatic module then {@code FindException} is thrown. This can arise
+     * when a legal module name cannot be derived from the file name of the JAR
+     * file, where the JAR file contains a {@code .class} in the top-level
+     * directory of the JAR file, where an entry in a service configuration
+     * file is not a legal class name or its package name is not in the set of
+     * packages derived for the module, or where the module main class is not
+     * a legal class name or its package is not in the module. </p>
      *
      * <p> In addition to JAR files, an implementation may also support modules
-     * that are packaged in other implementation specific module formats. When
-     * a file is encountered that is not recognized as a packaged module then
-     * {@code FindException} is thrown. An implementation may choose to ignore
-     * some files, {@link java.nio.file.Files#isHidden hidden} files for
-     * example. Paths to files that do not exist are always ignored. </p>
+     * that are packaged in other implementation specific module formats. If
+     * an element in the array specified to this method is a path to a directory
+     * of modules then entries in the directory that not recognized as modules
+     * are ignored. If an element in the array is a path to a packaged module
+     * that is not recognized then a {@code FindException} is thrown when the
+     * file is encountered. Paths to files that do not exist are always ignored.
+     * </p>
      *
      * <p> As with automatic modules, the contents of a packaged or exploded
      * module may need to be <em>scanned</em> in order to determine the packages
@@ -325,7 +325,7 @@
             };
         }
 
-        return new ModulePath(entries);
+        return ModulePath.of(entries);
     }
 
     /**
--- a/src/java.base/share/classes/java/lang/module/ModuleReader.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/module/ModuleReader.java	Fri Feb 10 09:04:39 2017 +0000
@@ -45,7 +45,7 @@
  * module. A module reader is also intended to be used by {@code ClassLoader}
  * implementations that load classes and resources from modules. </p>
  *
- * <p> A resource in a module is identified by a name that is a
+ * <p> A resource in a module is identified by an abstract name that is a
  * '{@code /}'-separated path string. For example, module {@code java.base} may
  * have a resource "{@code java/lang/Object.class}" that, by convention, is the
  * class file for {@code java.lang.Object}. </p>
@@ -61,8 +61,18 @@
  * open}, {@link #read read}, and {@link #list list} methods may throw {@code
  * SecurityException} if access is denied by the security manager. </p>
  *
+ * @implSpec Implementations of {@code ModuleReader} should take great care
+ * when translating an abstract resource name to the location of a resource in
+ * a packaged module or on the file system. Implementations are advised to
+ * treat resource names with elements such as '{@code .},  '{@code ..}',
+ * elements containing file separators, or empty elements as "not found". More
+ * generally, if the resource name is not in the stream of elements that the
+ * {@code list} method returns then the resource should be treated as "not
+ * found" to avoid inconsistencies.
+ *
  * @see ModuleReference
  * @since 9
+ * @spec JPMS
  */
 
 public interface ModuleReader extends Closeable {
@@ -148,6 +158,9 @@
      *         If an I/O error occurs or the module reader is closed
      * @throws SecurityException
      *         If denied by the security manager
+     * @throws OutOfMemoryError
+     *         If the resource is larger than {@code Integer.MAX_VALUE},
+     *         the maximum capacity of a byte buffer
      *
      * @see ClassLoader#defineClass(String, ByteBuffer, java.security.ProtectionDomain)
      */
--- a/src/java.base/share/classes/java/lang/module/ModuleReference.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/module/ModuleReference.java	Fri Feb 10 09:04:39 2017 +0000
@@ -44,6 +44,7 @@
  * @see ModuleFinder
  * @see ModuleReader
  * @since 9
+ * @spec JPMS
  */
 
 public abstract class ModuleReference {
@@ -76,7 +77,7 @@
     /**
      * Returns the location of this module's content, if known.
      *
-     * <p> This URI, when present, is used as the {@linkplain
+     * <p> This URI, when present, can be used as the {@linkplain
      * java.security.CodeSource#getLocation location} value of a {@link
      * java.security.CodeSource CodeSource} so that a module's classes can be
      * granted specific permissions when loaded by a {@link
--- a/src/java.base/share/classes/java/lang/module/ResolutionException.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/module/ResolutionException.java	Fri Feb 10 09:04:39 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, 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
@@ -26,10 +26,12 @@
 package java.lang.module;
 
 /**
- * Thrown when resolving a set of modules or binding fails.
+ * Thrown when resolving a set of modules, or resolving a set of modules with
+ * service binding, fails.
  *
  * @see Configuration
  * @since 9
+ * @spec JPMS
  */
 public class ResolutionException extends RuntimeException {
     private static final long serialVersionUID = -1031186845316729450L;
--- a/src/java.base/share/classes/java/lang/module/ResolvedModule.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/module/ResolvedModule.java	Fri Feb 10 09:04:39 2017 +0000
@@ -37,6 +37,7 @@
  * module's content.
  *
  * @since 9
+ * @spec JPMS
  * @see Configuration#modules()
  */
 public final class ResolvedModule {
--- a/src/java.base/share/classes/java/lang/module/Resolver.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/module/Resolver.java	Fri Feb 10 09:04:39 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -49,8 +49,8 @@
 import jdk.internal.module.ModuleReferenceImpl;
 
 /**
- * The resolver used by {@link Configuration#resolveRequires} and
- * {@link Configuration#resolveRequiresAndUses}.
+ * The resolver used by {@link Configuration#resolve} and {@link
+ * Configuration#resolveAndBind}.
  *
  * @implNote The resolver is used at VM startup and so deliberately avoids
  * using lambda and stream usages in code paths used during startup.
@@ -66,7 +66,19 @@
     // maps module name to module reference
     private final Map<String, ModuleReference> nameToReference = new HashMap<>();
 
+    // module constraints on target platform
+    private String osName;
+    private String osArch;
+    private String osVersion;
 
+    String osName() { return osName; }
+    String osArch() { return osArch; }
+    String osVersion() { return osVersion; }
+
+    /**
+     * @throws IllegalArgumentException if there are more than one parent and
+     *         the constraints on the target platform conflict
+     */
     Resolver(ModuleFinder beforeFinder,
              List<Configuration> parents,
              ModuleFinder afterFinder,
@@ -75,15 +87,54 @@
         this.parents = parents;
         this.afterFinder = afterFinder;
         this.traceOutput = traceOutput;
+
+        // record constraints on target platform, checking that they don't conflict
+        for (Configuration parent : parents) {
+            String value = parent.osName();
+            if (value != null) {
+                if (osName == null) {
+                    osName = value;
+                } else {
+                    if (!value.equals(osName)) {
+                        failParentConflict("Operating System", osName, value);
+                    }
+                }
+            }
+            value = parent.osArch();
+            if (value != null) {
+                if (osArch == null) {
+                    osArch = value;
+                } else {
+                    if (!value.equals(osArch)) {
+                        failParentConflict("OS architecture", osArch, value);
+                    }
+                }
+            }
+            value = parent.osVersion();
+            if (value != null) {
+                if (osVersion == null) {
+                    osVersion  = value;
+                } else {
+                    if (!value.equals(osVersion)) {
+                        failParentConflict("OS version", osVersion, value);
+                    }
+                }
+            }
+        }
     }
 
+    private void failParentConflict(String constraint, String s1, String s2) {
+        String msg = "Parents have conflicting constraints on target "
+                     + constraint + ": " + s1 + ", " + s2;
+        throw new IllegalArgumentException(msg);
+    }
 
     /**
      * Resolves the given named modules.
      *
      * @throws ResolutionException
      */
-    Resolver resolveRequires(Collection<String> roots) {
+    Resolver resolve(Collection<String> roots) {
 
         // create the visit stack to get us started
         Deque<ModuleDescriptor> q = new ArrayDeque<>();
@@ -100,7 +151,7 @@
 
                 mref = findWithAfterFinder(root);
                 if (mref == null) {
-                    fail("Module %s not found", root);
+                    findFail("Module %s not found", root);
                 }
             }
 
@@ -109,8 +160,7 @@
                 mref.location().ifPresent(uri -> trace("  (%s)", uri));
             }
 
-            assert mref.descriptor().name().equals(root);
-            nameToReference.put(root, mref);
+            addFoundModule(mref);
             q.push(mref.descriptor());
         }
 
@@ -152,19 +202,19 @@
 
                     mref = findWithAfterFinder(dn);
                     if (mref == null) {
-                        fail("Module %s not found, required by %s",
-                                dn, descriptor.name());
+                        findFail("Module %s not found, required by %s",
+                                 dn, descriptor.name());
                     }
                 }
 
                 if (!nameToReference.containsKey(dn)) {
-                    nameToReference.put(dn, mref);
+                    addFoundModule(mref);
                     q.offer(mref.descriptor());
                     resolved.add(mref.descriptor());
 
                     if (isTracing()) {
                         trace("Module %s located, required by %s",
-                                dn, descriptor.name());
+                              dn, descriptor.name());
                         mref.location().ifPresent(uri -> trace("  (%s)", uri));
                     }
                 }
@@ -181,7 +231,7 @@
      * Augments the set of resolved modules with modules induced by the
      * service-use relation.
      */
-    Resolver resolveUses() {
+    Resolver bind() {
 
         // Scan the finders for all available service provider modules. As
         // java.base uses services then then module finders will be scanned
@@ -246,7 +296,7 @@
                                             mref.location()
                                                 .ifPresent(uri -> trace("  (%s)", uri));
                                         }
-                                        nameToReference.put(pn, mref);
+                                        addFoundModule(mref);
                                         q.push(provider);
                                     }
                                 }
@@ -264,6 +314,81 @@
 
 
     /**
+     * Add the module to the nameToReference map. Also check any constraints on
+     * the target platform with the constraints of other modules.
+     */
+    private void addFoundModule(ModuleReference mref) {
+        ModuleDescriptor descriptor = mref.descriptor();
+        nameToReference.put(descriptor.name(), mref);
+
+        if (descriptor.osName().isPresent()
+                || descriptor.osArch().isPresent()
+                || descriptor.osVersion().isPresent())
+            checkTargetConstraints(descriptor);
+    }
+
+    /**
+     * Check that the module's constraints on the target platform do not
+     * conflict with the constraints of other modules resolved so far or
+     * modules in parent configurations.
+     */
+    private void checkTargetConstraints(ModuleDescriptor descriptor) {
+        String value = descriptor.osName().orElse(null);
+        if (value != null) {
+            if (osName == null) {
+                osName = value;
+            } else {
+                if (!value.equals(osName)) {
+                    failTargetConstraint(descriptor);
+                }
+            }
+        }
+        value = descriptor.osArch().orElse(null);
+        if (value != null) {
+            if (osArch == null) {
+                osArch = value;
+            } else {
+                if (!value.equals(osArch)) {
+                    failTargetConstraint(descriptor);
+                }
+            }
+        }
+        value = descriptor.osVersion().orElse(null);
+        if (value != null) {
+            if (osVersion == null) {
+                osVersion = value;
+            } else {
+                if (!value.equals(osVersion)) {
+                    failTargetConstraint(descriptor);
+                }
+            }
+        }
+    }
+
+    private void failTargetConstraint(ModuleDescriptor md) {
+        String s1 = targetAsString(osName, osArch, osVersion);
+        String s2 = targetAsString(md);
+        findFail("Module %s has constraints on target platform that conflict" +
+                 " with other modules: %s, %s", md.name(), s1, s2);
+    }
+
+    private String targetAsString(ModuleDescriptor descriptor) {
+        String osName = descriptor.osName().orElse(null);
+        String osArch = descriptor.osArch().orElse(null);
+        String osVersion = descriptor.osVersion().orElse(null);
+        return targetAsString(osName, osArch, osVersion);
+    }
+
+    private String targetAsString(String osName, String osArch, String osVersion) {
+        return new StringJoiner("-")
+                .add(Objects.toString(osName, "*"))
+                .add(Objects.toString(osArch, "*"))
+                .add(Objects.toString(osVersion, "*"))
+                .toString();
+    }
+
+
+    /**
      * Execute post-resolution checks and returns the module graph of resolved
      * modules as {@code Map}. The resolved modules will be in the given
      * configuration.
@@ -281,7 +406,6 @@
 
         if (check) {
             detectCycles();
-            checkPlatformConstraints();
             checkHashes();
         }
 
@@ -319,8 +443,7 @@
         if (!visited.contains(descriptor)) {
             boolean added = visitPath.add(descriptor);
             if (!added) {
-                throw new ResolutionException("Cycle detected: " +
-                        cycleAsString(descriptor));
+                resolveFail("Cycle detected: %s", cycleAsString(descriptor));
             }
             for (ModuleDescriptor.Requires requires : descriptor.requires()) {
                 String dn = requires.name();
@@ -354,86 +477,6 @@
 
 
     /**
-     * If there are platform specific modules then check that the OS name,
-     * architecture and version match.
-     *
-     * @apiNote This method does not currently check if the OS matches
-     *          platform specific modules in parent configurations.
-     */
-    private void checkPlatformConstraints() {
-
-        // first module encountered that is platform specific
-        String savedModuleName = null;
-        String savedOsName = null;
-        String savedOsArch = null;
-        String savedOsVersion = null;
-
-        for (ModuleReference mref : nameToReference.values()) {
-            ModuleDescriptor descriptor = mref.descriptor();
-
-            String osName = descriptor.osName().orElse(null);
-            String osArch = descriptor.osArch().orElse(null);
-            String osVersion = descriptor.osVersion().orElse(null);
-
-            if (osName != null || osArch != null || osVersion != null) {
-
-                if (savedModuleName == null) {
-
-                    savedModuleName = descriptor.name();
-                    savedOsName = osName;
-                    savedOsArch = osArch;
-                    savedOsVersion = osVersion;
-
-                } else {
-
-                    boolean matches = platformMatches(osName, savedOsName)
-                            && platformMatches(osArch, savedOsArch)
-                            && platformMatches(osVersion, savedOsVersion);
-
-                    if (!matches) {
-                        String s1 = platformAsString(savedOsName,
-                                                     savedOsArch,
-                                                     savedOsVersion);
-
-                        String s2 = platformAsString(osName, osArch, osVersion);
-                        fail("Mismatching constraints on target platform: "
-                                + savedModuleName + ": " + s1
-                                + ", " + descriptor.name() + ": " + s2);
-                    }
-
-                }
-
-            }
-        }
-
-    }
-
-    /**
-     * Returns true if the s1 and s2 are equal or one of them is null.
-     */
-    private boolean platformMatches(String s1, String s2) {
-        if (s1 == null || s2 == null)
-            return true;
-        else
-            return Objects.equals(s1, s2);
-    }
-
-    /**
-     * Return a string that encodes the OS name/arch/version.
-     */
-    private String platformAsString(String osName,
-                                    String osArch,
-                                    String osVersion) {
-
-        return new StringJoiner("-")
-                .add(Objects.toString(osName, "*"))
-                .add(Objects.toString(osArch, "*"))
-                .add(Objects.toString(osVersion, "*"))
-                .toString();
-
-    }
-
-    /**
      * Checks the hashes in the module descriptor to ensure that they match
      * any recorded hashes.
      */
@@ -460,7 +503,7 @@
                     continue;
 
                 if (!(mref2 instanceof ModuleReferenceImpl)) {
-                    fail("Unable to compute the hash of module %s", dn);
+                    findFail("Unable to compute the hash of module %s", dn);
                 }
 
                 // skip checking the hash if the module has been patched
@@ -469,11 +512,11 @@
                     byte[] recordedHash = hashes.hashFor(dn);
                     byte[] actualHash = other.computeHash(algorithm);
                     if (actualHash == null)
-                        fail("Unable to compute the hash of module %s", dn);
+                        findFail("Unable to compute the hash of module %s", dn);
                     if (!Arrays.equals(recordedHash, actualHash)) {
-                        fail("Hash of %s (%s) differs to expected hash (%s)" +
-                             " recorded in %s", dn, toHexString(actualHash),
-                             toHexString(recordedHash), descriptor.name());
+                        findFail("Hash of %s (%s) differs to expected hash (%s)" +
+                                 " recorded in %s", dn, toHexString(actualHash),
+                                 toHexString(recordedHash), descriptor.name());
                     }
                 }
             }
@@ -694,37 +737,38 @@
             for (ResolvedModule endpoint : reads) {
                 ModuleDescriptor descriptor2 = endpoint.descriptor();
 
-                for (ModuleDescriptor.Exports export : descriptor2.exports()) {
+                if (descriptor2.isAutomatic()) {
+                    // automatic modules read self and export all packages
+                    if (descriptor2 != descriptor1){
+                        for (String source : descriptor2.packages()) {
+                            ModuleDescriptor supplier
+                                = packageToExporter.putIfAbsent(source, descriptor2);
 
-                    if (export.isQualified()) {
-                        if (!export.targets().contains(descriptor1.name()))
-                            continue;
-                    }
-
-                    // source is exported to descriptor2
-                    String source = export.source();
-                    ModuleDescriptor other
-                        = packageToExporter.putIfAbsent(source, descriptor2);
-
-                    if (other != null && other != descriptor2) {
-                        // package might be local to descriptor1
-                        if (other == descriptor1) {
-                            fail("Module %s contains package %s"
-                                 + ", module %s exports package %s to %s",
-                                    descriptor1.name(),
-                                    source,
-                                    descriptor2.name(),
-                                    source,
-                                    descriptor1.name());
-                        } else {
-                            fail("Modules %s and %s export package %s to module %s",
-                                    descriptor2.name(),
-                                    other.name(),
-                                    source,
-                                    descriptor1.name());
+                            // descriptor2 and 'supplier' export source to descriptor1
+                            if (supplier != null) {
+                                failTwoSuppliers(descriptor1, source, descriptor2, supplier);
+                            }
                         }
 
                     }
+                } else {
+                    for (ModuleDescriptor.Exports export : descriptor2.exports()) {
+                        if (export.isQualified()) {
+                            if (!export.targets().contains(descriptor1.name()))
+                                continue;
+                        }
+
+                        // source is exported by descriptor2
+                        String source = export.source();
+                        ModuleDescriptor supplier
+                            = packageToExporter.putIfAbsent(source, descriptor2);
+
+                        // descriptor2 and 'supplier' export source to descriptor1
+                        if (supplier != null) {
+                            failTwoSuppliers(descriptor1, source, descriptor2, supplier);
+                        }
+                    }
+
                 }
             }
 
@@ -735,8 +779,8 @@
                 for (String service : descriptor1.uses()) {
                     String pn = packageName(service);
                     if (!packageToExporter.containsKey(pn)) {
-                        fail("Module %s does not read a module that exports %s",
-                             descriptor1.name(), pn);
+                        resolveFail("Module %s does not read a module that exports %s",
+                                    descriptor1.name(), pn);
                     }
                 }
 
@@ -744,15 +788,8 @@
                 for (ModuleDescriptor.Provides provides : descriptor1.provides()) {
                     String pn = packageName(provides.service());
                     if (!packageToExporter.containsKey(pn)) {
-                        fail("Module %s does not read a module that exports %s",
-                             descriptor1.name(), pn);
-                    }
-
-                    for (String provider : provides.providers()) {
-                        if (!packages.contains(packageName(provider))) {
-                            fail("Provider %s not in module %s",
-                                 provider, descriptor1.name());
-                        }
+                        resolveFail("Module %s does not read a module that exports %s",
+                                    descriptor1.name(), pn);
                     }
                 }
 
@@ -763,6 +800,42 @@
     }
 
     /**
+     * Fail because a module in the configuration exports the same package to
+     * a module that reads both. This includes the case where a module M
+     * containing a package p reads another module that exports p to at least
+     * module M.
+     */
+    private void failTwoSuppliers(ModuleDescriptor descriptor,
+                                  String source,
+                                  ModuleDescriptor supplier1,
+                                  ModuleDescriptor supplier2) {
+
+        if (supplier2 == descriptor) {
+            ModuleDescriptor tmp = supplier1;
+            supplier1 = supplier2;
+            supplier2 = tmp;
+        }
+
+        if (supplier1 == descriptor) {
+            resolveFail("Module %s contains package %s"
+                         + ", module %s exports package %s to %s",
+                    descriptor.name(),
+                    source,
+                    supplier2.name(),
+                    source,
+                    descriptor.name());
+        } else {
+            resolveFail("Modules %s and %s export package %s to module %s",
+                    supplier1.name(),
+                    supplier2.name(),
+                    source,
+                    descriptor.name());
+        }
+
+    }
+
+
+    /**
      * Find a module of the given name in the parent configurations
      */
     private ResolvedModule findInParent(String mn) {
@@ -779,24 +852,16 @@
      * Invokes the beforeFinder to find method to find the given module.
      */
     private ModuleReference findWithBeforeFinder(String mn) {
-        try {
-            return beforeFinder.find(mn).orElse(null);
-        } catch (FindException e) {
-            // unwrap
-            throw new ResolutionException(e.getMessage(), e.getCause());
-        }
+
+        return beforeFinder.find(mn).orElse(null);
+
     }
 
     /**
      * Invokes the afterFinder to find method to find the given module.
      */
     private ModuleReference findWithAfterFinder(String mn) {
-        try {
-            return afterFinder.find(mn).orElse(null);
-        } catch (FindException e) {
-            // unwrap
-            throw new ResolutionException(e.getMessage(), e.getCause());
-        }
+        return afterFinder.find(mn).orElse(null);
     }
 
     /**
@@ -804,34 +869,27 @@
      * and after ModuleFinders.
      */
     private Set<ModuleReference> findAll() {
-        try {
+        Set<ModuleReference> beforeModules = beforeFinder.findAll();
+        Set<ModuleReference> afterModules = afterFinder.findAll();
 
-            Set<ModuleReference> beforeModules = beforeFinder.findAll();
-            Set<ModuleReference> afterModules = afterFinder.findAll();
+        if (afterModules.isEmpty())
+            return beforeModules;
 
-            if (afterModules.isEmpty())
-                return beforeModules;
+        if (beforeModules.isEmpty()
+                && parents.size() == 1
+                && parents.get(0) == Configuration.empty())
+            return afterModules;
 
-            if (beforeModules.isEmpty()
-                    && parents.size() == 1
-                    && parents.get(0) == Configuration.empty())
-                return afterModules;
+        Set<ModuleReference> result = new HashSet<>(beforeModules);
+        for (ModuleReference mref : afterModules) {
+            String name = mref.descriptor().name();
+            if (!beforeFinder.find(name).isPresent()
+                    && findInParent(name) == null) {
+                result.add(mref);
+            }
+        }
 
-            Set<ModuleReference> result = new HashSet<>(beforeModules);
-            for (ModuleReference mref : afterModules) {
-                String name = mref.descriptor().name();
-                if (!beforeFinder.find(name).isPresent()
-                        && findInParent(name) == null) {
-                    result.add(mref);
-                }
-            }
-
-            return result;
-
-        } catch (FindException e) {
-            // unwrap
-            throw new ResolutionException(e.getMessage(), e.getCause());
-        }
+        return result;
     }
 
     /**
@@ -843,9 +901,17 @@
     }
 
     /**
+     * Throw FindException with the given format string and arguments
+     */
+    private static void findFail(String fmt, Object ... args) {
+        String msg = String.format(fmt, args);
+        throw new FindException(msg);
+    }
+
+    /**
      * Throw ResolutionException with the given format string and arguments
      */
-    private static void fail(String fmt, Object ... args) {
+    private static void resolveFail(String fmt, Object ... args) {
         String msg = String.format(fmt, args);
         throw new ResolutionException(msg);
     }
--- a/src/java.base/share/classes/java/lang/module/package-info.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/module/package-info.java	Fri Feb 10 09:04:39 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -27,6 +27,112 @@
  * Classes to support module descriptors and creating configurations of modules
  * by means of resolution and service binding.
  *
+ * <h2><a name="resolution">Resolution</a></h2>
+ *
+ * <p> Resolution is the process of computing the transitive closure of a set
+ * of root modules over a set of observable modules by resolving the
+ * dependences expressed by {@link
+ * java.lang.module.ModuleDescriptor.Requires requires} clauses.
+ * The <em>dependence graph</em> is augmented with edges that take account of
+ * implicitly declared dependences ({@code requires transitive}) to create a
+ * <em>readability graph</em>. The result of resolution is a {@link
+ * java.lang.module.Configuration Configuration} that encapsulates the
+ * readability graph. </p>
+ *
+ * <p> As an example, suppose we have the following observable modules: </p>
+ * <pre> {@code
+ *     module m1 { requires m2; }
+ *     module m2 { requires transitive m3; }
+ *     module m3 { }
+ *     module m4 { }
+ * } </pre>
+ *
+ * <p> If the module {@code m1} is resolved then the resulting configuration
+ * contains three modules ({@code m1}, {@code m2}, {@code m3}). The edges in
+ * its readability graph are: </p>
+ * <pre> {@code
+ *     m1 --> m2  (meaning m1 reads m2)
+ *     m1 --> m3
+ *     m2 --> m3
+ * } </pre>
+ *
+ * <p> Resolution is an additive process. When computing the transitive closure
+ * then the dependence relation may include dependences on modules in {@link
+ * java.lang.module.Configuration#parents() parent} configurations. The result
+ * is a <em>relative configuration</em> that is relative to one or more parent
+ * configurations and where the readability graph may have edges from modules
+ * in the configuration to modules in parent configurations. </p>
+ *
+ * <p> As an example, suppose we have the following observable modules: </p>
+ * <pre> {@code
+ *     module m1 { requires m2; requires java.xml; }
+ *     module m2 { }
+ * } </pre>
+ *
+ * <p> If module {@code m1} is resolved with the configuration for the {@link
+ * java.lang.reflect.Layer#boot() boot} layer as the parent then the resulting
+ * configuration contains two modules ({@code m1}, {@code m2}). The edges in
+ * its readability graph are:
+ * <pre> {@code
+ *     m1 --> m2
+ *     m1 --> java.xml
+ * } </pre>
+ * where module {@code java.xml} is in the parent configuration. For
+ * simplicity, this example omits the implicitly declared dependence on the
+ * {@code java.base} module.
+ *
+ * <p> Requires clauses that are "{@code requires static}" express an optional
+ * dependence (except at compile-time). If a module declares that it
+ * "{@code requires static M}" then resolution does not search the observable
+ * modules for "{@code M}". However, if "{@code M}" is resolved (because resolution
+ * resolves a module that requires "{@code M}" without the {@link
+ * java.lang.module.ModuleDescriptor.Requires.Modifier#STATIC static} modifier)
+ * then the readability graph will contain read edges for each module that
+ * "{@code requires static M}". </p>
+ *
+ * <p> {@link java.lang.module.ModuleDescriptor#isAutomatic() Automatic} modules
+ * receive special treatment during resolution. Each automatic module is resolved
+ * so that it reads all other modules in the configuration and all parent
+ * configurations. Each automatic module is also resolved as if it
+ * "{@code requires transitive}" all other automatic modules in the configuration
+ * (and all automatic modules in parent configurations). </p>
+ *
+ * <h2><a name="servicebinding">Service binding</a></h2>
+ *
+ * <p> Service binding is the process of augmenting a graph of resolved modules
+ * from the set of observable modules induced by the service-use dependence
+ * ({@code uses} and {@code provides} clauses). Any module that was not
+ * previously in the graph requires resolution to compute its transitive
+ * closure. Service binding is an iterative process in that adding a module
+ * that satisfies some service-use dependence may introduce new service-use
+ * dependences. </p>
+ *
+ * <p> Suppose we have the following observable modules: </p>
+ * <pre> {@code
+ *     module m1 { exports p; uses p.S; }
+ *     module m2 { requires m1; provides p.S with p2.S2; }
+ *     module m3 { requires m1; requires m4; provides p.S with p3.S3; }
+ *     module m4 { }
+ * } </pre>
+ *
+ * <p> If the module {@code m1} is resolved then the resulting graph of modules
+ * has one module ({@code m1}). If the graph is augmented with modules induced
+ * by the service-use dependence relation then the configuration will contain
+ * four modules ({@code m1}, {@code m2}, {@code m3}, {@code m4}). The edges in
+ * its readability graph are: </p>
+ * <pre> {@code
+ *     m2 --> m1
+ *     m3 --> m1
+ *     m3 --> m4
+ * } </pre>
+ * <p> The edges in the conceptual service-use graph are: </p>
+ * <pre> {@code
+ *     m1 --> m2  (meaning m1 uses a service that is provided by m2)
+ *     m1 --> m3
+ * } </pre>
+ *
+ * <h2>General Exceptions</h2>
+ *
  * <p> Unless otherwise noted, passing a {@code null} argument to a constructor
  * or method of any class or interface in this package will cause a {@link
  * java.lang.NullPointerException NullPointerException} to be thrown. Additionally,
@@ -34,6 +140,7 @@
  * will cause a {@code NullPointerException}, unless otherwise specified. </p>
  *
  * @since 9
+ * @spec JPMS
  */
 
 package java.lang.module;
--- a/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java	Fri Feb 10 09:04:39 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, 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
@@ -28,38 +28,44 @@
 import java.lang.annotation.Annotation;
 import java.security.AccessController;
 
-import jdk.internal.misc.VM;
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.Reflection;
 import jdk.internal.reflect.ReflectionFactory;
-import sun.security.action.GetPropertyAction;
 
 /**
- * The AccessibleObject class is the base class for Field, Method and
- * Constructor objects.  It provides the ability to flag a reflected
- * object as suppressing default Java language access control checks
- * when it is used. The access checks -- <em>module boundaries</em>,
- * public, default (package) access, protected, and private members --
- * are performed when Fields, Methods or Constructors are used to set
- * or get fields, to invoke methods or to create and initialize new
- * instances of classes, respectively. Unlike access control specified
- * in the <cite>The Java&trade; Language Specification</cite> and
- * <cite>The Java Virtual Machine Specification</cite>, access checks
- * with reflected objects assume {@link Module#canRead readability}.
+ * The {@code AccessibleObject} class is the base class for {@code Field},
+ * {@code Method}, and {@code Constructor} objects (known as <em>reflected
+ * objects</em>). It provides the ability to flag a reflected object as
+ * suppressing checks for Java language access control when it is used. This
+ * permits sophisticated applications with sufficient privilege, such as Java
+ * Object Serialization or other persistence mechanisms, to manipulate objects
+ * in a manner that would normally be prohibited.
  *
- * <p>Setting the {@code accessible} flag in a reflected object
- * permits sophisticated applications with sufficient privilege, such
- * as Java Object Serialization or other persistence mechanisms, to
- * manipulate objects in a manner that would normally be prohibited.
+ * <p> Java language access control prevents use of private members outside
+ * their class; package access members outside their package; protected members
+ * outside their package or subclasses; and public members outside their
+ * module unless they are declared in an {@link Module#isExported(String,Module)
+ * exported} package and the user {@link Module#canRead reads} their module. By
+ * default, Java language access control is enforced (with one variation) when
+ * {@code Field}s, {@code Method}s, or {@code Constructor}s are used to get or
+ * set fields, to invoke methods, or to create and initialize new instances of
+ * classes, respectively. Every reflected object checks that the code using it
+ * is in an appropriate class, package, or module. </p>
  *
- * <p>By default, a reflected object is <em>not</em> accessible.
+ * <p> The one variation from Java language access control is that the checks
+ * by reflected objects assume readability. That is, the module containing
+ * the use of a reflected object is assumed to read the module in which
+ * the underlying field, method, or constructor is declared. </p>
  *
- * @see Field
- * @see Method
- * @see Constructor
- * @see ReflectPermission
+ * <p> Whether the checks for Java language access control can be suppressed
+ * (and thus, whether access can be enabled) depends on whether the reflected
+ * object corresponds to a member in an exported or open package
+ * (see {@link #setAccessible(boolean)}). </p>
  *
+ * @jls 6.6 Access Control
  * @since 1.2
+ * @revised 9
+ * @spec JPMS
  */
 public class AccessibleObject implements AnnotatedElement {
 
@@ -78,15 +84,11 @@
 
     /**
      * Convenience method to set the {@code accessible} flag for an
-     * array of objects with a single security check (for efficiency).
+     * array of reflected objects with a single security check (for efficiency).
      *
-     * <p>This method cannot be used to enable access to an object that is a
-     * {@link Member member} of a class in a different module to the caller and
-     * where the class is in a package that is not exported to the caller's
-     * module. Additionally, if the member is non-public or its declaring
-     * class is non-public, then this method can only be used to enable access
-     * if the package is {@link Module#isOpen(String,Module) open} to at least
-     * the caller's module.
+     * <p> This method may be used to enable access to all reflected objects in
+     * the array when access to each reflected object can be enabled as
+     * specified by {@link #setAccessible(boolean) setAccessible(boolean)}. </p>
      *
      * <p>If there is a security manager, its
      * {@code checkPermission} method is first called with a
@@ -99,10 +101,15 @@
      * @param array the array of AccessibleObjects
      * @param flag  the new value for the {@code accessible} flag
      *              in each object
-     * @throws InaccessibleObjectException if access cannot be enabled
-     * @throws SecurityException if the request is denied.
+     * @throws InaccessibleObjectException if access cannot be enabled for all
+     *         objects in the array
+     * @throws SecurityException if the request is denied by the security manager
+     *         or an element in the array is a constructor for {@code
+     *         java.lang.Class}
      * @see SecurityManager#checkPermission
      * @see ReflectPermission
+     * @revised 9
+     * @spec JPMS
      */
     @CallerSensitive
     public static void setAccessible(AccessibleObject[] array, boolean flag) {
@@ -120,41 +127,143 @@
     }
 
     /**
-     * Set the {@code accessible} flag for this object to
+     * Set the {@code accessible} flag for this reflected object to
      * the indicated boolean value.  A value of {@code true} indicates that
-     * the reflected object should suppress Java language access
-     * checking when it is used.  A value of {@code false} indicates
-     * that the reflected object should enforce Java language access checks
-     * while assuming readability (as noted in the class description).
+     * the reflected object should suppress checks for Java language access
+     * control when it is used. A value of {@code false} indicates that
+     * the reflected object should enforce checks for Java language access
+     * control when it is used, with the variation noted in the class description.
      *
-     * <p>This method cannot be used to enable access to an object that is a
-     * {@link Member member} of a class in a different module to the caller and
-     * where the class is in a package that is not exported to the caller's
-     * module. Additionally, if the member is non-public or its declaring
-     * class is non-public, then this method can only be used to enable access
-     * if the package is {@link Module#isOpen(String,Module) open} to at least
-     * the caller's module.
+     * <p> This method may be used by a caller in class {@code C} to enable
+     * access to a {@link Member member} of {@link Member#getDeclaringClass()
+     * declaring class} {@code D} if any of the following hold: </p>
      *
-     * <p>If there is a security manager, its
+     * <ul>
+     *     <li> {@code C} and {@code D} are in the same module. </li>
+     *
+     *     <li> The member is {@code public} and {@code D} is {@code public} in
+     *     a package that the module containing {@code D} {@link
+     *     Module#isExported(String,Module) exports} to at least the module
+     *     containing {@code C}. </li>
+     *
+     *     <li> The member is {@code protected} {@code static}, {@code D} is
+     *     {@code public} in a package that the module containing {@code D}
+     *     exports to at least the module containing {@code C}, and {@code C}
+     *     is a subclass of {@code D}. </li>
+     *
+     *     <li> {@code D} is in a package that the module containing {@code D}
+     *     {@link Module#isOpen(String,Module) opens} to at least the module
+     *     containing {@code C}.
+     *     All packages in unnamed and open modules are open to all modules and
+     *     so this method always succeeds when {@code D} is in an unnamed or
+     *     open module. </li>
+     * </ul>
+     *
+     * <p> This method cannot be used to enable access to private members,
+     * members with default (package) access, protected instance members, or
+     * protected constructors when the declaring class is in a different module
+     * to the caller and the package containing the declaring class is not open
+     * to the caller's module. </p>
+     *
+     * <p> If there is a security manager, its
      * {@code checkPermission} method is first called with a
      * {@code ReflectPermission("suppressAccessChecks")} permission.
      *
      * @param flag the new value for the {@code accessible} flag
      * @throws InaccessibleObjectException if access cannot be enabled
-     * @throws SecurityException if the request is denied
-     * @see SecurityManager#checkPermission
-     * @see ReflectPermission
+     * @throws SecurityException if the request is denied by the security manager
+     * @see #trySetAccessible
      * @see java.lang.invoke.MethodHandles#privateLookupIn
+     * @revised 9
+     * @spec JPMS
      */
     public void setAccessible(boolean flag) {
         AccessibleObject.checkPermission();
         setAccessible0(flag);
     }
 
-    void setAccessible0(boolean flag) {
+    /**
+     * Sets the accessible flag and returns the new value
+     */
+    boolean setAccessible0(boolean flag) {
         this.override = flag;
+        return flag;
     }
 
+    /**
+     * Set the {@code accessible} flag for this reflected object to {@code true}
+     * if possible. This method sets the {@code accessible} flag, as if by
+     * invoking {@link #setAccessible(boolean) setAccessible(true)}, and returns
+     * the possibly-updated value for the {@code accessible} flag. If access
+     * cannot be enabled, i.e. the checks or Java language access control cannot
+     * be suppressed, this method returns {@code false} (as opposed to {@code
+     * setAccessible(true)} throwing {@code InaccessibleObjectException} when
+     * it fails).
+     *
+     * <p> This method is a no-op if the {@code accessible} flag for
+     * this reflected object is {@code true}.
+     *
+     * <p> For example, a caller can invoke {@code trySetAccessible}
+     * on a {@code Method} object for a private instance method
+     * {@code p.T::privateMethod} to suppress the checks for Java language access
+     * control when the {@code Method} is invoked.
+     * If {@code p.T} class is in a different module to the caller and
+     * package {@code p} is open to at least the caller's module,
+     * the code below successfully sets the {@code accessible} flag
+     * to {@code true}.
+     *
+     * <pre>
+     * {@code
+     *     p.T obj = ....;  // instance of p.T
+     *     :
+     *     Method m = p.T.class.getDeclaredMethod("privateMethod");
+     *     if (m.trySetAccessible()) {
+     *         m.invoke(obj);
+     *     } else {
+     *         // package p is not opened to the caller to access private member of T
+     *         ...
+     *     }
+     * }</pre>
+     *
+     * <p> If there is a security manager, its {@code checkPermission} method
+     * is first called with a {@code ReflectPermission("suppressAccessChecks")}
+     * permission. </p>
+     *
+     * @return {@code true} if the {@code accessible} flag is set to {@code true};
+     *         {@code false} if access cannot be enabled.
+     * @throws SecurityException if the request is denied by the security manager
+     *
+     * @since 9
+     * @spec JPMS
+     * @see java.lang.invoke.MethodHandles#privateLookupIn
+     */
+    @CallerSensitive
+    public final boolean trySetAccessible() {
+        AccessibleObject.checkPermission();
+
+        if (override == true) return true;
+
+        // if it's not a Constructor, Method, Field then no access check
+        if (!Member.class.isInstance(this)) {
+            return setAccessible0(true);
+        }
+
+        // does not allow to suppress access check for Class's constructor
+        Class<?> declaringClass = ((Member) this).getDeclaringClass();
+        if (declaringClass == Class.class && this instanceof Constructor) {
+            return false;
+        }
+
+        if (checkCanSetAccessible(Reflection.getCallerClass(),
+                                  declaringClass,
+                                  false)) {
+            return setAccessible0(true);
+        } else {
+            return false;
+        }
+    }
+
+
    /**
     * If the given AccessibleObject is a {@code Constructor}, {@code Method}
     * or {@code Field} then checks that its declaring class is in a package
@@ -164,22 +273,29 @@
         // do nothing, needs to be overridden by Constructor, Method, Field
     }
 
+
     void checkCanSetAccessible(Class<?> caller, Class<?> declaringClass) {
+        checkCanSetAccessible(caller, declaringClass, true);
+    }
+
+    private boolean checkCanSetAccessible(Class<?> caller,
+                                          Class<?> declaringClass,
+                                          boolean throwExceptionIfDenied) {
         Module callerModule = caller.getModule();
         Module declaringModule = declaringClass.getModule();
 
-        if (callerModule == declaringModule) return;
-        if (callerModule == Object.class.getModule()) return;
-        if (!declaringModule.isNamed()) return;
+        if (callerModule == declaringModule) return true;
+        if (callerModule == Object.class.getModule()) return true;
+        if (!declaringModule.isNamed()) return true;
 
         // package is open to caller
         String pn = packageName(declaringClass);
         if (declaringModule.isOpen(pn, callerModule)) {
-            printStackTraceIfOpenedReflectively(declaringModule, pn, callerModule);
-            return;
+            dumpStackIfOpenedReflectively(declaringModule, pn, callerModule);
+            return true;
         }
 
-        // package is exported to caller and class/member is public
+        // package is exported to caller
         boolean isExported = declaringModule.isExported(pn, callerModule);
         boolean isClassPublic = Modifier.isPublic(declaringClass.getModifiers());
         int modifiers;
@@ -188,48 +304,72 @@
         } else {
             modifiers = ((Field) this).getModifiers();
         }
-        boolean isMemberPublic = Modifier.isPublic(modifiers);
-        if (isExported && isClassPublic && isMemberPublic) {
-            printStackTraceIfExportedReflectively(declaringModule, pn, callerModule);
-            return;
+        if (isExported && isClassPublic) {
+
+            // member is public
+            if (Modifier.isPublic(modifiers)) {
+                dumpStackIfExportedReflectively(declaringModule, pn, callerModule);
+                return true;
+            }
+
+            // member is protected-static
+            if (Modifier.isProtected(modifiers)
+                && Modifier.isStatic(modifiers)
+                && isSubclassOf(caller, declaringClass)) {
+                dumpStackIfExportedReflectively(declaringModule, pn, callerModule);
+                return true;
+            }
         }
 
-        // not accessible
-        String msg = "Unable to make ";
-        if (this instanceof Field)
-            msg += "field ";
-        msg += this + " accessible: " + declaringModule + " does not \"";
-        if (isClassPublic && isMemberPublic)
-            msg += "exports";
-        else
-            msg += "opens";
-        msg += " " + pn + "\" to " + callerModule;
-        InaccessibleObjectException e = new InaccessibleObjectException(msg);
-        if (Reflection.printStackTraceWhenAccessFails()) {
-            e.printStackTrace(System.err);
+        if (throwExceptionIfDenied) {
+            // not accessible
+            String msg = "Unable to make ";
+            if (this instanceof Field)
+                msg += "field ";
+            msg += this + " accessible: " + declaringModule + " does not \"";
+            if (isClassPublic && Modifier.isPublic(modifiers))
+                msg += "exports";
+            else
+                msg += "opens";
+            msg += " " + pn + "\" to " + callerModule;
+            InaccessibleObjectException e = new InaccessibleObjectException(msg);
+            if (Reflection.printStackTraceWhenAccessFails()) {
+                e.printStackTrace(System.err);
+            }
+            throw e;
         }
-        throw e;
+        return false;
     }
 
-    private void printStackTraceIfOpenedReflectively(Module module,
-                                                     String pn,
-                                                     Module other) {
-        printStackTraceIfExposedReflectively(module, pn, other, true);
+    private boolean isSubclassOf(Class<?> queryClass, Class<?> ofClass) {
+        while (queryClass != null) {
+            if (queryClass == ofClass) {
+                return true;
+            }
+            queryClass = queryClass.getSuperclass();
+        }
+        return false;
     }
 
-    private void printStackTraceIfExportedReflectively(Module module,
-                                                       String pn,
-                                                       Module other) {
-        printStackTraceIfExposedReflectively(module, pn, other, false);
+    private void dumpStackIfOpenedReflectively(Module module,
+                                               String pn,
+                                               Module other) {
+        dumpStackIfExposedReflectively(module, pn, other, true);
     }
 
-    private void printStackTraceIfExposedReflectively(Module module,
-                                                      String pn,
-                                                      Module other,
-                                                      boolean open)
+    private void dumpStackIfExportedReflectively(Module module,
+                                                 String pn,
+                                                 Module other) {
+        dumpStackIfExposedReflectively(module, pn, other, false);
+    }
+
+    private void dumpStackIfExposedReflectively(Module module,
+                                                String pn,
+                                                Module other,
+                                                boolean open)
     {
         if (Reflection.printStackTraceWhenAccessSucceeds()
-            && !module.isStaticallyExportedOrOpen(pn, other, open))
+                && !module.isStaticallyExportedOrOpen(pn, other, open))
         {
             String msg = other + " allowed to invoke setAccessible on ";
             if (this instanceof Field)
@@ -256,15 +396,100 @@
     }
 
     /**
-     * Get the value of the {@code accessible} flag for this object.
+     * Get the value of the {@code accessible} flag for this reflected object.
      *
      * @return the value of the object's {@code accessible} flag
+     *
+     * @deprecated
+     * This method is deprecated because its name hints that it checks
+     * if the reflected object is accessible when it actually indicates
+     * if the checks for Java language access control are suppressed.
+     * This method may return {@code false} on a reflected object that is
+     * accessible to the caller. To test if this reflected object is accessible,
+     * it should use {@link #canAccess(Object)}.
+     *
+     * @revised 9
      */
+    @Deprecated(since="9")
     public boolean isAccessible() {
         return override;
     }
 
     /**
+     * Test if the caller can access this reflected object. If this reflected
+     * object corresponds to an instance method or field then this method tests
+     * if the caller can access the given {@code obj} with the reflected object.
+     * For instance methods or fields then the {@code obj} argument must be an
+     * instance of the {@link Member#getDeclaringClass() declaring class}. For
+     * static members and constructors then {@code obj} must be {@code null}.
+     *
+     * <p> This method returns {@code true} if the {@code accessible} flag
+     * is set to {@code true}, i.e. the checks for Java language access control
+     * are suppressed, or if the caller can access the member as
+     * specified in <cite>The Java&trade; Language Specification</cite>,
+     * with the variation noted in the class description. </p>
+     *
+     * @param obj an instance object of the declaring class of this reflected
+     *            object if it is an instance method or field
+     *
+     * @return {@code true} if the caller can access this reflected object.
+     *
+     * @throws IllegalArgumentException
+     *         <ul>
+     *         <li> if this reflected object is a static member or constructor and
+     *              the given {@code obj} is non-{@code null}, or </li>
+     *         <li> if this reflected object is an instance method or field
+     *              and the given {@code obj} is {@code null} or of type
+     *              that is not a subclass of the {@link Member#getDeclaringClass()
+     *              declaring class} of the member.</li>
+     *         </ul>
+     *
+     * @since 9
+     * @spec JPMS
+     * @jls 6.6 Access Control
+     * @see #trySetAccessible
+     * @see #setAccessible(boolean)
+     */
+    @CallerSensitive
+    public final boolean canAccess(Object obj) {
+        if (!Member.class.isInstance(this)) {
+            return override;
+        }
+
+        Class<?> declaringClass = ((Member) this).getDeclaringClass();
+        int modifiers = ((Member) this).getModifiers();
+        if (!Modifier.isStatic(modifiers) &&
+                (this instanceof Method || this instanceof Field)) {
+            if (obj == null) {
+                throw new IllegalArgumentException("null object for " + this);
+            }
+            // if this object is an instance member, the given object
+            // must be a subclass of the declaring class of this reflected object
+            if (!declaringClass.isAssignableFrom(obj.getClass())) {
+                throw new IllegalArgumentException("object is not an instance of "
+                                                   + declaringClass.getName());
+            }
+        } else if (obj != null) {
+            throw new IllegalArgumentException("non-null object for " + this);
+        }
+
+        // access check is suppressed
+        if (override) return true;
+
+        Class<?> caller = Reflection.getCallerClass();
+        Class<?> targetClass;
+        if (this instanceof Constructor) {
+            targetClass = declaringClass;
+        } else {
+            targetClass = Modifier.isStatic(modifiers) ? null : obj.getClass();
+        }
+        return Reflection.verifyMemberAccess(caller,
+                                             declaringClass,
+                                             targetClass,
+                                             modifiers);
+    }
+
+    /**
      * Constructor: only used by the Java Virtual Machine.
      */
     protected AccessibleObject() {}
--- a/src/java.base/share/classes/java/lang/reflect/Constructor.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/reflect/Constructor.java	Fri Feb 10 09:04:39 2017 +0000
@@ -168,6 +168,13 @@
      * is true. </p>
      *
      * @param flag {@inheritDoc}
+     *
+     * @throws InaccessibleObjectException {@inheritDoc}
+     * @throws SecurityException if the request is denied by the security manager
+     *         or this is a constructor for {@code java.lang.Class}
+     *
+     * @since 9
+     * @spec JPMS
      */
     @Override
     @CallerSensitive
--- a/src/java.base/share/classes/java/lang/reflect/Field.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/reflect/Field.java	Fri Feb 10 09:04:39 2017 +0000
@@ -158,6 +158,10 @@
         return res;
     }
 
+    /**
+     * @throws InaccessibleObjectException {@inheritDoc}
+     * @throws SecurityException {@inheritDoc}
+     */
     @Override
     @CallerSensitive
     public void setAccessible(boolean flag) {
--- a/src/java.base/share/classes/java/lang/reflect/InaccessibleObjectException.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/reflect/InaccessibleObjectException.java	Fri Feb 10 09:04:39 2017 +0000
@@ -30,6 +30,7 @@
  *
  * @see AccessibleObject#setAccessible(boolean)
  * @since 9
+ * @spec JPMS
  */
 
 public class InaccessibleObjectException extends RuntimeException {
--- a/src/java.base/share/classes/java/lang/reflect/Layer.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/reflect/Layer.java	Fri Feb 10 09:04:39 2017 +0000
@@ -56,20 +56,19 @@
 /**
  * A layer of modules in the Java virtual machine.
  *
- * <p> A layer is created from a graph of modules that is the {@link
- * Configuration} and a function that maps each module to a {@link ClassLoader}.
+ * <p> A layer is created from a graph of modules in a {@link Configuration}
+ * and a function that maps each module to a {@link ClassLoader}.
  * Creating a layer informs the Java virtual machine about the classes that
- * may be loaded from modules so that the Java virtual machine knows which
- * module that each class is a member of. Each layer, except the {@link
- * #empty() empty} layer, has at least one {@link #parents() parent}. </p>
+ * may be loaded from the modules so that the Java virtual machine knows which
+ * module that each class is a member of. </p>
  *
  * <p> Creating a layer creates a {@link Module} object for each {@link
  * ResolvedModule} in the configuration. For each resolved module that is
  * {@link ResolvedModule#reads() read}, the {@code Module} {@link
  * Module#canRead reads} the corresponding run-time {@code Module}, which may
- * be in the same layer or a parent layer. The {@code Module} {@link
- * Module#isExported(String) exports} the packages described by its {@link
- * ModuleDescriptor}. </p>
+ * be in the same layer or a {@link #parents() parent} layer. The {@code Module}
+ * {@link Module#isExported(String) exports} and {@link Module#isOpen(String)
+ * opens} the packages described by its {@link ModuleDescriptor}. </p>
  *
  * <p> The {@link #defineModulesWithOneLoader defineModulesWithOneLoader} and
  * {@link #defineModulesWithManyLoaders defineModulesWithManyLoaders} methods
@@ -80,7 +79,7 @@
  * a function specified to the method. Each of these methods has an instance
  * and static variant. The instance methods create a layer with the receiver
  * as the parent layer. The static methods are for more advanced cases where
- * there can be more than one parent layer or a {@link Layer.Controller
+ * there can be more than one parent layer or where a {@link Layer.Controller
  * Controller} is needed to control modules in the layer. </p>
  *
  * <p> A Java virtual machine has at least one non-empty layer, the {@link
@@ -93,9 +92,8 @@
  * the {@link #parents() parent} when creating additional layers. </p>
  *
  * <p> As when creating a {@code Configuration},
- * {@link ModuleDescriptor#isAutomatic() automatic} modules receive
- * <a href="../module/Configuration.html#automaticmoduleresolution">special
- * treatment</a> when creating a layer. An automatic module is created in the
+ * {@link ModuleDescriptor#isAutomatic() automatic} modules receive special
+ * treatment when creating a layer. An automatic module is created in the
  * Java virtual machine as a {@code Module} that reads every unnamed {@code
  * Module} in the Java virtual machine. </p>
  *
@@ -115,8 +113,7 @@
  *
  *     Layer parent = Layer.boot();
  *
- *     Configuration cf = parent.configuration()
- *         .resolveRequires(finder, ModuleFinder.of(), Set.of("myapp"));
+ *     Configuration cf = parent.configuration().resolve(finder, ModuleFinder.of(), Set.of("myapp"));
  *
  *     ClassLoader scl = ClassLoader.getSystemClassLoader();
  *
@@ -126,6 +123,7 @@
  * }</pre>
  *
  * @since 9
+ * @spec JPMS
  * @see Module#getLayer()
  */
 
@@ -168,10 +166,15 @@
      * module layers return a {@code Controller} that can be used to control
      * modules in the layer.
      *
+     * <p> Unless otherwise specified, passing a {@code null} argument to a
+     * method in this class causes a {@link NullPointerException
+     * NullPointerException} to be thrown. </p>
+     *
      * @apiNote Care should be taken with {@code Controller} objects, they
      * should never be shared with untrusted code.
      *
      * @since 9
+     * @spec JPMS
      */
     public static final class Controller {
         private final Layer layer;
@@ -281,10 +284,8 @@
      *         If the parent of the given configuration is not the configuration
      *         for this layer
      * @throws LayerInstantiationException
-     *         If all modules cannot be defined to the same class loader for any
-     *         of the reasons listed above or the layer cannot be created because
-     *         the configuration contains a module named "{@code java.base}" or
-     *         a module with a package name starting with "{@code java.}"
+     *         If the layer cannot be created for any of the reasons specified
+     *         by the static {@code defineModulesWithOneLoader} method
      * @throws SecurityException
      *         If {@code RuntimePermission("createClassLoader")} or
      *         {@code RuntimePermission("getClassLoader")} is denied by
@@ -325,9 +326,8 @@
      *         If the parent of the given configuration is not the configuration
      *         for this layer
      * @throws LayerInstantiationException
-     *         If the layer cannot be created because the configuration contains
-     *         a module named "{@code java.base}" or a module with a package
-     *         name starting with "{@code java.}"
+     *         If the layer cannot be created for any of the reasons specified
+     *         by the static {@code defineModulesWithManyLoaders} method
      * @throws SecurityException
      *         If {@code RuntimePermission("createClassLoader")} or
      *         {@code RuntimePermission("getClassLoader")} is denied by
@@ -365,14 +365,8 @@
      *         If the parent of the given configuration is not the configuration
      *         for this layer
      * @throws LayerInstantiationException
-     *         If creating the {@code Layer} fails for any of the reasons
-     *         listed above, the layer cannot be created because the
-     *         configuration contains a module named "{@code java.base}",
-     *         a module with a package name starting with "{@code java.}" is
-     *         mapped to a class loader other than the {@link
-     *         ClassLoader#getPlatformClassLoader() platform class loader},
-     *         or the function to map a module name to a class loader returns
-     *         {@code null}
+     *         If the layer cannot be created for any of the reasons specified
+     *         by the static {@code defineModules} method
      * @throws SecurityException
      *         If {@code RuntimePermission("getClassLoader")} is denied by
      *         the security manager
@@ -396,7 +390,6 @@
      * exported to one or more of the modules in this layer. The class
      * loader delegates to the class loader of the module, throwing {@code
      * ClassNotFoundException} if not found by that class loader.
-     *
      * When {@code loadClass} is invoked to load classes that do not map to a
      * module then it delegates to the parent class loader. </p>
      *
@@ -414,6 +407,10 @@
      *
      * </ul>
      *
+     * <p> In addition, a layer cannot be created if the configuration contains
+     * a module named "{@code java.base}" or a module with a package name
+     * starting with "{@code java.}". </p>
+     *
      * <p> If there is a security manager then the class loader created by
      * this method will load classes and resources with privileges that are
      * restricted by the calling context of this method. </p>
@@ -433,9 +430,7 @@
      *         the parent layers, including order
      * @throws LayerInstantiationException
      *         If all modules cannot be defined to the same class loader for any
-     *         of the reasons listed above or the layer cannot be created because
-     *         the configuration contains a module named "{@code java.base}" or
-     *         a module with a package name starting with "{@code java.}"
+     *         of the reasons listed above
      * @throws SecurityException
      *         If {@code RuntimePermission("createClassLoader")} or
      *         {@code RuntimePermission("getClassLoader")} is denied by
@@ -480,7 +475,6 @@
      * module in a parent layer. The class loader delegates to the class loader
      * of the module, throwing {@code ClassNotFoundException} if not found by
      * that class loader.
-     *
      * When {@code loadClass} is invoked to load classes that do not map to a
      * module then it delegates to the parent class loader. </p>
      *
@@ -533,15 +527,19 @@
 
     /**
      * Creates a new layer by defining the modules in the given {@code
-     * Configuration} to the Java virtual machine.
-     * Each module is mapped, by name, to its class loader by means of the
-     * given function. The class loader delegation implemented by these class
-     * loaders must respect module readability. The class loaders should be
+     * Configuration} to the Java virtual machine. The given function maps each
+     * module in the configuration, by name, to a class loader. Creating the
+     * layer informs the Java virtual machine about the classes that may be
+     * loaded so that the Java virtual machine knows which module that each
+     * class is a member of.
+     *
+     * <p> The class loader delegation implemented by the class loaders must
+     * respect module readability. The class loaders should be
      * {@link ClassLoader#registerAsParallelCapable parallel-capable} so as to
      * avoid deadlocks during class loading. In addition, the entity creating
-     * a new layer with this method should arrange that the class loaders are
+     * a new layer with this method should arrange that the class loaders be
      * ready to load from these modules before there are any attempts to load
-     * classes or resources.
+     * classes or resources. </p>
      *
      * <p> Creating a {@code Layer} can fail for the following reasons: </p>
      *
@@ -558,6 +556,13 @@
      *
      * </ul>
      *
+     * <p> In addition, a layer cannot be created if the configuration contains
+     * a module named "{@code java.base}", a configuration contains a module
+     * with a package name starting with "{@code java.}" is mapped to a class
+     * loader other than the {@link ClassLoader#getPlatformClassLoader()
+     * platform class loader}, or the function to map a module name to a class
+     * loader returns {@code null}. </p>
+     *
      * <p> If the function to map a module name to class loader throws an error
      * or runtime exception then it is propagated to the caller of this method.
      * </p>
@@ -565,7 +570,7 @@
      * @apiNote It is implementation specific as to whether creating a Layer
      * with this method is an atomic operation or not. Consequentially it is
      * possible for this method to fail with some modules, but not all, defined
-     * to Java virtual machine.
+     * to the Java virtual machine.
      *
      * @param  cf
      *         The configuration for the layer
@@ -580,14 +585,7 @@
      *         If the parent configurations do not match the configuration of
      *         the parent layers, including order
      * @throws LayerInstantiationException
-     *         If creating the {@code Layer} fails for any of the reasons
-     *         listed above, the layer cannot be created because the
-     *         configuration contains a module named "{@code java.base}",
-     *         a module with a package name starting with "{@code java.}" is
-     *         mapped to a class loader other than the {@link
-     *         ClassLoader#getPlatformClassLoader() platform class loader},
-     *         or the function to map a module name to a class loader returns
-     *         {@code null}
+     *         If creating the layer fails for any of the reasons listed above
      * @throws SecurityException
      *         If {@code RuntimePermission("getClassLoader")} is denied by
      *         the security manager
@@ -763,7 +761,7 @@
 
     /**
      * Returns the module with the given name in this layer, or if not in this
-     * layer, the {@linkplain #parents parents} layers. Finding a module in
+     * layer, the {@linkplain #parents parent} layers. Finding a module in
      * parent layers is equivalent to invoking {@code findModule} on each
      * parent, in search order, until the module is found or all parents have
      * been searched. In a <em>tree of layers</em>  then this is equivalent to
--- a/src/java.base/share/classes/java/lang/reflect/LayerInstantiationException.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/reflect/LayerInstantiationException.java	Fri Feb 10 09:04:39 2017 +0000
@@ -31,6 +31,7 @@
  * @see Layer
  *
  * @since 9
+ * @spec JPMS
  */
 public class LayerInstantiationException extends RuntimeException {
     private static final long serialVersionUID = -906239691613568347L;
--- a/src/java.base/share/classes/java/lang/reflect/Method.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/reflect/Method.java	Fri Feb 10 09:04:39 2017 +0000
@@ -179,6 +179,10 @@
         return res;
     }
 
+    /**
+     * @throws InaccessibleObjectException {@inheritDoc}
+     * @throws SecurityException {@inheritDoc}
+     */
     @Override
     @CallerSensitive
     public void setAccessible(boolean flag) {
--- a/src/java.base/share/classes/java/lang/reflect/Module.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/reflect/Module.java	Fri Feb 10 09:04:39 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, 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
@@ -39,7 +39,6 @@
 import java.net.URL;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -74,16 +73,15 @@
  * Java Virtual Machine when a graph of modules is defined to the Java virtual
  * machine to create a module {@link Layer Layer}. </p>
  *
- * <p> An unnamed module does not have a name. There is an unnamed module
- * per {@link ClassLoader ClassLoader} that is obtained by invoking the class
- * loader's {@link ClassLoader#getUnnamedModule() getUnnamedModule} method. The
- * {@link Class#getModule() getModule} method of all types defined by a class
- * loader that are not in a named module return the class loader's unnamed
+ * <p> An unnamed module does not have a name. There is an unnamed module for
+ * each {@link ClassLoader ClassLoader}, obtained by invoking its {@link
+ * ClassLoader#getUnnamedModule() getUnnamedModule} method. All types that are
+ * not in a named module are members of their defining class loader's unnamed
  * module. </p>
  *
  * <p> The package names that are parameters or returned by methods defined in
  * this class are the fully-qualified names of the packages as defined in
- * section 6.5.3 of <cite>The Java&trade; Language Specification </cite>, for
+ * section 6.5.3 of <cite>The Java&trade; Language Specification</cite>, for
  * example, {@code "java.lang"}. </p>
  *
  * <p> Unless otherwise specified, passing a {@code null} argument to a method
@@ -91,6 +89,7 @@
  * be thrown. </p>
  *
  * @since 9
+ * @spec JPMS
  * @see java.lang.Class#getModule
  */
 
@@ -327,8 +326,9 @@
      *
      * @return this module
      *
-     * @throws IllegalStateException
-     *         If this is a named module and the caller is not this module
+     * @throws IllegalCallerException
+     *         If this is a named module and the caller's module is not this
+     *         module
      *
      * @see #canRead
      */
@@ -338,7 +338,7 @@
         if (this.isNamed()) {
             Module caller = Reflection.getCallerClass().getModule();
             if (caller != this) {
-                throw new IllegalStateException(caller + " != " + this);
+                throw new IllegalCallerException(caller + " != " + this);
             }
             implAddReads(other, true);
         }
@@ -533,8 +533,8 @@
         if (other == this && containsPackage(pn))
             return true;
 
-        // all packages in open modules are open
-        if (descriptor.isOpen())
+        // all packages in open and automatic modules are open
+        if (descriptor.isOpen() || descriptor.isAutomatic())
             return containsPackage(pn);
 
         // exported/opened via module declaration/descriptor
@@ -634,8 +634,7 @@
      * the given package to the given module.
      *
      * <p> This method has no effect if the package is already exported (or
-     * <em>open</em>) to the given module. It also has no effect if
-     * invoked on an {@link ModuleDescriptor#isOpen open} module. </p>
+     * <em>open</em>) to the given module. </p>
      *
      * @apiNote As specified in section 5.4.3 of the <cite>The Java&trade;
      * Virtual Machine Specification </cite>, if an attempt to resolve a
@@ -653,8 +652,9 @@
      * @throws IllegalArgumentException
      *         If {@code pn} is {@code null}, or this is a named module and the
      *         package {@code pn} is not a package in this module
-     * @throws IllegalStateException
-     *         If this is a named module and the caller is not this module
+     * @throws IllegalCallerException
+     *         If this is a named module and the caller's module is not this
+     *         module
      *
      * @jvms 5.4.3 Resolution
      * @see #isExported(String,Module)
@@ -665,10 +665,10 @@
             throw new IllegalArgumentException("package is null");
         Objects.requireNonNull(other);
 
-        if (isNamed() && !descriptor.isOpen()) {
+        if (isNamed()) {
             Module caller = Reflection.getCallerClass().getModule();
             if (caller != this) {
-                throw new IllegalStateException(caller + " != " + this);
+                throw new IllegalCallerException(caller + " != " + this);
             }
             implAddExportsOrOpens(pn, other, /*open*/false, /*syncVM*/true);
         }
@@ -686,8 +686,7 @@
      * access control checks.
      *
      * <p> This method has no effect if the package is already <em>open</em>
-     * to the given module. It also has no effect if invoked on an {@link
-     * ModuleDescriptor#isOpen open} module. </p>
+     * to the given module. </p>
      *
      * @param  pn
      *         The package name
@@ -699,9 +698,9 @@
      * @throws IllegalArgumentException
      *         If {@code pn} is {@code null}, or this is a named module and the
      *         package {@code pn} is not a package in this module
-     * @throws IllegalStateException
+     * @throws IllegalCallerException
      *         If this is a named module and this module has not opened the
-     *         package to at least the caller
+     *         package to at least the caller's module
      *
      * @see #isOpen(String,Module)
      * @see AccessibleObject#setAccessible(boolean)
@@ -713,10 +712,10 @@
             throw new IllegalArgumentException("package is null");
         Objects.requireNonNull(other);
 
-        if (isNamed() && !descriptor.isOpen()) {
+        if (isNamed()) {
             Module caller = Reflection.getCallerClass().getModule();
             if (caller != this && !isOpen(pn, caller))
-                throw new IllegalStateException(pn + " is not open to " + caller);
+                throw new IllegalCallerException(pn + " is not open to " + caller);
             implAddExportsOrOpens(pn, other, /*open*/true, /*syncVM*/true);
         }
 
@@ -767,8 +766,8 @@
         Objects.requireNonNull(other);
         Objects.requireNonNull(pn);
 
-        // all packages are open in unnamed and open modules
-        if (!isNamed() || descriptor.isOpen())
+        // all packages are open in unnamed, open, and automatic modules
+        if (!isNamed() || descriptor.isOpen() || descriptor.isAutomatic())
             return;
 
         // nothing to do if already exported/open to other
@@ -819,17 +818,17 @@
      * passed a reference to the service type by other code. This method is
      * a no-op when invoked on an unnamed module or an automatic module.
      *
-     * <p> This method does not cause {@link
-     * Configuration#resolveRequiresAndUses resolveRequiresAndUses} to be
-     * re-run. </p>
+     * <p> This method does not cause {@link Configuration#resolveAndBind
+     * resolveAndBind} to be re-run. </p>
      *
      * @param  service
      *         The service type
      *
      * @return this module
      *
-     * @throws IllegalStateException
-     *         If this is a named module and the caller is not this module
+     * @throws IllegalCallerException
+     *         If this is a named module and the caller's module is not this
+     *         module
      *
      * @see #canUse(Class)
      * @see ModuleDescriptor#uses()
@@ -841,7 +840,7 @@
         if (isNamed() && !descriptor.isAutomatic()) {
             Module caller = Reflection.getCallerClass().getModule();
             if (caller != this) {
-                throw new IllegalStateException(caller + " != " + this);
+                throw new IllegalCallerException(caller + " != " + this);
             }
             implAddUses(service);
         }
@@ -894,14 +893,13 @@
     // -- packages --
 
     // Additional packages that are added to the module at run-time.
-    // The field is volatile as it may be replaced at run-time
-    private volatile Set<String> extraPackages;
+    private volatile Map<String, Boolean> extraPackages;
 
     private boolean containsPackage(String pn) {
         if (descriptor.packages().contains(pn))
             return true;
-        Set<String> extraPackages = this.extraPackages;
-        if (extraPackages != null && extraPackages.contains(pn))
+        Map<String, Boolean> extraPackages = this.extraPackages;
+        if (extraPackages != null && extraPackages.containsKey(pn))
             return true;
         return false;
     }
@@ -915,7 +913,7 @@
      * added to the module, <a href="Proxy.html#dynamicmodule">dynamic modules</a>
      * for example, after it was loaded.
      *
-     * <p> For unnamed modules, this method is the equivalent of invoking the
+     * <p> For unnamed modules, this method is the equivalent to invoking the
      * {@link ClassLoader#getDefinedPackages() getDefinedPackages} method of
      * this module's class loader and returning the array of package names. </p>
      *
@@ -930,12 +928,12 @@
         if (isNamed()) {
 
             Set<String> packages = descriptor.packages();
-            Set<String> extraPackages = this.extraPackages;
+            Map<String, Boolean> extraPackages = this.extraPackages;
             if (extraPackages == null) {
                 return packages.toArray(new String[0]);
             } else {
                 return Stream.concat(packages.stream(),
-                                     extraPackages.stream())
+                                     extraPackages.keySet().stream())
                         .toArray(String[]::new);
             }
 
@@ -955,10 +953,6 @@
      * Add a package to this module.
      *
      * @apiNote This method is for Proxy use.
-     *
-     * @apiNote This is an expensive operation, not expected to be used often.
-     * At this time then it does not validate that the package name is a
-     * valid java identifier.
      */
     void addPackage(String pn) {
         implAddPackage(pn, true);
@@ -976,49 +970,52 @@
     /**
      * Add a package to this module.
      *
-     * If {@code syncVM} is {@code true} then the VM is notified.
+     * If {@code syncVM} is {@code true} then the VM is notified. This method is
+     * a no-op if this is an unnamed module or the module already contains the
+     * package.
+     *
+     * @throws IllegalArgumentException if the package name is not legal
+     * @throws IllegalStateException if the package is defined to another module
      */
     private void implAddPackage(String pn, boolean syncVM) {
+        // no-op if unnamed module
         if (!isNamed())
-            throw new InternalError("adding package to unnamed module?");
-        if (descriptor.isOpen())
-            throw new InternalError("adding package to open module?");
+            return;
+
+        // no-op if module contains the package
+        if (containsPackage(pn))
+            return;
+
+        // check package name is legal for named modules
         if (pn.isEmpty())
-            throw new InternalError("adding <unnamed> package to module?");
-
-        if (descriptor.packages().contains(pn)) {
-            // already in module
-            return;
+            throw new IllegalArgumentException("Cannot add <unnamed> package");
+        for (int i=0; i<pn.length(); i++) {
+            char c = pn.charAt(i);
+            if (c == '/' || c == ';' || c == '[') {
+                throw new IllegalArgumentException("Illegal character: " + c);
+            }
         }
 
-        Set<String> extraPackages = this.extraPackages;
-        if (extraPackages != null && extraPackages.contains(pn)) {
-            // already added
-            return;
+        // create extraPackages if needed
+        Map<String, Boolean> extraPackages = this.extraPackages;
+        if (extraPackages == null) {
+            synchronized (this) {
+                extraPackages = this.extraPackages;
+                if (extraPackages == null)
+                    this.extraPackages = extraPackages = new ConcurrentHashMap<>();
+            }
         }
-        synchronized (this) {
-            // recheck under lock
-            extraPackages = this.extraPackages;
-            if (extraPackages != null) {
-                if (extraPackages.contains(pn)) {
-                    // already added
-                    return;
-                }
 
-                // copy the set
-                extraPackages = new HashSet<>(extraPackages);
-                extraPackages.add(pn);
-            } else {
-                extraPackages = Collections.singleton(pn);
+        // update VM first in case it fails. This is a no-op if another thread
+        // beats us to add the package first
+        if (syncVM) {
+            // throws IllegalStateException if defined to another module
+            addPackage0(this, pn);
+            if (descriptor.isOpen() || descriptor.isAutomatic()) {
+                addExportsToAll0(this, pn);
             }
-
-            // update VM first, just in case it fails
-            if (syncVM)
-                addPackage0(this, pn);
-
-            // replace with new set
-            this.extraPackages = extraPackages; // volatile write
         }
+        extraPackages.putIfAbsent(pn, Boolean.TRUE);
     }
 
 
@@ -1169,8 +1166,9 @@
                                             Map<String, Module> nameToModule,
                                             Module m)
     {
-        // The VM doesn't know about open modules so need to export all packages
-        if (descriptor.isOpen()) {
+        // The VM doesn't special case open or automatic modules so need to
+        // export all packages
+        if (descriptor.isOpen() || descriptor.isAutomatic()) {
             assert descriptor.opens().isEmpty();
             for (String source : descriptor.packages()) {
                 addExportsToAll0(m, source);
@@ -1375,35 +1373,44 @@
 
 
     /**
-     * Returns an input stream for reading a resource in this module. The
-     * {@code name} parameter is a {@code '/'}-separated path name that
-     * identifies the resource.
+     * Returns an input stream for reading a resource in this module.
+     * The {@code name} parameter is a {@code '/'}-separated path name that
+     * identifies the resource. As with {@link Class#getResourceAsStream
+     * Class.getResourceAsStream}, this method delegates to the module's class
+     * loader {@link ClassLoader#findResource(String,String)
+     * findResource(String,String)} method, invoking it with the module name
+     * (or {@code null} when the module is unnamed) and the name of the
+     * resource. If the resource name has a leading slash then it is dropped
+     * before delegation.
      *
-     * <p> A resource in a named modules may be <em>encapsulated</em> so that
+     * <p> A resource in a named module may be <em>encapsulated</em> so that
      * it cannot be located by code in other modules. Whether a resource can be
-     * located or not is determined as follows:
+     * located or not is determined as follows: </p>
      *
      * <ul>
-     *     <li> The <em>package name</em> of the resource is derived from the
-     *     subsequence of characters that precedes the last {@code '/'} and then
-     *     replacing each {@code '/'} character in the subsequence with
-     *     {@code '.'}. For example, the package name derived for a resource
-     *     named "{@code a/b/c/foo.properties}" is "{@code a.b.c}". </li>
+     *     <li> If the resource name ends with  "{@code .class}" then it is not
+     *     encapsulated. </li>
      *
-     *     <li> If the package name is a package in the module then the package
-     *     must be {@link #isOpen open} the module of the caller of this method.
-     *     If the package is not in the module then the resource is not
-     *     encapsulated. Resources in the unnamed package or "{@code META-INF}",
-     *     for example, are never encapsulated because they can never be
-     *     packages in a named module. </li>
+     *     <li> A <em>package name</em> is derived from the resource name. If
+     *     the package name is a {@link #getPackages() package} in the module
+     *     then the resource can only be located by the caller of this method
+     *     when the package is {@link #isOpen(String,Module) open} to at least
+     *     the caller's module. If the resource is not in a package in the module
+     *     then the resource is not encapsulated. </li>
+     * </ul>
      *
-     *     <li> As a special case, resources ending with "{@code .class}" are
-     *     never encapsulated. </li>
-     * </ul>
+     * <p> In the above, the <em>package name</em> for a resource is derived
+     * from the subsequence of characters that precedes the last {@code '/'} in
+     * the name and then replacing each {@code '/'} character in the subsequence
+     * with {@code '.'}. A leading slash is ignored when deriving the package
+     * name. As an example, the package name derived for a resource named
+     * "{@code a/b/c/foo.properties}" is "{@code a.b.c}". A resource name
+     * with the name "{@code META-INF/MANIFEST.MF}" is never encapsulated
+     * because "{@code META-INF}" is not a legal package name. </p>
      *
      * <p> This method returns {@code null} if the resource is not in this
      * module, the resource is encapsulated and cannot be located by the caller,
-     * or access to the resource is denied by the security manager.
+     * or access to the resource is denied by the security manager. </p>
      *
      * @param  name
      *         The resource name
@@ -1413,11 +1420,13 @@
      * @throws IOException
      *         If an I/O error occurs
      *
-     * @see java.lang.module.ModuleReader#open(String)
+     * @see Class#getResourceAsStream(String)
      */
     @CallerSensitive
     public InputStream getResourceAsStream(String name) throws IOException {
-        Objects.requireNonNull(name);
+        if (name.startsWith("/")) {
+            name = name.substring(1);
+        }
 
         if (isNamed() && !ResourceHelper.isSimpleResource(name)) {
             Module caller = Reflection.getCallerClass().getModule();
--- a/src/java.base/share/classes/java/lang/reflect/Proxy.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/reflect/Proxy.java	Fri Feb 10 09:04:39 2017 +0000
@@ -25,6 +25,7 @@
 
 package java.lang.reflect;
 
+import java.lang.module.ModuleDescriptor;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.Arrays;
@@ -52,6 +53,9 @@
 import sun.security.action.GetPropertyAction;
 import sun.security.util.SecurityConstants;
 
+import static java.lang.module.ModuleDescriptor.Modifier.SYNTHETIC;
+
+
 /**
  *
  * {@code Proxy} provides static methods for creating objects that act like instances
@@ -164,7 +168,8 @@
  * methods is specified as follows:
  *
  * <ol>
- * <li>If all the proxy interfaces are in <em>exported</em> packages:
+ * <li>If all the proxy interfaces are in <em>exported</em> or <em>open</em>
+ *     packages:
  * <ol type="a">
  * <li>if all the proxy interfaces are <em>public</em>, then the proxy class is
  *     <em>public</em> in a package exported by the
@@ -178,10 +183,11 @@
  *     <a href="#restrictions">not possible</a>.</li>
  * </ol>
  * </li>
- * <li>If at least one proxy interface is a <em>non-exported</em> package:
+ * <li>If at least one proxy interface is in a package that is
+ *     <em>non-exported</em> and <em>non-open</em>:
  * <ol type="a">
  * <li>if all the proxy interfaces are <em>public</em>, then the proxy class is
- *     <em>public</em> in a <em>non-exported</em> package of
+ *     <em>public</em> in a <em>non-exported</em>, <em>non-open</em> package of
  *     <a href="#dynamicmodule"><em>dynamic module</em>.</a>
  *     The names of the package and the module are unspecified.</li>
  *
@@ -195,21 +201,22 @@
  * </ol>
  *
  * <p>
- * Note that if proxy interfaces with a mix of accessibilities --
- * exported public, exported non-public, non-exported public, non-exported non-public --
- * are proxied by the same instance, then the proxy class's accessibility is
+ * Note that if proxy interfaces with a mix of accessibilities -- for example,
+ * an exported public interface and a non-exported non-public interface -- are
+ * proxied by the same instance, then the proxy class's accessibility is
  * governed by the least accessible proxy interface.
  * <p>
  * Note that it is possible for arbitrary code to obtain access to a proxy class
- * in an exported package with {@link AccessibleObject#setAccessible setAccessible},
- * whereas a proxy class in a non-exported package is never accessible to
+ * in an open package with {@link AccessibleObject#setAccessible setAccessible},
+ * whereas a proxy class in a non-open package is never accessible to
  * code outside the module of the proxy class.
  *
  * <p>
- * Throughout this specification, a "non-exported package" refers to a package that
- * is not exported to all modules. Specifically, it refers to a package that
- * either is not exported at all by its containing module or is exported in a
- * qualified fashion by its containing module.
+ * Throughout this specification, a "non-exported package" refers to a package
+ * that is not exported to all modules, and a "non-open package" refers to
+ * a package that is not open to all modules.  Specifically, these terms refer to
+ * a package that either is not exported/open by its containing module or is
+ * exported/open in a qualified fashion by its containing module.
  *
  * <h3><a name="dynamicmodule">Dynamic Modules</a></h3>
  * <p>
@@ -272,6 +279,8 @@
  * @author      Peter Jones
  * @see         InvocationHandler
  * @since       1.3
+ * @revised 9
+ * @spec JPMS
  */
 public class Proxy implements java.io.Serializable {
     private static final long serialVersionUID = -2222568056686623797L;
@@ -358,6 +367,8 @@
      *      to create a proxy instance instead.
      *
      * @see <a href="#membership">Package and Module Membership of Proxy Class</a>
+     * @revised 9
+     * @spec JPMS
      */
     @Deprecated
     @CallerSensitive
@@ -855,7 +866,11 @@
                 // create a dynamic module and setup module access
                 String mn = "jdk.proxy" + counter.incrementAndGet();
                 String pn = PROXY_PACKAGE_PREFIX + "." + mn;
-                Module m = Modules.defineModule(ld, mn, Collections.singleton(pn));
+                ModuleDescriptor descriptor =
+                    ModuleDescriptor.newModule(mn, Set.of(SYNTHETIC))
+                                    .packages(Set.of(pn))
+                                    .build();
+                Module m = Modules.defineModule(ld, descriptor, null);
                 Modules.addReads(m, Proxy.class.getModule());
                 // java.base to create proxy instance
                 Modules.addExports(m, pn, Object.class.getModule());
@@ -955,6 +970,8 @@
      *          {@code null}
      *
      * @see <a href="#membership">Package and Module Membership of Proxy Class</a>
+     * @revised 9
+     * @spec JPMS
      */
     @CallerSensitive
     public static Object newProxyInstance(ClassLoader loader,
@@ -1039,6 +1056,9 @@
      * @return  {@code true} if the class is a proxy class and
      *          {@code false} otherwise
      * @throws  NullPointerException if {@code cl} is {@code null}
+     *
+     * @revised 9
+     * @spec JPMS
      */
     public static boolean isProxyClass(Class<?> cl) {
         return Proxy.class.isAssignableFrom(cl) && ProxyBuilder.isProxyClass(cl);
--- a/src/java.base/share/classes/java/lang/reflect/package-info.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/lang/reflect/package-info.java	Fri Feb 10 09:04:39 2017 +0000
@@ -45,5 +45,7 @@
  * members declared by a given class.
  *
  * @since 1.1
+ * @revised 9
+ * @spec JPMS
  */
 package java.lang.reflect;
--- a/src/java.base/share/classes/java/net/URLClassLoader.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/net/URLClassLoader.java	Fri Feb 10 09:04:39 2017 +0000
@@ -228,6 +228,7 @@
      *         allow creation of a class loader.
      *
      * @since 9
+     * @spec JPMS
      */
     public URLClassLoader(String name,
                           URL[] urls,
@@ -262,6 +263,7 @@
      *         creation of a class loader.
      *
      * @since 9
+     * @spec JPMS
      */
     public URLClassLoader(String name, URL[] urls, ClassLoader parent,
                           URLStreamHandlerFactory factory) {
@@ -558,6 +560,9 @@
      * @throws      IllegalArgumentException if the package name is
      *              already defined by this class loader
      * @return      the newly defined {@code Package} object
+     *
+     * @revised 9
+     * @spec JPMS
      */
     protected Package definePackage(String name, Manifest man, URL url) {
         String path = name.replace('.', '/').concat("/");
--- a/src/java.base/share/classes/java/security/SecureClassLoader.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/security/SecureClassLoader.java	Fri Feb 10 09:04:39 2017 +0000
@@ -125,6 +125,7 @@
      *         doesn't allow creation of a class loader.
      *
      * @since 9
+     * @spec JPMS
      */
     protected SecureClassLoader(String name, ClassLoader parent) {
         super(name, parent);
--- a/src/java.base/share/classes/java/security/Security.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/security/Security.java	Fri Feb 10 09:04:39 2017 +0000
@@ -25,11 +25,12 @@
 
 package java.security;
 
-import java.lang.reflect.*;
 import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 import java.io.*;
 import java.net.URL;
+
+import jdk.internal.misc.SharedSecrets;
 import sun.security.util.Debug;
 import sun.security.util.PropertyExpander;
 
@@ -800,9 +801,6 @@
      * "package.definition", we need to signal to the SecurityManager
      * class that the value has just changed, and that it should
      * invalidate it's local cache values.
-     *
-     * Rather than create a new API entry for this function,
-     * we use reflection to set a private variable.
      */
     private static void invalidateSMCache(String key) {
 
@@ -810,42 +808,8 @@
         final boolean pd = key.equals("package.definition");
 
         if (pa || pd) {
-            AccessController.doPrivileged(new PrivilegedAction<>() {
-                public Void run() {
-                    try {
-                        /* Get the class via the bootstrap class loader. */
-                        Class<?> cl = Class.forName(
-                            "java.lang.SecurityManager", false, null);
-                        Field f = null;
-                        boolean accessible = false;
-
-                        if (pa) {
-                            f = cl.getDeclaredField("packageAccessValid");
-                            accessible = f.isAccessible();
-                            f.setAccessible(true);
-                        } else {
-                            f = cl.getDeclaredField("packageDefinitionValid");
-                            accessible = f.isAccessible();
-                            f.setAccessible(true);
-                        }
-                        f.setBoolean(f, false);
-                        f.setAccessible(accessible);
-                    }
-                    catch (Exception e1) {
-                        /* If we couldn't get the class, it hasn't
-                         * been loaded yet.  If there is no such
-                         * field, we shouldn't try to set it.  There
-                         * shouldn't be a security execption, as we
-                         * are loaded by boot class loader, and we
-                         * are inside a doPrivileged() here.
-                         *
-                         * NOOP: don't do anything...
-                         */
-                    }
-                    return null;
-                }  /* run */
-            });  /* PrivilegedAction */
-        }  /* if */
+            SharedSecrets.getJavaLangAccess().invalidatePackageAccessCache();
+        }
     }
 
     private static void check(String directive) {
--- a/src/java.base/share/classes/java/util/ResourceBundle.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/util/ResourceBundle.java	Fri Feb 10 09:04:39 2017 +0000
@@ -350,6 +350,8 @@
  * @see MissingResourceException
  * @see ResourceBundleProvider
  * @since 1.1
+ * @revised 9
+ * @spec JPMS
  */
 public abstract class ResourceBundle {
 
@@ -870,6 +872,8 @@
      * @throws UnsupportedOperationException
      *         if this method is called in a named module
      * @since 1.6
+     * @revised 9
+     * @spec JPMS
      */
     @CallerSensitive
     public static final ResourceBundle getBundle(String baseName,
@@ -938,6 +942,7 @@
      *         specified module
      * @return a resource bundle for the given base name and the default locale
      * @since 9
+     * @spec JPMS
      * @see ResourceBundleProvider
      */
     @CallerSensitive
@@ -991,6 +996,7 @@
      *         be found in the specified {@code module}
      * @return a resource bundle for the given base name and locale in the module
      * @since 9
+     * @spec JPMS
      */
     @CallerSensitive
     public static ResourceBundle getBundle(String baseName, Locale targetLocale, Module module) {
@@ -1036,6 +1042,8 @@
      * @throws UnsupportedOperationException
      *         if this method is called in a named module
      * @since 1.6
+     * @revised 9
+     * @spec JPMS
      */
     @CallerSensitive
     public static final ResourceBundle getBundle(String baseName, Locale targetLocale,
@@ -1243,6 +1251,8 @@
      * @exception MissingResourceException
      *        if no resource bundle for the specified base name can be found
      * @since 1.2
+     * @revised 9
+     * @spec JPMS
      */
     @CallerSensitive
     public static ResourceBundle getBundle(String baseName, Locale locale,
@@ -1465,6 +1475,8 @@
      * @throws UnsupportedOperationException
      *         if this method is called in a named module
      * @since 1.6
+     * @revised 9
+     * @spec JPMS
      */
     @CallerSensitive
     public static ResourceBundle getBundle(String baseName, Locale targetLocale,
@@ -2194,6 +2206,8 @@
      * by the caller's module.
      *
      * @since 1.6
+     * @revised 9
+     * @spec JPMS
      * @see ResourceBundle.Control#getTimeToLive(String,Locale)
      */
     @CallerSensitive
@@ -2475,6 +2489,8 @@
      * of {@link ResourceBundleControlProvider} are ignored in named modules.
      *
      * @since 1.6
+     * @revised 9
+     * @spec JPMS
      * @see java.util.spi.ResourceBundleProvider
      */
     public static class Control {
@@ -3103,6 +3119,8 @@
          *        if an error occurred when reading resources using
          *        any I/O operations
          * @see java.util.spi.ResourceBundleProvider#getBundle(String, Locale)
+         * @revised 9
+         * @spec JPMS
          */
         public ResourceBundle newBundle(String baseName, Locale locale, String format,
                                         ClassLoader loader, boolean reload)
--- a/src/java.base/share/classes/java/util/ServiceLoader.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/util/ServiceLoader.java	Fri Feb 10 09:04:39 2017 +0000
@@ -119,7 +119,7 @@
  * and deployed as an explicit module must have an appropriate <i>uses</i>
  * clause in its <i>module descriptor</i> to declare that the module uses
  * implementations of the service. A corresponding requirement is that a
- * provider deployed as a named module must have an appropriate
+ * provider deployed as an explicit module must have an appropriate
  * <i>provides</i> clause in its module descriptor to declare that the module
  * provides an implementation of the service. The <i>uses</i> and
  * <i>provides</i> allow consumers of a service to be <i>linked</i> to modules
@@ -203,8 +203,11 @@
  *     ordering of modules in a layer, is not defined. </li>
  *
  *     <li> If a named module declares more than one provider then the providers
- *     are located in the order that they appear in the {@code provides} table of
- *     the {@code Module} class file attribute ({@code module-info.class}). </li>
+ *     are located in the iteration order of the {@link
+ *     java.lang.module.ModuleDescriptor.Provides#providers() providers} list.
+ *     Providers added dynamically by instrumentation agents ({@link
+ *     java.lang.instrument.Instrumentation#redefineModule redefineModule})
+ *     are always located after providers declared by the module. </li>
  *
  *     <li> When locating providers in unnamed modules then the ordering is
  *     based on the order that the class loader's {@link
@@ -335,6 +338,8 @@
  *
  * @author Mark Reinhold
  * @since 1.6
+ * @revised 9
+ * @spec JPMS
  */
 
 public final class ServiceLoader<S>
@@ -386,6 +391,7 @@
      *
      * @param  <S> The service type
      * @since 9
+     * @spec JPMS
      */
     public static interface Provider<S> extends Supplier<S> {
         /**
@@ -927,26 +933,28 @@
             } else {
                 catalog = ServicesCatalog.getServicesCatalogOrNull(loader);
             }
-            Stream<ServiceProvider> stream1;
+            List<ServiceProvider> providers;
             if (catalog == null) {
-                stream1 = Stream.empty();
+                providers = List.of();
             } else {
-                stream1 = catalog.findServices(serviceName).stream();
+                providers = catalog.findServices(serviceName);
             }
 
             // modules in custom layers that define modules to the class loader
-            Stream<ServiceProvider> stream2;
             if (loader == null) {
-                stream2 = Stream.empty();
+                return providers.iterator();
             } else {
+                List<ServiceProvider> allProviders = new ArrayList<>(providers);
                 Layer bootLayer = Layer.boot();
-                stream2 = JLRM_ACCESS.layers(loader)
-                        .filter(l -> (l != bootLayer))
-                        .map(l -> providers(l))
-                        .flatMap(List::stream);
+                Iterator<Layer> iterator = JLRM_ACCESS.layers(loader).iterator();
+                while (iterator.hasNext()) {
+                    Layer layer = iterator.next();
+                    if (layer != bootLayer) {
+                        allProviders.addAll(providers(layer));
+                    }
+                }
+                return allProviders.iterator();
             }
-
-            return Stream.concat(stream1, stream2).iterator();
         }
 
         @Override
@@ -1214,6 +1222,9 @@
      *
      * @return  An iterator that lazily loads providers for this loader's
      *          service
+     *
+     * @revised 9
+     * @spec JPMS
      */
     public Iterator<S> iterator() {
 
@@ -1279,8 +1290,10 @@
      * provider to be loaded. </p>
      *
      * <p> If this loader's provider caches are cleared by invoking the {@link
-     * #reload() reload} method then existing streams for this service
-     * loader should be discarded. </p>
+     * #reload() reload} method then existing streams for this service loader
+     * should be discarded. The returned stream's source {@code Spliterator} is
+     * <em>fail-fast</em> and will throw {@link ConcurrentModificationException}
+     * if the provider cache has been cleared. </p>
      *
      * <p> The following examples demonstrate usage. The first example
      * creates a stream of providers, the second example is the same except
@@ -1300,6 +1313,7 @@
      * @return  A stream that lazily loads providers for this loader's service
      *
      * @since 9
+     * @spec JPMS
      */
     public Stream<Provider<S>> stream() {
         // use cached providers as the source when all providers loaded
@@ -1414,6 +1428,9 @@
      *         if the service type is not accessible to the caller or the
      *         caller is in an explicit module and its module descriptor does
      *         not declare that it uses {@code service}
+     *
+     * @revised 9
+     * @spec JPMS
      */
     @CallerSensitive
     public static <S> ServiceLoader<S> load(Class<S> service,
@@ -1457,6 +1474,9 @@
      *         if the service type is not accessible to the caller or the
      *         caller is in an explicit module and its module descriptor does
      *         not declare that it uses {@code service}
+     *
+     * @revised 9
+     * @spec JPMS
      */
     @CallerSensitive
     public static <S> ServiceLoader<S> load(Class<S> service) {
@@ -1490,6 +1510,9 @@
      *         if the service type is not accessible to the caller or the
      *         caller is in an explicit module and its module descriptor does
      *         not declare that it uses {@code service}
+     *
+     * @revised 9
+     * @spec JPMS
      */
     @CallerSensitive
     public static <S> ServiceLoader<S> loadInstalled(Class<S> service) {
@@ -1522,6 +1545,7 @@
      *         not declare that it uses {@code service}
      *
      * @since 9
+     * @spec JPMS
      */
     @CallerSensitive
     public static <S> ServiceLoader<S> load(Layer layer, Class<S> service) {
@@ -1551,6 +1575,7 @@
      *         or error is thrown when locating or instantiating the provider.
      *
      * @since 9
+     * @spec JPMS
      */
     public Optional<S> findFirst() {
         Iterator<S> iterator = iterator();
--- a/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/util/spi/AbstractResourceBundleProvider.java	Fri Feb 10 09:04:39 2017 +0000
@@ -81,6 +81,7 @@
  *     ResourceBundleProvider Service Providers</a>
  *
  * @since 9
+ * @spec JPMS
  */
 public abstract class AbstractResourceBundleProvider implements ResourceBundleProvider {
     private static final JavaUtilResourceBundleAccess RB_ACCESS =
--- a/src/java.base/share/classes/java/util/spi/ResourceBundleControlProvider.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/util/spi/ResourceBundleControlProvider.java	Fri Feb 10 09:04:39 2017 +0000
@@ -44,6 +44,8 @@
  *
  * @author Masayoshi Okutsu
  * @since 1.8
+ * @revised 9
+ * @spec JPMS
  * @see ResourceBundle#getBundle(String, java.util.Locale, ClassLoader, ResourceBundle.Control)
  *      ResourceBundle.getBundle
  * @see java.util.ServiceLoader#load(Class)
--- a/src/java.base/share/classes/java/util/spi/ResourceBundleProvider.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/java/util/spi/ResourceBundleProvider.java	Fri Feb 10 09:04:39 2017 +0000
@@ -57,6 +57,7 @@
  * @see <a href="../ResourceBundle.html#RBP_support">
  *     ResourceBundleProvider Service Providers</a>
  * @since 9
+ * @spec JPMS
  */
 public interface ResourceBundleProvider {
     /**
--- a/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java	Fri Feb 10 09:04:39 2017 +0000
@@ -186,7 +186,7 @@
     public Entry getEntry(Section section, String name) {
         String entry = section.jmodDir() + "/" + name;
         ZipEntry ze = zipfile.getEntry(entry);
-        return (ze != null) ? new Entry(ze) : null;
+        return (ze == null || ze.isDirectory()) ? null : new Entry(ze);
     }
 
     /**
@@ -201,7 +201,7 @@
     {
         String entry = section.jmodDir() + "/" + name;
         ZipEntry e = zipfile.getEntry(entry);
-        if (e == null) {
+        if (e == null || e.isDirectory()) {
             throw new IOException(name + " not found: " + file);
         }
         return zipfile.getInputStream(e);
--- a/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java	Fri Feb 10 09:04:39 2017 +0000
@@ -57,8 +57,9 @@
 import java.util.jar.Manifest;
 import java.util.stream.Stream;
 
+import jdk.internal.misc.VM;
 import jdk.internal.module.ModulePatcher.PatchedModuleReader;
-import jdk.internal.misc.VM;
+import jdk.internal.module.SystemModules;
 
 
 /**
@@ -135,7 +136,7 @@
 
     // maps package name to loaded module for modules in the boot layer
     private static final Map<String, LoadedModule> packageToModule
-        = new ConcurrentHashMap<>(1024);
+        = new ConcurrentHashMap<>(SystemModules.PACKAGES_IN_BOOT_LAYER);
 
     // maps a module name to a module reference
     private final Map<String, ModuleReference> nameToModule;
@@ -922,13 +923,13 @@
      * Returns the ModuleReader for the given module.
      */
     private ModuleReader moduleReaderFor(ModuleReference mref) {
-        return moduleToReader.computeIfAbsent(mref, m -> createModuleReader(mref));
+        return moduleToReader.computeIfAbsent(mref, BuiltinClassLoader::createModuleReader);
     }
 
     /**
      * Creates a ModuleReader for the given module.
      */
-    private ModuleReader createModuleReader(ModuleReference mref) {
+    private static ModuleReader createModuleReader(ModuleReference mref) {
         try {
             return mref.open();
         } catch (IOException e) {
--- a/src/java.base/share/classes/jdk/internal/loader/ResourceHelper.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/loader/ResourceHelper.java	Fri Feb 10 09:04:39 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -24,6 +24,10 @@
  */
 package jdk.internal.loader;
 
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
 import jdk.internal.module.Checks;
 
 /**
@@ -34,7 +38,8 @@
     private ResourceHelper() { }
 
     /**
-     * Returns the <em>package name</em> for a resource.
+     * Returns the <em>package name</em> for a resource or the empty package if
+     * the resource name does not contain a slash.
      */
     public static String getPackageName(String name) {
         int index = name.lastIndexOf('/');
@@ -46,19 +51,75 @@
     }
 
     /**
-     * Returns true if the resource is a <em>simple resource</em> that can
-     * never be encapsulated. Resources ending in "{@code .class}" or where
-     * the package name is not a Java identifier are resources that can
-     * never be encapsulated.
+     * Returns true if the resource is a <em>simple resource</em>. Simple
+     * resources can never be encapsulated. Resources ending in "{@code .class}"
+     * or where the package name is not a legal package name can not be
+     * encapsulated.
      */
     public static boolean isSimpleResource(String name) {
         int len = name.length();
         if (len > 6 && name.endsWith(".class")) {
             return true;
         }
-        if (!Checks.isJavaIdentifier(getPackageName(name))) {
+        if (!Checks.isPackageName(getPackageName(name))) {
             return true;
         }
         return false;
     }
+
+    /**
+     * Converts a resource name to a file path. Returns {@code null} if the
+     * resource name cannot be converted into a file path. Resource names
+     * with empty elements, or elements that are "." or ".." are rejected,
+     * as is a resource name that translates to a file path with a root
+     * component.
+     */
+    public static Path toFilePath(String name) {
+        // scan the resource name to eagerly reject obviously invalid names
+        int next;
+        int off = 0;
+        while ((next = name.indexOf('/', off)) != -1) {
+            int len = next - off;
+            if (!mayTranslate(name, off, len)) {
+                return null;
+            }
+            off = next + 1;
+        }
+        int rem = name.length() - off;
+        if (!mayTranslate(name, off, rem)) {
+            return null;
+        }
+
+        // convert to file path
+        Path path;
+        if (File.separatorChar == '/') {
+            path = Paths.get(name);
+        } else {
+            // not allowed to embed file separators
+            if (name.contains(File.separator))
+                return null;
+            path = Paths.get(name.replace('/', File.separatorChar));
+        }
+
+        // file path not allowed to have root component
+        return (path.getRoot() == null) ? path : null;
+    }
+
+    /**
+     * Returns {@code true} if the element in a resource name is a candidate
+     * to translate to the element of a file path.
+     */
+    private static boolean mayTranslate(String name, int off, int len) {
+        if (len <= 2) {
+            if (len == 0)
+                return false;
+            boolean starsWithDot = (name.charAt(off) == '.');
+            if (len == 1 && starsWithDot)
+                return false;
+            if (len == 2 && starsWithDot && (name.charAt(off+1) == '.'))
+                return false;
+        }
+        return true;
+    }
+
 }
--- a/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java	Fri Feb 10 09:04:39 2017 +0000
@@ -174,4 +174,9 @@
      * Invokes Long.fastUUID
      */
     String fastUUID(long lsb, long msb);
+
+    /**
+     * Invalidate package access cache
+     */
+    void invalidatePackageAccessCache();
 }
--- a/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java	Fri Feb 10 09:04:39 2017 +0000
@@ -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
@@ -59,20 +59,21 @@
      */
     ModuleDescriptor.Builder newModuleBuilder(String mn,
                                               boolean strict,
-                                              boolean open,
-                                              boolean synthetic);
+                                              Set<ModuleDescriptor.Modifier> ms);
 
     /**
-     * Returns the set of packages that are exported (unconditionally or
-     * unconditionally).
+     * Returns a snapshot of the packages in the module.
      */
-    Set<String> exportedPackages(ModuleDescriptor.Builder builder);
+    Set<String> packages(ModuleDescriptor.Builder builder);
 
     /**
-     * Returns the set of packages that are opened (unconditionally or
-     * unconditionally).
+     * Adds a dependence on a module with the given (possibly un-parsable)
+     * version string.
      */
-    Set<String> openPackages(ModuleDescriptor.Builder builder);
+    void requires(ModuleDescriptor.Builder builder,
+                  Set<Requires.Modifier> ms,
+                  String mn,
+                  String compiledVersion);
 
     /**
      * Returns a {@code ModuleDescriptor.Requires} of the given modifiers
@@ -114,23 +115,11 @@
     Provides newProvides(String service, List<String> providers);
 
     /**
-     * Returns a {@code ModuleDescriptor.Version} of the given version.
-     */
-    Version newVersion(String v);
-
-    /**
-     * Clones the given module descriptor with an augmented set of packages
-     */
-    ModuleDescriptor newModuleDescriptor(ModuleDescriptor md, Set<String> pkgs);
-
-    /**
      * Returns a new {@code ModuleDescriptor} instance.
      */
     ModuleDescriptor newModuleDescriptor(String name,
                                          Version version,
-                                         boolean open,
-                                         boolean automatic,
-                                         boolean synthetic,
+                                         Set<ModuleDescriptor.Modifier> ms,
                                          Set<Requires> requires,
                                          Set<Exports> exports,
                                          Set<Opens> opens,
@@ -148,9 +137,9 @@
      * and the empty configuration as the parent. The post resolution
      * checks are optionally run.
      */
-    Configuration resolveRequiresAndUses(ModuleFinder finder,
-                                         Collection<String> roots,
-                                         boolean check,
-                                         PrintStream traceOutput);
+    Configuration resolveAndBind(ModuleFinder finder,
+                                 Collection<String> roots,
+                                 boolean check,
+                                 PrintStream traceOutput);
 
 }
--- a/src/java.base/share/classes/jdk/internal/module/Builder.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/Builder.java	Fri Feb 10 09:04:39 2017 +0000
@@ -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
@@ -38,7 +38,7 @@
 import jdk.internal.misc.SharedSecrets;
 
 /**
- * This builder is optimized for reconstituting ModuleDescriptor
+ * This builder is optimized for reconstituting the {@code ModuleDescriptor}s
  * for system modules.  The validation should be done at jlink time.
  *
  * 1. skip name validation
@@ -136,9 +136,7 @@
     }
 
     final String name;
-    boolean open;
-    boolean automatic;
-    boolean synthetic;
+    boolean open, synthetic, mandated;
     Set<Requires> requires;
     Set<Exports> exports;
     Set<Opens> opens;
@@ -165,13 +163,13 @@
         return this;
     }
 
-    Builder automatic(boolean value) {
-        this.automatic = value;
+    Builder synthetic(boolean value) {
+        this.synthetic = value;
         return this;
     }
 
-    Builder synthetic(boolean value) {
-        this.synthetic = value;
+    Builder mandated(boolean value) {
+        this.mandated = value;
         return this;
     }
 
@@ -228,13 +226,10 @@
      *
      * @throws IllegalArgumentException if {@code v} is null or cannot be
      *         parsed as a version string
-     * @throws IllegalStateException if the module version is already set
      *
      * @see Version#parse(String)
      */
     public Builder version(String v) {
-        if (version != null)
-            throw new IllegalStateException("module version already set");
         Version ver = cachedVersion;
         if (ver != null && v.equals(ver.toString())) {
             version = ver;
@@ -246,63 +241,63 @@
 
     /**
      * Sets the module main class.
-     *
-     * @throws IllegalStateException if already set
      */
     public Builder mainClass(String mc) {
-        if (mainClass != null)
-            throw new IllegalStateException("main class already set");
         mainClass = mc;
         return this;
     }
 
     /**
      * Sets the OS name.
-     *
-     * @throws IllegalStateException if already set
      */
     public Builder osName(String name) {
-        if (osName != null)
-            throw new IllegalStateException("OS name already set");
         this.osName = name;
         return this;
     }
 
     /**
      * Sets the OS arch.
-     *
-     * @throws IllegalStateException if already set
      */
     public Builder osArch(String arch) {
-        if (osArch != null)
-            throw new IllegalStateException("OS arch already set");
         this.osArch = arch;
         return this;
     }
 
     /**
      * Sets the OS version.
-     *
-     * @throws IllegalStateException if already set
      */
     public Builder osVersion(String version) {
-        if (osVersion != null)
-            throw new IllegalStateException("OS version already set");
         this.osVersion = version;
         return this;
     }
 
     /**
+     * Returns an immutable set of the module modifiers derived from the flags.
+     */
+    private Set<ModuleDescriptor.Modifier> modifiers() {
+        int n = 0;
+        if (open) n++;
+        if (synthetic) n++;
+        if (mandated) n++;
+        if (n == 0) {
+            return Collections.emptySet();
+        } else {
+            ModuleDescriptor.Modifier[] mods = new ModuleDescriptor.Modifier[n];
+            if (open) mods[--n] = ModuleDescriptor.Modifier.OPEN;
+            if (synthetic) mods[--n] = ModuleDescriptor.Modifier.SYNTHETIC;
+            if (mandated) mods[--n] = ModuleDescriptor.Modifier.MANDATED;
+            return Set.of(mods);
+        }
+    }
+
+    /**
      * Builds a {@code ModuleDescriptor} from the components.
      */
     public ModuleDescriptor build(int hashCode) {
         assert name != null;
-
         return JLMA.newModuleDescriptor(name,
                                         version,
-                                        open,
-                                        automatic,
-                                        synthetic,
+                                        modifiers(),
                                         requires,
                                         exports,
                                         opens,
--- a/src/java.base/share/classes/jdk/internal/module/Checks.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/Checks.java	Fri Feb 10 09:04:39 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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,7 +26,7 @@
 package jdk.internal.module;
 
 /**
- * Utility class for checking module name and binary names.
+ * Utility class for checking module, package, and class names.
  */
 
 public final class Checks {
@@ -58,8 +58,6 @@
             throw new IllegalArgumentException(name + ": Invalid module name"
                     + ": '" + id + "' is not a Java identifier");
         }
-        //if (!Character.isJavaIdentifierStart(last))
-        //    throw new IllegalArgumentException(name + ": Module name ends in digit");
         return name;
     }
 
@@ -77,8 +75,6 @@
         int last = isJavaIdentifier(name, off, name.length() - off);
         if (last == -1)
             return false;
-        //if (!Character.isJavaIdentifierStart(last))
-        //    return false;
         return true;
     }
 
@@ -89,40 +85,62 @@
      *         package name
      */
     public static String requirePackageName(String name) {
-        return requireBinaryName("package name", name);
+        return requireTypeName("package name", name);
     }
 
     /**
-     * Checks a name to ensure that it's a legal type name.
-     *
-     * @throws IllegalArgumentException if name is null or not a legal
-     *         type name
+     * Returns {@code true} if the given name is a legal package name.
      */
-    public static String requireServiceTypeName(String name) {
-        return requireBinaryName("service type name", name);
+    public static boolean isPackageName(String name) {
+        return isTypeName(name);
     }
 
     /**
-     * Checks a name to ensure that it's a legal type name.
+     * Checks a name to ensure that it's a legal qualified class name
      *
      * @throws IllegalArgumentException if name is null or not a legal
-     *         type name
+     *         qualified class name
      */
-    public static String requireServiceProviderName(String name) {
-        return requireBinaryName("service provider name", name);
+    public static String requireServiceTypeName(String name) {
+        return requireQualifiedClassName("service type name", name);
     }
 
     /**
-     * Returns {@code true} if the given name is a legal binary name.
+     * Checks a name to ensure that it's a legal qualified class name.
+     *
+     * @throws IllegalArgumentException if name is null or not a legal
+     *         qualified class name
      */
-    public static boolean isJavaIdentifier(String name) {
-        return isBinaryName(name);
+    public static String requireServiceProviderName(String name) {
+        return requireQualifiedClassName("service provider name", name);
     }
 
     /**
-     * Returns {@code true} if the given name is a legal binary name.
+     * Checks a name to ensure that it's a legal qualified class name in
+     * a named package.
+     *
+     * @throws IllegalArgumentException if name is null or not a legal
+     *         qualified class name in a named package
      */
-    public static boolean isBinaryName(String name) {
+    public static String requireQualifiedClassName(String what, String name) {
+        requireTypeName(what, name);
+        if (name.indexOf('.') == -1)
+            throw new IllegalArgumentException(name + ": is not a qualified name of"
+                                               + " a Java class in a named package");
+        return name;
+    }
+
+    /**
+     * Returns {@code true} if the given name is a legal class name.
+     */
+    public static boolean isClassName(String name) {
+        return isTypeName(name);
+    }
+
+    /**
+     * Returns {@code true} if the given name is a legal type name.
+     */
+    private static boolean isTypeName(String name) {
         int next;
         int off = 0;
         while ((next = name.indexOf('.', off)) != -1) {
@@ -135,12 +153,12 @@
     }
 
     /**
-     * Checks if the given name is a legal binary name.
+     * Checks if the given name is a legal type name.
      *
      * @throws IllegalArgumentException if name is null or not a legal
-     *         binary name
+     *         type name
      */
-    public static String requireBinaryName(String what, String name) {
+    private static String requireTypeName(String what, String name) {
         if (name == null)
             throw new IllegalArgumentException("Null " + what);
         int next;
--- a/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java	Fri Feb 10 09:04:39 2017 +0000
@@ -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
@@ -26,6 +26,7 @@
 package jdk.internal.module;
 
 import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Builder;
 import java.lang.module.ModuleDescriptor.Requires;
 import java.lang.module.ModuleDescriptor.Exports;
 import java.lang.module.ModuleDescriptor.Opens;
@@ -98,14 +99,17 @@
 
             // module_flags
             int module_flags = cr.readUnsignedShort(off);
-            boolean open = ((module_flags & ACC_OPEN) != 0);
-            boolean synthetic = ((module_flags & ACC_SYNTHETIC) != 0);
             off += 2;
 
-            ModuleDescriptor.Builder builder = JLMA.newModuleBuilder(mn,
-                                                                     false,
-                                                                     open,
-                                                                     synthetic);
+            Set<ModuleDescriptor.Modifier> modifiers = new HashSet<>();
+            if ((module_flags & ACC_OPEN) != 0)
+                modifiers.add(ModuleDescriptor.Modifier.OPEN);
+            if ((module_flags & ACC_SYNTHETIC) != 0)
+                modifiers.add(ModuleDescriptor.Modifier.SYNTHETIC);
+            if ((module_flags & ACC_MANDATED) != 0)
+                modifiers.add(ModuleDescriptor.Modifier.MANDATED);
+
+            Builder builder = JLMA.newModuleBuilder(mn, false, modifiers);
 
             // module_version
             String module_version = cr.readUTF8(off, buf);
@@ -142,19 +146,13 @@
                         mods.add(Requires.Modifier.MANDATED);
                 }
 
-
                 // requires_version
-                Version compiledVersion = null;
                 String requires_version = cr.readUTF8(off, buf);
                 off += 2;
-                if (requires_version != null) {
-                    compiledVersion = Version.parse(requires_version);
-                }
-
-                if (compiledVersion == null) {
+                if (requires_version == null) {
                     builder.requires(mods, dn);
                 } else {
-                    builder.requires(mods, dn, compiledVersion);
+                    JLMA.requires(builder, mods, dn, requires_version);
                 }
             }
 
@@ -283,11 +281,14 @@
             attr.putShort(module_name_index);
 
             // module_flags
+            Set<ModuleDescriptor.Modifier> modifiers = descriptor.modifiers();
             int module_flags = 0;
-            if (descriptor.isOpen())
+            if (modifiers.contains(ModuleDescriptor.Modifier.OPEN))
                 module_flags |= ACC_OPEN;
-            if (descriptor.isSynthetic())
+            if (modifiers.contains(ModuleDescriptor.Modifier.SYNTHETIC))
                 module_flags |= ACC_SYNTHETIC;
+            if (modifiers.contains(ModuleDescriptor.Modifier.MANDATED))
+                module_flags |= ACC_MANDATED;
             attr.putShort(module_flags);
 
             // module_version
--- a/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ClassFileConstants.java	Fri Feb 10 09:04:39 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 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
@@ -46,8 +46,8 @@
     // access, requires, exports, and opens flags
     public static final int ACC_MODULE        = 0x8000;
     public static final int ACC_OPEN          = 0x0020;
-    public static final int ACC_TRANSITIVE    = 0x0010;
-    public static final int ACC_STATIC_PHASE  = 0x0020;
+    public static final int ACC_TRANSITIVE    = 0x0020;
+    public static final int ACC_STATIC_PHASE  = 0x0040;
     public static final int ACC_SYNTHETIC     = 0x1000;
     public static final int ACC_MANDATED      = 0x8000;
 
--- a/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java	Fri Feb 10 09:04:39 2017 +0000
@@ -26,7 +26,9 @@
 package jdk.internal.module;
 
 import java.io.File;
+import java.io.IOException;
 import java.io.PrintStream;
+import java.io.UncheckedIOException;
 import java.lang.module.Configuration;
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleFinder;
@@ -35,6 +37,7 @@
 import java.lang.reflect.Layer;
 import java.lang.reflect.Module;
 import java.net.URI;
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
@@ -46,6 +49,7 @@
 import java.util.Optional;
 import java.util.Set;
 import java.util.function.Function;
+import java.util.stream.Stream;
 
 import jdk.internal.loader.BootLoader;
 import jdk.internal.loader.BuiltinClassLoader;
@@ -114,7 +118,12 @@
         long t0 = System.nanoTime();
 
         // system modules (may be patched)
-        ModuleFinder systemModules = ModuleFinder.ofSystem();
+        ModuleFinder systemModules;
+        if (SystemModules.MODULE_NAMES.length > 0) {
+            systemModules = SystemModuleFinder.getInstance();
+        } else {
+            systemModules = ModuleFinder.ofSystem();
+        }
 
         PerfCounters.systemModulesTime.addElapsedTimeFrom(t0);
 
@@ -275,10 +284,10 @@
 
         // run the resolver to create the configuration
         Configuration cf = SharedSecrets.getJavaLangModuleAccess()
-                .resolveRequiresAndUses(finder,
-                                        roots,
-                                        needPostResolutionChecks,
-                                        traceOutput);
+                .resolveAndBind(finder,
+                                roots,
+                                needPostResolutionChecks,
+                                traceOutput);
 
         // time to create configuration
         PerfCounters.resolveTime.addElapsedTimeFrom(t3);
@@ -318,20 +327,20 @@
         // if needed check that there are no split packages in the set of
         // resolved modules for the boot layer
         if (SystemModules.hasSplitPackages() || needPostResolutionChecks) {
-                Map<String, String> packageToModule = new HashMap<>();
-                for (ResolvedModule resolvedModule : cf.modules()) {
-                    ModuleDescriptor descriptor =
-                        resolvedModule.reference().descriptor();
-                    String name = descriptor.name();
-                    for (String p : descriptor.packages()) {
-                        String other = packageToModule.putIfAbsent(p, name);
-                        if (other != null) {
-                            fail("Package " + p + " in both module "
-                                 + name + " and module " + other);
-                        }
+            Map<String, String> packageToModule = new HashMap<>();
+            for (ResolvedModule resolvedModule : cf.modules()) {
+                ModuleDescriptor descriptor =
+                    resolvedModule.reference().descriptor();
+                String name = descriptor.name();
+                for (String p : descriptor.packages()) {
+                    String other = packageToModule.putIfAbsent(p, name);
+                    if (other != null) {
+                        fail("Package " + p + " in both module "
+                             + name + " and module " + other);
                     }
                 }
             }
+        }
 
         long t4 = System.nanoTime();
 
@@ -380,10 +389,9 @@
                                             Set<String> otherMods)
     {
         // resolve all root modules
-        Configuration cf = Configuration.empty()
-                .resolveRequires(finder,
-                                 ModuleFinder.of(),
-                                 roots);
+        Configuration cf = Configuration.empty().resolve(finder,
+                                                         ModuleFinder.of(),
+                                                         roots);
 
         // module name -> reference
         Map<String, ModuleReference> map = new HashMap<>();
@@ -416,7 +424,7 @@
 
     /**
      * Creates a finder from the module path that is the value of the given
-     * system property.
+     * system property and optionally patched by --patch-module
      */
     private static ModuleFinder createModulePathFinder(String prop) {
         String s = System.getProperty(prop);
@@ -429,7 +437,7 @@
             for (String dir: dirs) {
                 paths[i++] = Paths.get(dir);
             }
-            return ModuleFinder.of(paths);
+            return ModulePath.of(patcher, paths);
         }
     }
 
@@ -528,8 +536,48 @@
         if (!extraOpens.isEmpty()) {
             addExtraExportsOrOpens(bootLayer, extraOpens, true);
         }
+
+        // DEBUG_ADD_OPENS is for debugging purposes only
+        String home = System.getProperty("java.home");
+        Path file = Paths.get(home, "conf", "DEBUG_ADD_OPENS");
+        if (Files.exists(file)) {
+            warn(file + " detected; may break encapsulation");
+            try (Stream<String> lines = Files.lines(file)) {
+                lines.map(line -> line.trim())
+                    .filter(line -> (!line.isEmpty() && !line.startsWith("#")))
+                    .forEach(line -> {
+                        String[] s = line.split("/");
+                        if (s.length != 2) {
+                            fail("Unable to parse as <module>/<package>: " + line);
+                        } else {
+                            String mn = s[0];
+                            String pkg = s[1];
+                            openPackage(bootLayer, mn, pkg);
+                        }
+                    });
+            } catch (IOException ioe) {
+                throw new UncheckedIOException(ioe);
+            }
+        }
     }
 
+    private static void openPackage(Layer bootLayer, String mn, String pkg) {
+        if (mn.equals("ALL-RESOLVED") && pkg.equals("ALL-PACKAGES")) {
+            bootLayer.modules().stream().forEach(m ->
+                m.getDescriptor().packages().forEach(pn -> openPackage(m, pn)));
+        } else {
+            bootLayer.findModule(mn)
+                     .filter(m -> m.getDescriptor().packages().contains(pkg))
+                     .ifPresent(m -> openPackage(m, pkg));
+        }
+    }
+
+    private static void openPackage(Module m, String pn) {
+        Modules.addOpensToAllUnnamed(m, pn);
+        warn("Opened for deep reflection: " + m.getName()  + "/" + pn);
+    }
+
+
     private static void addExtraExportsOrOpens(Layer bootLayer,
                                                Map<String, List<String>> map,
                                                boolean opens)
--- a/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java	Fri Feb 10 09:04:39 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, 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
@@ -37,7 +37,6 @@
 import java.lang.module.ModuleDescriptor.Requires;
 import java.lang.module.ModuleDescriptor.Exports;
 import java.lang.module.ModuleDescriptor.Opens;
-import java.lang.module.ModuleDescriptor.Version;
 import java.nio.ByteBuffer;
 import java.nio.BufferUnderflowException;
 import java.util.ArrayList;
@@ -51,7 +50,6 @@
 
 import jdk.internal.misc.JavaLangModuleAccess;
 import jdk.internal.misc.SharedSecrets;
-import jdk.internal.module.ModuleResolution;
 
 import static jdk.internal.module.ClassFileConstants.*;
 
@@ -221,7 +219,7 @@
         Set<String> attributes = new HashSet<>();
 
         Builder builder = null;
-        Set<String> packages = null;
+        Set<String> allPackages = null;
         String mainClass = null;
         String[] osValues = null;
         ModuleHashes hashes = null;
@@ -245,7 +243,7 @@
                     break;
 
                 case MODULE_PACKAGES :
-                    packages = readModulePackagesAttribute(in, cpool);
+                    allPackages = readModulePackagesAttribute(in, cpool);
                     break;
 
                 case MODULE_MAIN_CLASS :
@@ -284,51 +282,44 @@
             throw invalidModuleDescriptor(MODULE + " attribute not found");
         }
 
+        // ModuleMainClass and ModuleTarget attributes
+        if (mainClass != null) {
+            builder.mainClass(mainClass);
+        }
+        if (osValues != null) {
+            if (osValues[0] != null) builder.osName(osValues[0]);
+            if (osValues[1] != null) builder.osArch(osValues[1]);
+            if (osValues[2] != null) builder.osVersion(osValues[2]);
+        }
+
         // If the ModulePackages attribute is not present then the packageFinder
         // is used to find the set of packages
         boolean usedPackageFinder = false;
-        if (packages == null && packageFinder != null) {
+        if (allPackages == null && packageFinder != null) {
             try {
-                packages = new HashSet<>(packageFinder.get());
+                allPackages = packageFinder.get();
             } catch (UncheckedIOException x) {
                 throw x.getCause();
             }
             usedPackageFinder = true;
         }
-        if (packages != null) {
-            Set<String> exportedPackages = JLMA.exportedPackages(builder);
-            Set<String> openPackages = JLMA.openPackages(builder);
-            if (packages.containsAll(exportedPackages)
-                    && packages.containsAll(openPackages)) {
-                packages.removeAll(exportedPackages);
-                packages.removeAll(openPackages);
-            } else {
-                // the set of packages is not complete
-                Set<String> exportedAndOpenPackages = new HashSet<>();
-                exportedAndOpenPackages.addAll(exportedPackages);
-                exportedAndOpenPackages.addAll(openPackages);
-                for (String pn : exportedAndOpenPackages) {
-                    if (!packages.contains(pn)) {
-                        String tail;
-                        if (usedPackageFinder) {
-                            tail = " not found by package finder";
-                        } else {
-                            tail = " missing from ModulePackages attribute";
-                        }
-                        throw invalidModuleDescriptor("Package " + pn + tail);
-                    }
+        if (allPackages != null) {
+            Set<String> knownPackages = JLMA.packages(builder);
+            if (!allPackages.containsAll(knownPackages)) {
+                Set<String> missingPackages = new HashSet<>(knownPackages);
+                missingPackages.removeAll(allPackages);
+                assert !missingPackages.isEmpty();
+                String missingPackage = missingPackages.iterator().next();
+                String tail;
+                if (usedPackageFinder) {
+                    tail = " not found in module";
+                } else {
+                    tail = " missing from ModulePackages class file attribute";
                 }
-                assert false; // should not get here
+                throw invalidModuleDescriptor("Package " + missingPackage + tail);
+
             }
-            builder.contains(packages);
-        }
-
-        if (mainClass != null)
-            builder.mainClass(mainClass);
-        if (osValues != null) {
-            if (osValues[0] != null) builder.osName(osValues[0]);
-            if (osValues[1] != null) builder.osArch(osValues[1]);
-            if (osValues[2] != null) builder.osVersion(osValues[2]);
+            builder.packages(allPackages);
         }
 
         ModuleDescriptor descriptor = builder.build();
@@ -347,10 +338,17 @@
         String mn = cpool.getModuleName(module_name_index);
 
         int module_flags = in.readUnsignedShort();
+
+        Set<ModuleDescriptor.Modifier> modifiers = new HashSet<>();
         boolean open = ((module_flags & ACC_OPEN) != 0);
-        boolean synthetic = ((module_flags & ACC_SYNTHETIC) != 0);
+        if (open)
+            modifiers.add(ModuleDescriptor.Modifier.OPEN);
+        if ((module_flags & ACC_SYNTHETIC) != 0)
+            modifiers.add(ModuleDescriptor.Modifier.SYNTHETIC);
+        if ((module_flags & ACC_MANDATED) != 0)
+            modifiers.add(ModuleDescriptor.Modifier.MANDATED);
 
-        Builder builder = JLMA.newModuleBuilder(mn, false, open, synthetic);
+        Builder builder = JLMA.newModuleBuilder(mn, false, modifiers);
 
         int module_version_index = in.readUnsignedShort();
         if (module_version_index != 0) {
@@ -381,16 +379,11 @@
             }
 
             int requires_version_index = in.readUnsignedShort();
-            Version compiledVersion = null;
-            if (requires_version_index != 0) {
-                String vs = cpool.getUtf8(requires_version_index);
-                compiledVersion = Version.parse(vs);
-            }
-
-            if (compiledVersion == null) {
+            if (requires_version_index == 0) {
                 builder.requires(mods, dn);
             } else {
-                builder.requires(mods, dn, compiledVersion);
+                String vs = cpool.getUtf8(requires_version_index);
+                JLMA.requires(builder, mods, dn, vs);
             }
 
             if (dn.equals("java.base"))
@@ -629,10 +622,7 @@
 
     /**
      * Return true if the given attribute name is the name of a pre-defined
-     * attribute that is not allowed in the class file.
-     *
-     * Except for Module, InnerClasses, SourceFile, SourceDebugExtension, and
-     * Deprecated, none of the pre-defined attributes in JVMS 4.7 may appear.
+     * attribute in JVMS 4.7 that is not allowed in a module-info class.
      */
     private static boolean isAttributeDisallowed(String name) {
         Set<String> notAllowed = predefinedNotAllowed;
@@ -640,6 +630,7 @@
             notAllowed = Set.of(
                     "ConstantValue",
                     "Code",
+                    "Deprecated",
                     "StackMapTable",
                     "Exceptions",
                     "EnclosingMethod",
--- a/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java	Fri Feb 10 09:04:39 2017 +0000
@@ -56,7 +56,7 @@
     // the packages in the ModulePackages attribute
     private Set<String> packages;
 
-    // the value of the module_version in Module attribute
+    // the value for the module version in the Module attribute
     private Version version;
 
     // the value of the ModuleMainClass attribute
@@ -78,7 +78,11 @@
     }
 
     /**
-     * Sets the set of packages for the ModulePackages attribute
+     * Sets the packages for the ModulePackages attribute
+     *
+     * @apiNote This method does not check that the package names are legal
+     * package names or that the set of packages is a super set of the
+     * packages in the module.
      */
     public ModuleInfoExtender packages(Set<String> packages) {
         this.packages = Collections.unmodifiableSet(packages);
@@ -86,7 +90,7 @@
     }
 
     /**
-     * Sets the value of the module_version in Module attribute.
+     * Sets the value for the module version in the Module attribute
      */
     public ModuleInfoExtender version(Version version) {
         this.version = version;
@@ -95,6 +99,9 @@
 
     /**
      * Sets the value of the ModuleMainClass attribute.
+     *
+     * @apiNote This method does not check that the main class is a legal
+     * class name in a named package.
      */
     public ModuleInfoExtender mainClass(String mainClass) {
         this.mainClass = mainClass;
@@ -133,7 +140,7 @@
 
     /**
      * A ClassVisitor that supports adding class file attributes. If an
-     * attribute already exists then the first occurence of the attribute
+     * attribute already exists then the first occurrence of the attribute
      * is replaced.
      */
     private static class AttributeAddingClassVisitor extends ClassVisitor {
--- a/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleLoaderMap.java	Fri Feb 10 09:04:39 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 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
@@ -41,13 +41,6 @@
  * are generated at build time.
  */
 final class ModuleLoaderMap {
-    /*
-     * The list of boot modules and platform modules are generated at build time.
-     */
-    private static final String[] BOOT_MODULES
-        = new String[] { "@@BOOT_MODULE_NAMES@@" };
-    private static final String[] PLATFORM_MODULES
-        = new String[] { "@@PLATFORM_MODULE_NAMES@@" };
 
     /**
      * Returns the function to map modules in the given configuration to the
@@ -55,6 +48,10 @@
      */
     static Function<String, ClassLoader> mappingFunction(Configuration cf) {
 
+        // The list of boot modules and platform modules are generated at build time.
+        final String[] BOOT_MODULES = new String[] { "@@BOOT_MODULE_NAMES@@" };
+        final String[] PLATFORM_MODULES = new String[] { "@@PLATFORM_MODULE_NAMES@@" };
+
         Set<String> bootModules = new HashSet<>(BOOT_MODULES.length);
         for (String mn : BOOT_MODULES) {
             bootModules.add(mn);
--- a/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java	Fri Feb 10 09:04:39 2017 +0000
@@ -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
@@ -31,6 +31,7 @@
 import java.io.InputStream;
 import java.io.UncheckedIOException;
 import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Builder;
 import java.lang.module.ModuleReader;
 import java.lang.module.ModuleReference;
 import java.net.MalformedURLException;
@@ -54,6 +55,7 @@
 import java.util.stream.Stream;
 
 import jdk.internal.loader.Resource;
+import jdk.internal.loader.ResourceHelper;
 import jdk.internal.misc.JavaLangModuleAccess;
 import jdk.internal.misc.SharedSecrets;
 import sun.net.www.ParseUtil;
@@ -108,8 +110,11 @@
         if (paths == null)
             return mref;
 
-        // scan the JAR file or directory tree to get the set of packages
+        // Scan the JAR file or directory tree to get the set of packages.
+        // For automatic modules then packages that do not contain class files
+        // must be ignored.
         Set<String> packages = new HashSet<>();
+        boolean isAutomatic = descriptor.isAutomatic();
         try {
             for (Path file : paths) {
                 if (Files.isRegularFile(file)) {
@@ -118,8 +123,10 @@
                     // is not supported by the boot class loader
                     try (JarFile jf = new JarFile(file.toFile())) {
                         jf.stream()
+                          .filter(e -> !e.isDirectory()
+                                  && (!isAutomatic || e.getName().endsWith(".class")))
                           .map(e -> toPackageName(file, e))
-                          .filter(Checks::isJavaIdentifier)
+                          .filter(Checks::isPackageName)
                           .forEach(packages::add);
                     }
 
@@ -129,8 +136,10 @@
                     Path top = file;
                     Files.find(top, Integer.MAX_VALUE,
                                ((path, attrs) -> attrs.isRegularFile()))
+                            .filter(path -> !isAutomatic
+                                    || path.toString().endsWith(".class"))
                             .map(path -> toPackageName(top, path))
-                            .filter(Checks::isJavaIdentifier)
+                            .filter(Checks::isPackageName)
                             .forEach(packages::add);
 
                 }
@@ -141,10 +150,30 @@
         }
 
         // if there are new packages then we need a new ModuleDescriptor
-        Set<String> original = descriptor.packages();
-        packages.addAll(original);
-        if (packages.size() > original.size()) {
-            descriptor = JLMA.newModuleDescriptor(descriptor, packages);
+        packages.removeAll(descriptor.packages());
+        if (!packages.isEmpty()) {
+            Builder builder = JLMA.newModuleBuilder(descriptor.name(),
+                                                    /*strict*/ false,
+                                                    descriptor.modifiers());
+            if (!descriptor.isAutomatic()) {
+                descriptor.requires().forEach(builder::requires);
+                descriptor.exports().forEach(builder::exports);
+                descriptor.opens().forEach(builder::opens);
+                descriptor.uses().forEach(builder::uses);
+            }
+            descriptor.provides().forEach(builder::provides);
+
+            descriptor.version().ifPresent(builder::version);
+            descriptor.mainClass().ifPresent(builder::mainClass);
+            descriptor.osName().ifPresent(builder::osName);
+            descriptor.osArch().ifPresent(builder::osArch);
+            descriptor.osVersion().ifPresent(builder::osVersion);
+
+            // original + new packages
+            builder.packages(descriptor.packages());
+            builder.packages(packages);
+
+            descriptor = builder.build();
         }
 
         // return a module reference to the patched module
@@ -471,23 +500,14 @@
 
         @Override
         public Resource find(String name) throws IOException {
-            Path file = Paths.get(name.replace('/', File.separatorChar));
-            if (file.getRoot() == null) {
-                file = dir.resolve(file);
-            } else {
-                // drop the root component so that the resource is
-                // located relative to the module directory
-                int n = file.getNameCount();
-                if (n == 0)
-                    return null;
-                file = dir.resolve(file.subpath(0, n));
+            Path path = ResourceHelper.toFilePath(name);
+            if (path != null) {
+                Path file = dir.resolve(path);
+                if (Files.isRegularFile(file)) {
+                    return newResource(name, dir, file);
+                }
             }
-
-            if (Files.isRegularFile(file)) {
-                return newResource(name, dir, file);
-            } else {
-                return null;
-            }
+            return null;
         }
 
         private Resource newResource(String name, Path top, Path file) {
--- a/src/java.base/share/classes/jdk/internal/module/ModulePath.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ModulePath.java	Fri Feb 10 09:04:39 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, 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
@@ -35,7 +35,6 @@
 import java.lang.module.FindException;
 import java.lang.module.InvalidModuleDescriptorException;
 import java.lang.module.ModuleDescriptor;
-import java.lang.module.ModuleDescriptor.Requires;
 import java.lang.module.ModuleFinder;
 import java.lang.module.ModuleReference;
 import java.net.URI;
@@ -70,12 +69,11 @@
 
 /**
  * A {@code ModuleFinder} that locates modules on the file system by searching
- * a sequence of directories or packaged modules.
- *
- * The {@code ModuleFinder} can be created to work in either the run-time
- * or link-time phases. In both cases it locates modular JAR and exploded
- * modules. When created for link-time then it additionally locates
- * modules in JMOD files.
+ * a sequence of directories or packaged modules. The ModuleFinder can be
+ * created to work in either the run-time or link-time phases. In both cases it
+ * locates modular JAR and exploded modules. When created for link-time then it
+ * additionally locates modules in JMOD files. The ModuleFinder can also
+ * optionally patch any modules that it locates with a ModulePatcher.
  */
 
 public class ModulePath implements ModuleFinder {
@@ -87,6 +85,9 @@
     // true for the link phase (supports modules packaged in JMOD format)
     private final boolean isLinkPhase;
 
+    // for patching modules, can be null
+    private final ModulePatcher patcher;
+
     // the entries on this module path
     private final Path[] entries;
     private int next;
@@ -94,19 +95,51 @@
     // map of module name to module reference map for modules already located
     private final Map<String, ModuleReference> cachedModules = new HashMap<>();
 
-    public ModulePath(Runtime.Version version, boolean isLinkPhase, Path... entries) {
+
+    private ModulePath(Runtime.Version version,
+                       boolean isLinkPhase,
+                       ModulePatcher patcher,
+                       Path... entries) {
         this.releaseVersion = version;
         this.isLinkPhase = isLinkPhase;
+        this.patcher = patcher;
         this.entries = entries.clone();
         for (Path entry : this.entries) {
             Objects.requireNonNull(entry);
         }
     }
 
-    public ModulePath(Path... entries) {
-        this(JarFile.runtimeVersion(), false, entries);
+    /**
+     * Returns a ModuleFinder that that locates modules on the file system by
+     * searching a sequence of directories and/or packaged modules. The modules
+     * may be patched by the given ModulePatcher.
+     */
+    public static ModuleFinder of(ModulePatcher patcher, Path... entries) {
+        return new ModulePath(JarFile.runtimeVersion(), false, patcher, entries);
     }
 
+    /**
+     * Returns a ModuleFinder that that locates modules on the file system by
+     * searching a sequence of directories and/or packaged modules.
+     */
+    public static ModuleFinder of(Path... entries) {
+        return of((ModulePatcher)null, entries);
+    }
+
+    /**
+     * Returns a ModuleFinder that that locates modules on the file system by
+     * searching a sequence of directories and/or packaged modules.
+     *
+     * @param version The release version to use for multi-release JAR files
+     * @param isLinkPhase {@code true} if the link phase to locate JMOD files
+     */
+    public static ModuleFinder of(Runtime.Version version,
+                                  boolean isLinkPhase,
+                                  Path... entries) {
+        return new ModulePath(version, isLinkPhase, null, entries);
+    }
+
+
     @Override
     public Optional<ModuleReference> find(String name) {
         Objects.requireNonNull(name);
@@ -195,8 +228,7 @@
             if (attrs.isDirectory()) {
                 Path mi = entry.resolve(MODULE_INFO);
                 if (!Files.exists(mi)) {
-                    // does not exist or unable to determine so assume a
-                    // directory of modules
+                    // assume a directory of modules
                     return scanDirectory(entry);
                 }
             }
@@ -206,10 +238,16 @@
             if (mref != null) {
                 String name = mref.descriptor().name();
                 return Collections.singletonMap(name, mref);
+            }
+
+            // not recognized
+            String msg;
+            if (!isLinkPhase && entry.toString().endsWith(".jmod")) {
+                msg = "JMOD format not supported at execution time";
             } else {
-                // skipped
-                return Collections.emptyMap();
+                msg = "Module format not recognized";
             }
+            throw new FindException(msg + ": " + entry);
 
         } catch (IOException ioe) {
             throw new FindException(ioe);
@@ -266,14 +304,11 @@
 
 
     /**
-     * Locates a packaged or exploded module, returning a {@code ModuleReference}
-     * to the module. Returns {@code null} if the entry is skipped because it is
-     * to a directory that does not contain a module-info.class or it's a hidden
-     * file.
+     * Reads a packaged or exploded module, returning a {@code ModuleReference}
+     * to the module. Returns {@code null} if the entry is not recognized.
      *
      * @throws IOException if an I/O error occurs
-     * @throws FindException if the file is not recognized as a module or an
-     *         error occurs parsing its module descriptor
+     * @throws FindException if an error occurs parsing its module descriptor
      */
     private ModuleReference readModule(Path entry, BasicFileAttributes attrs)
         throws IOException
@@ -282,24 +317,16 @@
 
             if (attrs.isDirectory()) {
                 return readExplodedModule(entry); // may return null
-            }
-
-            String fn = entry.getFileName().toString();
-            if (attrs.isRegularFile()) {
-                if (fn.endsWith(".jar")) {
-                    return readJar(entry);
-                } else if (fn.endsWith(".jmod")) {
-                    if (isLinkPhase)
+            } else {
+                String fn = entry.getFileName().toString();
+                if (attrs.isRegularFile()) {
+                    if (fn.endsWith(".jar")) {
+                        return readJar(entry);
+                    } else if (isLinkPhase && fn.endsWith(".jmod")) {
                         return readJMod(entry);
-                    throw new FindException("JMOD files not supported: " + entry);
+                    }
                 }
-            }
-
-            // skip hidden files
-            if (fn.startsWith(".") || Files.isHidden(entry)) {
                 return null;
-            } else {
-                throw new FindException("Unrecognized module: " + entry);
             }
 
         } catch (InvalidModuleDescriptorException e) {
@@ -327,7 +354,7 @@
         }
     }
 
-    // -- jmod files --
+    // -- JMOD files --
 
     private Set<String> jmodPackages(JmodFile jf) {
         return jf.stream()
@@ -339,7 +366,7 @@
     }
 
     /**
-     * Returns a {@code ModuleReference} to a module in jmod file on the
+     * Returns a {@code ModuleReference} to a module in JMOD file on the
      * file system.
      *
      * @throws IOException
@@ -362,7 +389,7 @@
 
     /**
      * Returns the service type corresponding to the name of a services
-     * configuration file if it is a valid Java identifier.
+     * configuration file if it is a legal type name.
      *
      * For example, if called with "META-INF/services/p.S" then this method
      * returns a container with the value "p.S".
@@ -374,7 +401,7 @@
             String prefix = cf.substring(0, index);
             if (prefix.equals(SERVICES_PREFIX)) {
                 String sn = cf.substring(index);
-                if (Checks.isJavaIdentifier(sn))
+                if (Checks.isClassName(sn))
                     return Optional.of(sn);
             }
         }
@@ -403,11 +430,10 @@
      *
      * 1. The module name (and optionally the version) is derived from the file
      *    name of the JAR file
-     * 2. All packages are exported and open
-     * 3. It has no non-exported/non-open packages
-     * 4. The contents of any META-INF/services configuration files are mapped
+     * 2. All packages are derived from the .class files in the JAR file
+     * 3. The contents of any META-INF/services configuration files are mapped
      *    to "provides" declarations
-     * 5. The Main-Class attribute in the main attributes of the JAR manifest
+     * 4. The Main-Class attribute in the main attributes of the JAR manifest
      *    is mapped to the module descriptor mainClass
      */
     private ModuleDescriptor deriveModuleDescriptor(JarFile jf)
@@ -443,9 +469,7 @@
         mn = cleanModuleName(mn);
 
         // Builder throws IAE if module name is empty or invalid
-        ModuleDescriptor.Builder builder
-            = ModuleDescriptor.automaticModule(mn)
-                .requires(Set.of(Requires.Modifier.MANDATED), "java.base");
+        ModuleDescriptor.Builder builder = ModuleDescriptor.newAutomaticModule(mn);
         if (vs != null)
             builder.version(vs);
 
@@ -453,17 +477,22 @@
         Map<Boolean, Set<String>> map = VersionedStream.stream(jf)
                 .filter(e -> !e.isDirectory())
                 .map(JarEntry::getName)
+                .filter(e -> (e.endsWith(".class") ^ e.startsWith(SERVICES_PREFIX)))
                 .collect(Collectors.partitioningBy(e -> e.startsWith(SERVICES_PREFIX),
                                                    Collectors.toSet()));
 
-        Set<String> resources = map.get(Boolean.FALSE);
+        Set<String> classFiles = map.get(Boolean.FALSE);
         Set<String> configFiles = map.get(Boolean.TRUE);
-        // all packages are exported and open
-        resources.stream()
+
+        // the packages containing class files
+        Set<String> packages = classFiles.stream()
                 .map(this::toPackageName)
                 .flatMap(Optional::stream)
                 .distinct()
-                .forEach(pn -> builder.exports(pn).opens(pn));
+                .collect(Collectors.toSet());
+
+        // all packages are exported and open
+        builder.packages(packages);
 
         // map names of service configuration files to service names
         Set<String> serviceNames = configFiles.stream()
@@ -481,6 +510,11 @@
                 String cn;
                 while ((cn = nextLine(reader)) != null) {
                     if (cn.length() > 0) {
+                        String pn = packageName(cn);
+                        if (!packages.contains(pn)) {
+                            String msg = "Provider class " + cn + " not in module";
+                            throw new IOException(msg);
+                        }
                         providerClasses.add(cn);
                     }
                 }
@@ -494,8 +528,15 @@
         if (man != null) {
             Attributes attrs = man.getMainAttributes();
             String mainClass = attrs.getValue(Attributes.Name.MAIN_CLASS);
-            if (mainClass != null)
-                builder.mainClass(mainClass.replace("/", "."));
+            if (mainClass != null) {
+                mainClass = mainClass.replace("/", ".");
+                String pn = packageName(mainClass);
+                if (!packages.contains(pn)) {
+                    String msg = "Main-Class " + mainClass + " not in module";
+                    throw new IOException(msg);
+                }
+                builder.mainClass(mainClass);
+            }
         }
 
         return builder.build();
@@ -569,10 +610,10 @@
                 try {
                     ModuleDescriptor md = deriveModuleDescriptor(jf);
                     attrs = new ModuleInfo.Attributes(md, null, null);
-                } catch (IllegalArgumentException iae) {
+                } catch (IllegalArgumentException e) {
                     throw new FindException(
                         "Unable to derive module descriptor for: "
-                        + jf.getName(), iae);
+                        + jf.getName(), e);
                 }
 
             } else {
@@ -580,7 +621,7 @@
                                         () -> jarPackages(jf));
             }
 
-            return ModuleReferences.newJarModule(attrs, file);
+            return ModuleReferences.newJarModule(attrs, patcher, file);
         }
     }
 
@@ -617,7 +658,15 @@
             // for now
             return null;
         }
-        return ModuleReferences.newExplodedModule(attrs, dir);
+        return ModuleReferences.newExplodedModule(attrs, patcher, dir);
+    }
+
+    /**
+     * Maps a type name to its package name.
+     */
+    private static String packageName(String cn) {
+        int index = cn.lastIndexOf('.');
+        return (index == -1) ? "" : cn.substring(0, index);
     }
 
     /**
@@ -629,19 +678,18 @@
      */
     private Optional<String> toPackageName(String name) {
         assert !name.endsWith("/");
-
         int index = name.lastIndexOf("/");
         if (index == -1) {
             if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
                 throw new IllegalArgumentException(name
-                        + " found in top-level directory:"
+                        + " found in top-level directory"
                         + " (unnamed package not allowed in module)");
             }
             return Optional.empty();
         }
 
         String pn = name.substring(0, index).replace('/', '.');
-        if (Checks.isJavaIdentifier(pn)) {
+        if (Checks.isPackageName(pn)) {
             return Optional.of(pn);
         } else {
             // not a valid package name
@@ -654,7 +702,7 @@
      * name.
      *
      * @throws IllegalArgumentException if the name is a class file in
-     *         the top-level directory (and it's not module-info.class)
+     *          the top-level directory (and it's not module-info.class)
      */
     private Optional<String> toPackageName(Path file) {
         assert file.getRoot() == null;
@@ -664,14 +712,14 @@
             String name = file.toString();
             if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
                 throw new IllegalArgumentException(name
-                        + " found in in top-level directory"
+                        + " found in top-level directory"
                         + " (unnamed package not allowed in module)");
             }
             return Optional.empty();
         }
 
         String pn = parent.toString().replace(File.separatorChar, '.');
-        if (Checks.isJavaIdentifier(pn)) {
+        if (Checks.isPackageName(pn)) {
             return Optional.of(pn);
         } else {
             // not a valid package name
--- a/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java	Fri Feb 10 09:04:39 2017 +0000
@@ -163,7 +163,14 @@
 
     @Override
     public String toString() {
-        return super.toString();
+        StringBuilder sb = new StringBuilder();
+        sb.append("[module ");
+        sb.append(descriptor().name());
+        sb.append(", location=");
+        sb.append(location().orElseThrow(() -> new InternalError()));
+        if (isPatched()) sb.append(" (patched)");
+        sb.append("]");
+        return sb.toString();
     }
 
 }
--- a/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java	Fri Feb 10 09:04:39 2017 +0000
@@ -36,7 +36,6 @@
 import java.nio.ByteBuffer;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
@@ -51,7 +50,7 @@
 import java.util.zip.ZipFile;
 
 import jdk.internal.jmod.JmodFile;
-import jdk.internal.misc.JavaLangAccess;
+import jdk.internal.loader.ResourceHelper;
 import jdk.internal.misc.SharedSecrets;
 import jdk.internal.module.ModuleHashes.HashSupplier;
 import jdk.internal.util.jar.VersionedStream;
@@ -65,20 +64,16 @@
  */
 
 class ModuleReferences {
-
-    private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
-
     private ModuleReferences() { }
 
     /**
-     * Creates a ModuleReference to a module or to patched module when
-     * creating modules for the boot Layer and --patch-module is specified.
+     * Creates a ModuleReference to a possibly-patched module
      */
     private static ModuleReference newModule(ModuleInfo.Attributes attrs,
                                              URI uri,
                                              Supplier<ModuleReader> supplier,
+                                             ModulePatcher patcher,
                                              HashSupplier hasher) {
-
         ModuleReference mref = new ModuleReferenceImpl(attrs.descriptor(),
                                                        uri,
                                                        supplier,
@@ -86,38 +81,42 @@
                                                        attrs.recordedHashes(),
                                                        hasher,
                                                        attrs.moduleResolution());
-        if (JLA.getBootLayer() == null)
-            mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
+        if (patcher != null)
+            mref = patcher.patchIfNeeded(mref);
 
         return mref;
     }
 
     /**
-     * Creates a ModuleReference to a module packaged as a modular JAR.
+     * Creates a ModuleReference to a possibly-patched module in a modular JAR.
      */
-    static ModuleReference newJarModule(ModuleInfo.Attributes attrs, Path file) {
+    static ModuleReference newJarModule(ModuleInfo.Attributes attrs,
+                                        ModulePatcher patcher,
+                                        Path file) {
         URI uri = file.toUri();
         Supplier<ModuleReader> supplier = () -> new JarModuleReader(file, uri);
         HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
-        return newModule(attrs, uri, supplier, hasher);
+        return newModule(attrs, uri, supplier, patcher, hasher);
     }
 
     /**
-     * Creates a ModuleReference to a module packaged as a JMOD.
+     * Creates a ModuleReference to a module in a JMOD file.
      */
     static ModuleReference newJModModule(ModuleInfo.Attributes attrs, Path file) {
         URI uri = file.toUri();
         Supplier<ModuleReader> supplier = () -> new JModModuleReader(file, uri);
         HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
-        return newModule(attrs, uri, supplier, hasher);
+        return newModule(attrs, uri, supplier, null, hasher);
     }
 
     /**
-     * Creates a ModuleReference to an exploded module.
+     * Creates a ModuleReference to a possibly-patched exploded module.
      */
-    static ModuleReference newExplodedModule(ModuleInfo.Attributes attrs, Path dir) {
+    static ModuleReference newExplodedModule(ModuleInfo.Attributes attrs,
+                                             ModulePatcher patcher,
+                                             Path dir) {
         Supplier<ModuleReader> supplier = () -> new ExplodedModuleReader(dir);
-        return newModule(attrs, dir.toUri(), supplier, null);
+        return newModule(attrs, dir.toUri(), supplier, patcher, null);
     }
 
 
@@ -243,7 +242,8 @@
         }
 
         private JarEntry getEntry(String name) {
-            return jf.getJarEntry(Objects.requireNonNull(name));
+            JarEntry entry = jf.getJarEntry(Objects.requireNonNull(name));
+            return (entry == null || entry.isDirectory()) ? null : entry;
         }
 
         @Override
@@ -370,32 +370,33 @@
         }
 
         /**
-         * Returns a Path to access to the given resource.
-         */
-        private Path toPath(String name) {
-            Path path = Paths.get(name.replace('/', File.separatorChar));
-            if (path.getRoot() == null) {
-                return dir.resolve(path);
-            } else {
-                // drop the root component so that the resource is
-                // located relative to the module directory
-                int n = path.getNameCount();
-                return (n > 0) ? dir.resolve(path.subpath(0, n)) : null;
-            }
-        }
-
-        /**
          * Throws IOException if the module reader is closed;
          */
         private void ensureOpen() throws IOException {
             if (closed) throw new IOException("ModuleReader is closed");
         }
 
+        /**
+         * Returns a Path to access the given resource. Returns null if the
+         * resource name does not convert to a file path that locates a regular
+         * file in the module.
+         */
+        private Path toFilePath(String name) {
+            Path path = ResourceHelper.toFilePath(name);
+            if (path != null) {
+                Path file = dir.resolve(path);
+                if (Files.isRegularFile(file)) {
+                    return file;
+                }
+            }
+            return null;
+        }
+
         @Override
         public Optional<URI> find(String name) throws IOException {
             ensureOpen();
-            Path path = toPath(name);
-            if (path != null && Files.isRegularFile(path)) {
+            Path path = toFilePath(name);
+            if (path != null) {
                 try {
                     return Optional.of(path.toUri());
                 } catch (IOError e) {
@@ -409,8 +410,8 @@
         @Override
         public Optional<InputStream> open(String name) throws IOException {
             ensureOpen();
-            Path path = toPath(name);
-            if (path != null && Files.isRegularFile(path)) {
+            Path path = toFilePath(name);
+            if (path != null) {
                 return Optional.of(Files.newInputStream(path));
             } else {
                 return Optional.empty();
@@ -420,8 +421,8 @@
         @Override
         public Optional<ByteBuffer> read(String name) throws IOException {
             ensureOpen();
-            Path path = toPath(name);
-            if (path != null && Files.isRegularFile(path)) {
+            Path path = toFilePath(name);
+            if (path != null) {
                 return Optional.of(ByteBuffer.wrap(Files.readAllBytes(path)));
             } else {
                 return Optional.empty();
--- a/src/java.base/share/classes/jdk/internal/module/Modules.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/Modules.java	Fri Feb 10 09:04:39 2017 +0000
@@ -82,8 +82,8 @@
                                       String name,
                                       Set<String> packages)
     {
-        ModuleDescriptor descriptor = ModuleDescriptor.module(name)
-                .contains(packages)
+        ModuleDescriptor descriptor = ModuleDescriptor.newModule(name)
+                .packages(packages)
                 .build();
 
         return JLRMA.defineModule(loader, descriptor, null);
@@ -185,7 +185,8 @@
     /**
      * Adds a package to a module's content.
      *
-     * This method is a no-op if the module already contains the package.
+     * This method is a no-op if the module already contains the package or the
+     * module is an unnamed module.
      */
     public static void addPackage(Module m, String pn) {
         JLRMA.addPackage(m, pn);
--- a/src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java	Fri Feb 10 09:04:39 2017 +0000
@@ -80,8 +80,6 @@
         = PerfCounter.newPerfCounter("jdk.module.finder.jimage.packages");
     private static final PerfCounter exportsCount
         = PerfCounter.newPerfCounter("jdk.module.finder.jimage.exports");
-    // ImageReader used to access all modules in the image
-    private static final ImageReader imageReader;
 
     // singleton finder to find modules in the run-time images
     private static final SystemModuleFinder INSTANCE;
@@ -96,13 +94,28 @@
      */
     static {
         long t0 = System.nanoTime();
-        imageReader = ImageReaderFactory.getImageReader();
 
         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;
     }
@@ -114,7 +127,7 @@
 
         // this happens when java.base is patched with java.base
         // from an exploded image
-        return imageReader.getModuleNames();
+        return SystemImage.reader().getModuleNames();
     }
 
     // the set of modules in the run-time image
@@ -151,6 +164,7 @@
             descriptors = new ModuleDescriptor[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");
@@ -291,6 +305,7 @@
             Objects.requireNonNull(name);
             if (closed)
                 throw new IOException("ModuleReader is closed");
+            ImageReader imageReader = SystemImage.reader();
             if (imageReader != null) {
                 return imageReader.findLocation(module, name);
             } else {
@@ -330,7 +345,7 @@
         public Optional<ByteBuffer> read(String name) throws IOException {
             ImageLocation location = findImageLocation(name);
             if (location != null) {
-                return Optional.of(imageReader.getResourceBuffer(location));
+                return Optional.of(SystemImage.reader().getResourceBuffer(location));
             } else {
                 return Optional.empty();
             }
@@ -372,7 +387,7 @@
             stack = new ArrayDeque<>();
 
             // push the root node to the stack to get started
-            ImageReader.Node dir = imageReader.findNode(moduleRoot);
+            ImageReader.Node dir = SystemImage.reader().findNode(moduleRoot);
             if (dir == null || !dir.isDirectory())
                 throw new IOException(moduleRoot + " not a directory");
             stack.push(dir);
@@ -390,7 +405,7 @@
                     String name = node.getName();
                     if (node.isDirectory()) {
                         // build node
-                        ImageReader.Node dir = imageReader.findNode(name);
+                        ImageReader.Node dir = SystemImage.reader().findNode(name);
                         assert dir.isDirectory();
                         stack.push(dir);
                     } else {
--- a/src/java.base/share/classes/jdk/internal/reflect/Reflection.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/reflect/Reflection.java	Fri Feb 10 09:04:39 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2013, 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
@@ -211,15 +211,7 @@
         if (currentModule == memberModule)
            return true;  // same module (named or unnamed)
 
-        // memberClass may be primitive or array class
-        Class<?> c = memberClass;
-        while (c.isArray()) {
-            c = c.getComponentType();
-        }
-        if (c.isPrimitive())
-            return true;
-
-        String pkg = c.getPackageName();
+        String pkg = memberClass.getPackageName();
         boolean allowed = memberModule.isExported(pkg, currentModule);
         if (allowed && memberModule.isNamed() && printStackTraceWhenAccessSucceeds()) {
             if (!SharedSecrets.getJavaLangReflectModuleAccess()
@@ -237,10 +229,6 @@
     private static boolean isSameClassPackage(Class<?> c1, Class<?> c2) {
         if (c1.getClassLoader() != c2.getClassLoader())
             return false;
-        while (c1.isArray())
-            c1 = c1.getComponentType();
-        while (c2.isArray())
-            c2 = c2.getComponentType();
         return Objects.equals(c1.getPackageName(), c2.getPackageName());
     }
 
@@ -378,12 +366,6 @@
         }
     }
 
-    public static void enableStackTraces() {
-        printStackWhenAccessFails = true;
-        printStackWhenAccessSucceeds = true;
-        printStackPropertiesSet = true;
-    }
-
     public static boolean printStackTraceWhenAccessFails() {
         ensurePrintStackPropertiesSet();
         return printStackWhenAccessFails;
@@ -413,11 +395,7 @@
         if (m2.isNamed())
             memberSuffix = " (in " + m2 + ")";
 
-        Class<?> c = memberClass;
-        while (c.isArray()) {
-            c = c.getComponentType();
-        }
-        String memberPackageName = c.getPackageName();
+        String memberPackageName = memberClass.getPackageName();
 
         String msg = currentClass + currentSuffix + " cannot access ";
         if (m2.isExported(memberPackageName, m1)) {
--- a/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java	Fri Feb 10 09:04:39 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 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
@@ -39,6 +39,7 @@
 
     private VerifyAccess() { }  // cannot instantiate
 
+    private static final int UNCONDITIONAL_ALLOWED = java.lang.invoke.MethodHandles.Lookup.UNCONDITIONAL;
     private static final int MODULE_ALLOWED = java.lang.invoke.MethodHandles.Lookup.MODULE;
     private static final int PACKAGE_ONLY = 0;
     private static final int PACKAGE_ALLOWED = java.lang.invoke.MethodHandles.Lookup.PACKAGE;
@@ -92,7 +93,7 @@
                                              int      allowedModes) {
         if (allowedModes == 0)  return false;
         assert((allowedModes & PUBLIC) != 0 &&
-               (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED)) == 0);
+               (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED|UNCONDITIONAL_ALLOWED)) == 0);
         // The symbolic reference class (refc) must always be fully verified.
         if (!isClassAccessible(refc, lookupClass, allowedModes)) {
             return false;
@@ -173,7 +174,7 @@
                                             int allowedModes) {
         if (allowedModes == 0)  return false;
         assert((allowedModes & PUBLIC) != 0 &&
-               (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED)) == 0);
+               (allowedModes & ~(ALL_ACCESS_MODES|PACKAGE_ALLOWED|MODULE_ALLOWED|UNCONDITIONAL_ALLOWED)) == 0);
         int mods = getClassModifiers(refc);
         if (isPublic(mods)) {
 
@@ -191,22 +192,17 @@
                 (lookupModule == refModule))
                 return true;
 
-            // check readability
-            if (lookupModule.canRead(refModule)) {
+            // check readability when UNCONDITIONAL not allowed
+            if (((allowedModes & UNCONDITIONAL_ALLOWED) != 0)
+                || lookupModule.canRead(refModule)) {
 
                 // check that refc is in an exported package
-                Class<?> c = refc;
-                while (c.isArray()) {
-                    c = c.getComponentType();
-                }
-                if (c.isPrimitive())
-                    return true;
                 if ((allowedModes & MODULE_ALLOWED) != 0) {
-                    if (refModule.isExported(c.getPackageName(), lookupModule))
+                    if (refModule.isExported(refc.getPackageName(), lookupModule))
                         return true;
                 } else {
                     // exported unconditionally
-                    if (refModule.isExported(c.getPackageName()))
+                    if (refModule.isExported(refc.getPackageName()))
                         return true;
                 }
 
--- a/src/java.base/share/classes/sun/launcher/LauncherHelper.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/sun/launcher/LauncherHelper.java	Fri Feb 10 09:04:39 2017 +0000
@@ -966,6 +966,10 @@
                     ostream.print("open ");
                 if (md.isAutomatic())
                     ostream.print("automatic ");
+                if (md.modifiers().contains(ModuleDescriptor.Modifier.SYNTHETIC))
+                    ostream.print("synthetic ");
+                if (md.modifiers().contains(ModuleDescriptor.Modifier.MANDATED))
+                    ostream.print("mandated ");
                 ostream.println("module " + midAndLocation(md, mref.location()));
 
                 // unqualified exports (sorted by package)
--- a/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java	Fri Feb 10 09:04:39 2017 +0000
@@ -32,7 +32,9 @@
 import java.io.InputStream;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.security.AccessController;
 import java.security.Permission;
+import java.security.PrivilegedAction;
 
 import jdk.internal.jimage.ImageLocation;
 import jdk.internal.jimage.ImageReader;
@@ -51,7 +53,11 @@
 public class JavaRuntimeURLConnection extends URLConnection {
 
     // ImageReader to access resources in jimage
-    private static final ImageReader reader = ImageReaderFactory.getImageReader();
+    private static final ImageReader reader;
+    static {
+        PrivilegedAction<ImageReader> pa = ImageReaderFactory::getImageReader;
+        reader = AccessController.doPrivileged(pa);
+    }
 
     // the module and resource name in the URL
     private final String module;
--- a/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java	Fri Feb 10 09:04:39 2017 +0000
@@ -229,6 +229,7 @@
      *         or {@code null} if no transform is performed
      *
      * @since  9
+     * @spec JPMS
      */
     default byte[]
     transform(  Module              module,
--- a/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.instrument/share/classes/java/lang/instrument/Instrumentation.java	Fri Feb 10 09:04:39 2017 +0000
@@ -714,6 +714,7 @@
      * @throws NullPointerException if any of the arguments are {@code null} or
      *         any of the Sets or Maps contains a {@code null} key or value
      * @since 9
+     * @spec JPMS
      */
     void redefineModule(Module module,
                         Set<Module> extraReads,
--- a/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnector.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnector.java	Fri Feb 10 09:04:39 2017 +0000
@@ -38,6 +38,7 @@
 import java.io.ObjectInputStream;
 import java.io.ObjectStreamClass;
 import java.io.Serializable;
+import java.lang.module.ModuleDescriptor;
 import java.lang.ref.WeakReference;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationHandler;
@@ -107,6 +108,8 @@
 import sun.rmi.transport.LiveRef;
 import java.io.NotSerializableException;
 
+import static java.lang.module.ModuleDescriptor.Modifier.SYNTHETIC;
+
 /**
  * <p>A connection to a remote RMI connector.  Usually, such
  * connections are made using {@link
@@ -2020,8 +2023,14 @@
                 Module rmiModule = RemoteRef.class.getModule();
 
                 String pkg = packageOf(pRefClassName);
-                assert pkg != null && pkg.length() > 0 && !pkg.equals(packageOf(proxyRefCName));
-                Module m = Modules.defineModule(cl, "jdk.remoteref", Collections.singleton(pkg));
+                assert pkg != null && pkg.length() > 0 &&
+                        !pkg.equals(packageOf(proxyRefCName));
+
+                ModuleDescriptor descriptor =
+                    ModuleDescriptor.newModule("jdk.remoteref", Set.of(SYNTHETIC))
+                        .packages(Set.of(pkg))
+                        .build();
+                Module m = Modules.defineModule(cl, descriptor, null);
 
                 // jdk.remoteref needs to read to java.base and jmxModule
                 Modules.addReads(m, Object.class.getModule());
--- a/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java	Fri Feb 10 09:04:39 2017 +0000
@@ -157,8 +157,7 @@
                     for (String dir : dirs) {
                         paths[i++] = Paths.get(dir);
                     }
-                    jartool.moduleFinder =
-                        new ModulePath(Runtime.version(), true, paths);
+                    jartool.moduleFinder = ModulePath.of(Runtime.version(), true, paths);
                 }
             },
             new Option(false, OptionType.CREATE_UPDATE, "--do-not-resolve-by-default") {
--- a/src/jdk.jartool/share/classes/sun/tools/jar/Main.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/jdk.jartool/share/classes/sun/tools/jar/Main.java	Fri Feb 10 09:04:39 2017 +0000
@@ -699,7 +699,7 @@
         }
         String pn = toPackageName(name);
         // add if this is a class or resource in a package
-        if (Checks.isJavaIdentifier(pn)) {
+        if (Checks.isPackageName(pn)) {
             packages.add(pn);
         }
     }
@@ -1995,7 +1995,7 @@
             }
             // get a resolved module graph
             Configuration config =
-                Configuration.empty().resolveRequires(system, finder, roots);
+                Configuration.empty().resolve(system, finder, roots);
 
             // filter modules resolved from the system module finder
             this.modules = config.modules().stream()
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java	Fri Feb 10 09:04:39 2017 +0000
@@ -29,6 +29,7 @@
 import java.io.PrintWriter;
 import java.io.UncheckedIOException;
 import java.lang.module.Configuration;
+import java.lang.module.FindException;
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleFinder;
 import java.lang.module.ModuleReference;
@@ -232,7 +233,7 @@
 
             return EXIT_OK;
         } catch (PluginException | IllegalArgumentException |
-                 UncheckedIOException |IOException | ResolutionException e) {
+                 UncheckedIOException |IOException | FindException | ResolutionException e) {
             log.println(taskHelper.getMessage("error.prefix") + " " + e.getMessage());
             if (DEBUG) {
                 e.printStackTrace(log);
@@ -370,7 +371,7 @@
      */
     private ModuleFinder modulePathFinder() {
         Path[] entries = options.modulePath.toArray(new Path[0]);
-        ModuleFinder finder = new ModulePath(Runtime.version(), true, entries);
+        ModuleFinder finder = ModulePath.of(Runtime.version(), true, entries);
         if (!options.limitMods.isEmpty()) {
             finder = limitFinder(finder, options.limitMods, Collections.emptySet());
         }
@@ -388,7 +389,7 @@
                                                Set<String> roots)
     {
         Path[] entries = paths.toArray(new Path[0]);
-        ModuleFinder finder = new ModulePath(Runtime.version(), true, entries);
+        ModuleFinder finder = ModulePath.of(Runtime.version(), true, entries);
 
         // if limitmods is specified then limit the universe
         if (!limitMods.isEmpty()) {
@@ -418,9 +419,9 @@
         }
 
         Configuration cf = Configuration.empty()
-                .resolveRequires(finder,
-                                 ModuleFinder.of(),
-                                 roots);
+                .resolve(finder,
+                         ModuleFinder.of(),
+                         roots);
 
         // emit warning for modules that end with a digit
         cf.modules().stream()
@@ -458,9 +459,9 @@
 
         // resolve all root modules
         Configuration cf = Configuration.empty()
-                .resolveRequires(finder,
-                                 ModuleFinder.of(),
-                                 roots);
+                .resolve(finder,
+                         ModuleFinder.of(),
+                         roots);
 
         // module name -> reference
         Map<String, ModuleReference> map = new HashMap<>();
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java	Fri Feb 10 09:04:39 2017 +0000
@@ -51,7 +51,7 @@
         ModuleDescriptor md = mod.descriptor();
 
         // drop hashes
-        ModuleDescriptor.Builder builder = ModuleDescriptor.module(md.name());
+        ModuleDescriptor.Builder builder = ModuleDescriptor.newModule(md.name());
         md.requires().stream()
           .forEach(builder::requires);
         md.exports().stream()
@@ -62,12 +62,7 @@
           .forEach(builder::uses);
         md.provides().stream()
           .forEach(builder::provides);
-
-        // build the proper concealed packages
-        Set<String> concealed = new HashSet<>(mod.packages());
-        md.exports().stream().map(ModuleDescriptor.Exports::source).forEach(concealed::remove);
-        md.opens().stream().map(ModuleDescriptor.Opens::source).forEach(concealed::remove);
-        concealed.stream().forEach(builder::contains);
+        builder.packages(md.packages());
 
         md.version().ifPresent(builder::version);
         md.mainClass().ifPresent(builder::mainClass);
@@ -124,7 +119,7 @@
             }
         };
 
-        return Configuration.empty().resolveRequires(
+        return Configuration.empty().resolve(
             finder, ModuleFinder.of(), nameToModRef.keySet());
     }
 }
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java	Fri Feb 10 09:04:39 2017 +0000
@@ -718,13 +718,13 @@
     static Layer createPluginsLayer(List<Path> paths) {
 
         Path[] dirs = paths.toArray(new Path[0]);
-        ModuleFinder finder = new ModulePath(Runtime.version(), true, dirs);
+        ModuleFinder finder = ModulePath.of(Runtime.version(), true, dirs);
         Configuration bootConfiguration = Layer.boot().configuration();
         try {
             Configuration cf = bootConfiguration
-                .resolveRequiresAndUses(ModuleFinder.of(),
-                                        finder,
-                                        Collections.emptySet());
+                .resolveAndBind(ModuleFinder.of(),
+                                finder,
+                                Collections.emptySet());
             ClassLoader scl = ClassLoader.getSystemClassLoader();
             return Layer.boot().defineModulesWithOneLoader(cf, scl);
         } catch (Exception ex) {
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java	Fri Feb 10 09:04:39 2017 +0000
@@ -771,9 +771,12 @@
                 if (md.isOpen()) {
                     setModuleBit("open", true);
                 }
-                if (md.isSynthetic()) {
+                if (md.modifiers().contains(ModuleDescriptor.Modifier.SYNTHETIC)) {
                     setModuleBit("synthetic", true);
                 }
+                if (md.modifiers().contains(ModuleDescriptor.Modifier.MANDATED)) {
+                    setModuleBit("mandated", true);
+                }
             }
 
             /*
--- a/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java	Fri Feb 10 09:04:39 2017 +0000
@@ -34,6 +34,7 @@
 import java.io.PrintWriter;
 import java.io.UncheckedIOException;
 import java.lang.module.Configuration;
+import java.lang.module.FindException;
 import java.lang.module.ModuleReader;
 import java.lang.module.ModuleReference;
 import java.lang.module.ModuleFinder;
@@ -851,8 +852,8 @@
             // get a resolved module graph
             Configuration config = null;
             try {
-                config = Configuration.empty().resolveRequires(system, finder, roots);
-            } catch (ResolutionException e) {
+                config = Configuration.empty().resolve(system, finder, roots);
+            } catch (FindException | ResolutionException e) {
                 throw new CommandException("err.module.resolution.fail", e.getMessage());
             }
 
@@ -1392,7 +1393,7 @@
                 options.legalNotices = getLastElement(opts.valuesOf(legalNotices));
             if (opts.has(modulePath)) {
                 Path[] dirs = getLastElement(opts.valuesOf(modulePath)).toArray(new Path[0]);
-                options.moduleFinder = new ModulePath(Runtime.version(), true, dirs);
+                options.moduleFinder = ModulePath.of(Runtime.version(), true, dirs);
             }
             if (opts.has(moduleVersion))
                 options.moduleVersion = getLastElement(opts.valuesOf(moduleVersion));
--- a/test/ProblemList.txt	Thu Feb 09 17:21:47 2017 +0000
+++ b/test/ProblemList.txt	Fri Feb 10 09:04:39 2017 +0000
@@ -296,6 +296,8 @@
 
 sun/tools/jcmd/TestJcmdSanity.java                              8031482 windows-all
 
+sun/tools/jstat/jstatClassloadOutput1.sh                        8173942 generic-all
+
 sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java    8057732 generic-all
 
 demo/jvmti/compiledMethodLoad/CompiledMethodLoadTest.java       8151899 generic-all
--- a/test/java/io/FilePermission/ReadFileOnPath.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/test/java/io/FilePermission/ReadFileOnPath.java	Fri Feb 10 09:04:39 2017 +0000
@@ -57,7 +57,7 @@
                 "module-info.class", "base", "p/App.class", "p/child");
 
         // exploded module
-        test("--module-path", "modules", "-m", "m/p.App", "SS+++++");
+        test("--module-path", "modules", "-m", "m/p.App", "SS++++0");
 
         // module in jar
         test("--module-path", "new.jar", "-m", "m/p.App", "SSSS++0");
--- a/test/java/lang/Class/forName/modules/TestLayer.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/test/java/lang/Class/forName/modules/TestLayer.java	Fri Feb 10 09:04:39 2017 +0000
@@ -46,9 +46,9 @@
         ModuleFinder finder = ModuleFinder.of(MODS_DIR);
 
         Configuration parent = Layer.boot().configuration();
-        Configuration cf = parent.resolveRequiresAndUses(ModuleFinder.of(),
-                                                         finder,
-                                                         modules);
+        Configuration cf = parent.resolveAndBind(ModuleFinder.of(),
+                                                 finder,
+                                                 modules);
 
         ClassLoader scl = ClassLoader.getSystemClassLoader();
         Layer layer = Layer.boot().defineModulesWithManyLoaders(cf, scl);
--- a/test/java/lang/Class/forName/modules/src/m3/p3/NoAccess.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/test/java/lang/Class/forName/modules/src/m3/p3/NoAccess.java	Fri Feb 10 09:04:39 2017 +0000
@@ -50,9 +50,9 @@
         Layer bootLayer = Layer.boot();
         Configuration parent = bootLayer.configuration();
 
-        Configuration cf = parent.resolveRequiresAndUses(finder,
-                                                         ModuleFinder.of(),
-                                                         Set.of("m1", "m2"));
+        Configuration cf = parent.resolveAndBind(finder,
+                                                 ModuleFinder.of(),
+                                                 Set.of("m1", "m2"));
 
         ClassLoader scl = ClassLoader.getSystemClassLoader();
         Layer layer = bootLayer.defineModulesWithManyLoaders(cf, scl);
--- a/test/java/lang/Class/getPackageName/Basic.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/test/java/lang/Class/getPackageName/Basic.java	Fri Feb 10 09:04:39 2017 +0000
@@ -154,8 +154,8 @@
         return new Object[][] {
 
             { Basic.class,                  TEST_PACKAGE },
-            { Basic[].class,                null },
-            { Basic[][].class,              null },
+            { Basic[].class,                TEST_PACKAGE },
+            { Basic[][].class,              TEST_PACKAGE },
 
             { getNestedClass1(),            TEST_PACKAGE },
             { getNestedClass2(),            TEST_PACKAGE },
@@ -174,14 +174,14 @@
             { getAnonymousClass6(),         TEST_PACKAGE },
 
             { Object.class,                 "java.lang" },
-            { Object[].class,               null },
-            { Object[][].class,             null },
+            { Object[].class,               "java.lang" },
+            { Object[][].class,             "java.lang" },
 
-            { int.class,                    null },
-            { int[].class,                  null },
-            { int[][].class,                null },
+            { int.class,                    "java.lang" },
+            { int[].class,                  "java.lang" },
+            { int[][].class,                "java.lang" },
 
-            { void.class,                   null },
+            { void.class,                   "java.lang" },
 
         };
     }
--- a/test/java/lang/StackWalker/CallerFromMain.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/test/java/lang/StackWalker/CallerFromMain.java	Fri Feb 10 09:04:39 2017 +0000
@@ -51,7 +51,7 @@
         try {
             Class<?> c = sw.getCallerClass();
             throw new RuntimeException("UOE not thrown. Caller: " + c);
-        } catch (IllegalStateException e) {}
+        } catch (IllegalCallerException e) {}
 
         // StackWalker::getCallerClass
         // Runnable::run
--- a/test/java/lang/invoke/AccessControlTest.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/test/java/lang/invoke/AccessControlTest.java	Fri Feb 10 09:04:39 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 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
@@ -118,6 +118,8 @@
                 suffix = "/noaccess";
             else if (lookupModes == PUBLIC)
                 suffix = "/public";
+             else if (lookupModes == (PUBLIC|UNCONDITIONAL))
+                suffix = "/publicLookup";
             else if (lookupModes == (PUBLIC|MODULE))
                 suffix = "/module";
             else if (lookupModes == (PUBLIC|MODULE|PACKAGE))
@@ -140,23 +142,24 @@
          * [A2] However, the resulting {@code Lookup} object is guaranteed
          * to have no more access capabilities than the original.
          * In particular, access capabilities can be lost as follows:<ul>
-         * <li>[A3] If the new lookup class differs from the old one,
-         * protected members will not be accessible by virtue of inheritance.
+         * <li> [A3] If the old lookup class is in a named module, and the new
+         * lookup class is in a different module {@code M}, then no members, not
+         * even public members in {@code M}'s exported packages, will be accessible.
+         * The exception to this is when this lookup is publicLookup, in which case
+         * public access is not lost.
+         * <li> [A4] If the old lookup class is in an unnamed module, and the new
+         * lookup class is a different module then module access is lost.
+         * <li> [A5] If the new lookup class differs from the old one then UNCONDITIONAL
+         * is lost. If the new lookup class is not within the same package member as the
+         * old one, protected members will not be accessible by virtue of inheritance.
          * (Protected members may continue to be accessible because of package sharing.)
-         * <li>[A4] If the new lookup class is in a different package
-         * than the old one, protected and default (package) members will not be accessible.
-         * <li>[A5] If the new lookup class is not within the same package member
+         * <li> [A6] If the new lookup class is in a different package than the old one,
+         * protected and default (package) members will not be accessible.
+         * <li> [A7] If the new lookup class is not within the same package member
          * as the old one, private members will not be accessible.
-         * <li>[A6] If the new lookup class is not accessible to the old lookup class,
-         * using the original access modes,
+         * <li> [A8] If the new lookup class is not accessible to the old lookup class,
          * then no members, not even public members, will be accessible.
-         * <li>[A7] If the new lookup class for this {@code Lookup} is in the unnamed module,
-         * and the new lookup class is in a named module {@code M}, then no members in
-         * {@code M}'s non-exported packages will be accessible.
-         * <li>[A8] If the lookup for this {@code Lookup} is in a named module, and the
-         * new lookup class is in a different module, then no members, not even
-         * public members in {@code M}'s exported packages, will be accessible.
-         * [A8] (In all other cases, public members will continue to be accessible.)
+         * <li> [A9] (In all other cases, public members will continue to be accessible.)
          * </ul>
          * Other than the above cases, the new lookup will have the same
          * access capabilities as the original. [A10]
@@ -171,36 +174,35 @@
             boolean sameModule = (c1.getModule() == c2.getModule()) ||
                                  (!c1.getModule().isNamed() && !c2.getModule().isNamed());
             boolean samePackage = (c1.getClassLoader() == c2.getClassLoader() &&
-                                   packagePrefix(c1).equals(packagePrefix(c2)));
+                                   c1.getPackageName().equals(c2.getPackageName()));
             boolean sameTopLevel = (topLevelClass(c1) == topLevelClass(c2));
             boolean sameClass = (c1 == c2);
             assert(samePackage  || !sameTopLevel);
             assert(sameTopLevel || !sameClass);
-            boolean accessible = sameClass;  // [A6]
+            boolean accessible = sameClass;
             if ((m1 & PACKAGE) != 0)  accessible |= samePackage;
             if ((m1 & PUBLIC ) != 0)  accessible |= (c2.getModifiers() & PUBLIC) != 0;
             if (!sameModule) {
-                if (c1.getModule().isNamed()) {
-                    accessible = false;  // [A8]
+                if (c1.getModule().isNamed() && (m1 & UNCONDITIONAL) == 0) {
+                    accessible = false;  // [A3]
                 } else {
-                    // Different module; loose MODULE and lower access.
-                    changed |= (MODULE|PACKAGE|PRIVATE|PROTECTED);  // [A7]
+                    changed |= (MODULE|PACKAGE|PRIVATE|PROTECTED);    // [A3] [A4]
                 }
             }
             if (!accessible) {
                 // Different package and no access to c2; lose all access.
-                changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED);  // [A6]
+                changed |= (PUBLIC|MODULE|PACKAGE|PRIVATE|PROTECTED);  // [A8]
             }
             if (!samePackage) {
                 // Different package; loose PACKAGE and lower access.
-                changed |= (PACKAGE|PRIVATE|PROTECTED);  // [A4]
+                changed |= (PACKAGE|PRIVATE|PROTECTED);  // [A6]
             }
             if (!sameTopLevel) {
-                // Different top-level class.  Lose PRIVATE and lower access.
-                changed |= (PRIVATE|PROTECTED);  // [A5]
+                // Different top-level class.  Lose PRIVATE and PROTECTED access.
+                changed |= (PRIVATE|PROTECTED);  // [A5] [A7]
             }
             if (!sameClass) {
-                changed |= (PROTECTED);     // [A3]
+                changed |= (UNCONDITIONAL);     // [A5]
             } else {
                 assert(changed == 0);       // [A10] (no deprivation if same class)
             }
@@ -228,11 +230,10 @@
             Class<?> c1 = lookupClass();
             Class<?> c2 = m.getDeclaringClass();
 
-            // if the lookup class is in a loose module with PUBLIC access then
-            // public members of public types in all unnamed modules can be accessed
-            if (isLooseModule(c1.getModule())
+            // publicLookup has access to all public types/members of types in unnamed modules
+            if ((lookupModes & UNCONDITIONAL) != 0
                 && (lookupModes & PUBLIC) != 0
-                && (!c2.getModule().isNamed())
+                && !c2.getModule().isNamed()
                 && Modifier.isPublic(c2.getModifiers())
                 && Modifier.isPublic(m.getModifiers()))
                 return true;
@@ -261,17 +262,12 @@
             if (load && c2.getClassLoader() != null) {
                 if (c1.getClassLoader() == null) {
                     // not visible
-                return false;
-            }
-                if (c1 == publicLookup().lookupClass()) {
-                    // not visible as lookup class is defined by child of the boot loader
                     return false;
                 }
             }
 
-            // if the lookup class is in a loose module with PUBLIC access then
-            // public types in all unnamed modules can be accessed
-            if (isLooseModule(c1.getModule())
+            // publicLookup has access to all public types/members of types in unnamed modules
+            if ((lookupModes & UNCONDITIONAL) != 0
                 && (lookupModes & PUBLIC) != 0
                 && (!c2.getModule().isNamed())
                 && Modifier.isPublic(c2.getModifiers()))
@@ -295,11 +291,6 @@
             }
             return r;
         }
-
-        private boolean isLooseModule(Module m) {
-            ClassLoader cl = new ClassLoader() { };
-            return m.canRead(cl.getUnnamedModule());
-        }
     }
 
     private static Class<?> topLevelClass(Class<?> cls) {
@@ -311,14 +302,6 @@
         return c;
     }
 
-    private static String packagePrefix(Class<?> c) {
-        while (c.isArray())  c = c.getComponentType();
-        String s = c.getName();
-        assert(s.indexOf('/') < 0);
-        return s.substring(0, s.lastIndexOf('.')+1);
-    }
-
-
     private final TreeSet<LookupCase> CASES = new TreeSet<>();
     private final TreeMap<LookupCase,TreeSet<LookupCase>> CASE_EDGES = new TreeMap<>();
     private final ArrayList<ClassLoader> LOADERS = new ArrayList<>();
--- a/test/java/lang/invoke/DropLookupModeTest.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/test/java/lang/invoke/DropLookupModeTest.java	Fri Feb 10 09:04:39 2017 +0000
@@ -65,6 +65,10 @@
         lookup = fullPowerLookup.dropLookupMode(PUBLIC);
         assertTrue(lookup.lookupClass() == lc);
         assertTrue(lookup.lookupModes() == 0);
+
+        lookup = fullPowerLookup.dropLookupMode(UNCONDITIONAL);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == (PUBLIC|MODULE|PACKAGE|PRIVATE));
     }
 
     /**
@@ -108,7 +112,7 @@
     public void testPublicLookup() {
         final Lookup publicLookup = MethodHandles.publicLookup();
         final Class<?> lc = publicLookup.lookupClass();
-        assertTrue(publicLookup.lookupModes() == PUBLIC);
+        assertTrue(publicLookup.lookupModes() == (PUBLIC|UNCONDITIONAL));
 
         Lookup lookup = publicLookup.dropLookupMode(PRIVATE);
         assertTrue(lookup.lookupClass() == lc);
@@ -129,6 +133,10 @@
         lookup = publicLookup.dropLookupMode(PUBLIC);
         assertTrue(lookup.lookupClass() == lc);
         assertTrue(lookup.lookupModes() == 0);
+
+        lookup = publicLookup.dropLookupMode(UNCONDITIONAL);
+        assertTrue(lookup.lookupClass() == lc);
+        assertTrue(lookup.lookupModes() == PUBLIC);
     }
 
     @DataProvider(name = "badInput")
--- a/test/java/lang/invoke/MethodHandles/privateLookupIn/Driver.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/test/java/lang/invoke/MethodHandles/privateLookupIn/Driver.java	Fri Feb 10 09:04:39 2017 +0000
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @build test/* m1/* m2/* m3/*
+ * @build test/* m1/* m2/* m3/* Unnamed
  * @run testng/othervm test/p.PrivateLookupInTests
  * @summary Unit tests for MethodHandles.privateLookupIn
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/invoke/MethodHandles/privateLookupIn/Unnamed.java	Fri Feb 10 09:04:39 2017 +0000
@@ -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.
+ */
+
+public class Unnamed { }
--- a/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java	Thu Feb 09 17:21:47 2017 +0000
+++ b/test/java/lang/invoke/MethodHandles/privateLookupIn/test/p/PrivateLookupInTests.java	Fri Feb 10 09:04:39 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -126,6 +126,26 @@
         Object obj = mh.invokeExact();
     }
 
+    // test target class in unnamed module
+    public void testTargetClassInUnnamedModule() throws Throwable {
+        Class<?> clazz = Class.forName("Unnamed");
+        assertFalse(clazz.getModule().isNamed());
+
+        // thisModule does not read the unnamed module
+        Module thisModule = getClass().getModule();
+        assertFalse(thisModule.canRead(clazz.getModule()));
+        try {
+            MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
+            assertTrue(false);
+        } catch (IllegalAccessException expected) { }
+
+        // thisModule reads the unnamed module
+        thisModule.addReads(clazz.getModule());
+        Lookup lookup = MethodHandles.privateLookupIn(clazz, MethodHandles.lookup());
+        assertTrue(lookup.lookupClass() == clazz);
+        assertTrue(lookup.hasPrivateAccess());
+    }
+
     // test does not read m2, m2 opens p2 to test
     @Test(expectedExceptions = {IllegalAccessException.class})
     public void testCallerDoesNotRead() throws Throwable {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/invoke/modules/Driver.java	Fri Feb 10 09:04:39 2017 +0000
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+/**
+ * @test
+ * @build m1/* m2/* Unnamed
+ * @run testng/othervm m1/p1.Main
+ * @summary Basic test case for module access checks and Lookup.in.
+ */
--- a/test/java/lang/invoke/modules/ModuleAccessControlTest.java	Thu Feb 09 17:21:47 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-/*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Arrays;
-import java.util.List;
-
-import static jdk.testlibrary.ProcessTools.executeTestJava;
-
-import org.testng.annotations.BeforeTest;
-import org.testng.annotations.Test;
-import static org.testng.Assert.*;
-
-/**
- * @test
- * @library /lib/testlibrary
- * @modules jdk.compiler
- * @build CompilerUtils jdk.testlibrary.*
- * @run testng ModuleAccessControlTest
- * @summary Driver for testing module access checking by MethodHandles.Lookup
- */
-
-public class ModuleAccessControlTest {
-
-    private static final String TEST_SRC = System.getProperty("test.src");
-
-    private static final Path SRC_DIR = Paths.