changeset 16912:7081836d4ceb

Merge
author lana
date Thu, 23 Mar 2017 22:57:12 +0000
parents af1ace480c5e 443f9939b3b3
children 77ab8e3b4b04 b45f8cb93c6f e352eacd7a94
files src/java.base/share/classes/jdk/internal/loader/ResourceHelper.java
diffstat 184 files changed, 4939 insertions(+), 2000 deletions(-) [+]
line wrap: on
line diff
--- a/make/mapfiles/libjava/mapfile-vers	Thu Mar 23 22:31:12 2017 +0000
+++ b/make/mapfiles/libjava/mapfile-vers	Thu Mar 23 22:57:12 2017 +0000
@@ -128,7 +128,6 @@
 		Java_java_lang_Class_isInstance;
 		Java_java_lang_Class_registerNatives;
 		Java_java_lang_ClassLoader_findBootstrapClass;
-		Java_java_lang_ClassLoader_defineClass0;
 		Java_java_lang_ClassLoader_defineClass1;
 		Java_java_lang_ClassLoader_defineClass2;
 		Java_java_lang_ClassLoader_findBuiltinLib;
--- a/make/src/classes/build/tools/taglet/Incubating.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/make/src/classes/build/tools/taglet/Incubating.java	Thu Mar 23 22:57:12 2017 +0000
@@ -28,6 +28,7 @@
 import java.util.EnumSet;
 import java.util.List;
 import java.util.Set;
+import javax.lang.model.element.Element;
 import com.sun.source.doctree.DocTree;
 import jdk.javadoc.doclet.Taglet;
 import static jdk.javadoc.doclet.Taglet.Location.*;
@@ -59,7 +60,7 @@
                 + " Will be removed in a future release.</b>";
 
     @Override
-    public String toString(List<? extends DocTree> tags) {
+    public String toString(List<? extends DocTree> tags, Element elem) {
         return MESSAGE;
     }
 }
--- a/src/java.base/share/classes/java/lang/Class.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/java/lang/Class.java	Thu Mar 23 22:57:12 2017 +0000
@@ -64,9 +64,9 @@
 import jdk.internal.HotSpotIntrinsicCandidate;
 import jdk.internal.loader.BootLoader;
 import jdk.internal.loader.BuiltinClassLoader;
-import jdk.internal.loader.ResourceHelper;
 import jdk.internal.misc.Unsafe;
 import jdk.internal.misc.VM;
+import jdk.internal.module.Resources;
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.ConstantPool;
 import jdk.internal.reflect.Reflection;
@@ -2563,11 +2563,11 @@
 
         Module module = getModule();
         if (module.isNamed()) {
-            if (!ResourceHelper.isSimpleResource(name)) {
+            if (Resources.canEncapsulate(name)) {
                 Module caller = Reflection.getCallerClass().getModule();
                 if (caller != module) {
                     Set<String> packages = module.getDescriptor().packages();
-                    String pn = ResourceHelper.getPackageName(name);
+                    String pn = Resources.toPackageName(name);
                     if (packages.contains(pn) && !module.isOpen(pn, caller)) {
                         // resource is in package not open to caller
                         return null;
@@ -2665,11 +2665,11 @@
 
         Module module = getModule();
         if (module.isNamed()) {
-            if (!ResourceHelper.isSimpleResource(name)) {
+            if (Resources.canEncapsulate(name)) {
                 Module caller = Reflection.getCallerClass().getModule();
                 if (caller != module) {
                     Set<String> packages = module.getDescriptor().packages();
-                    String pn = ResourceHelper.getPackageName(name);
+                    String pn = Resources.toPackageName(name);
                     if (packages.contains(pn) && !module.isOpen(pn, caller)) {
                         // resource is in package not open to caller
                         return null;
@@ -2771,7 +2771,7 @@
          * In all other cases, it requires RuntimePermission("accessDeclaredMembers")
          * permission.
          */
-        final ClassLoader ccl = caller.getClassLoader0();
+        final ClassLoader ccl = ClassLoader.getClassLoader(caller);
         if (which != Member.PUBLIC) {
             final ClassLoader cl = getClassLoader0();
             if (ccl != cl) {
--- a/src/java.base/share/classes/java/lang/ClassLoader.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/java/lang/ClassLoader.java	Thu Mar 23 22:57:12 2017 +0000
@@ -983,7 +983,7 @@
     {
         protectionDomain = preDefineClass(name, protectionDomain);
         String source = defineClassSourceLocation(protectionDomain);
-        Class<?> c = defineClass1(name, b, off, len, protectionDomain, source);
+        Class<?> c = defineClass1(this, name, b, off, len, protectionDomain, source);
         postDefineClass(c, protectionDomain);
         return c;
     }
@@ -1075,17 +1075,17 @@
 
         protectionDomain = preDefineClass(name, protectionDomain);
         String source = defineClassSourceLocation(protectionDomain);
-        Class<?> c = defineClass2(name, b, b.position(), len, protectionDomain, source);
+        Class<?> c = defineClass2(this, name, b, b.position(), len, protectionDomain, source);
         postDefineClass(c, protectionDomain);
         return c;
     }
 
-    private native Class<?> defineClass1(String name, byte[] b, int off, int len,
-                                         ProtectionDomain pd, String source);
+    static native Class<?> defineClass1(ClassLoader loader, String name, byte[] b, int off, int len,
+                                        ProtectionDomain pd, String source);
 
-    private native Class<?> defineClass2(String name, java.nio.ByteBuffer b,
-                                         int off, int len, ProtectionDomain pd,
-                                         String source);
+    static native Class<?> defineClass2(ClassLoader loader, String name, java.nio.ByteBuffer b,
+                                        int off, int len, ProtectionDomain pd,
+                                        String source);
 
     // true if the name is null or has the potential to be a valid binary name
     private boolean checkName(String name) {
--- a/src/java.base/share/classes/java/lang/RuntimePermission.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/java/lang/RuntimePermission.java	Thu Mar 23 22:57:12 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
@@ -26,9 +26,7 @@
 package java.lang;
 
 import java.security.*;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.StringTokenizer;
+import java.lang.module.ModuleFinder;
 
 /**
  * This class is for runtime permissions. A {@code RuntimePermission}
@@ -265,6 +263,16 @@
  * </tr>
  *
  * <tr>
+ *   <td>defineClass</td>
+ *   <td>Define a class with
+ * {@link java.lang.invoke.MethodHandles.Lookup#defineClass(byte[])
+ * Lookup.defineClass}.</td>
+ *   <td>This grants code with a suitably privileged {@code Lookup} object
+ * permission to define classes in the same package as the {@code Lookup}'s
+ * lookup class. </td>
+ * </tr>
+ *
+ * <tr>
  *   <td>accessDeclaredMembers</td>
  *   <td>Access to the declared members of a class</td>
  *   <td>This grants code permission to query a class for its public,
@@ -367,6 +375,14 @@
  *   <td>See {@link java.lang.System.LoggerFinder java.lang.System.LoggerFinder}
  *   for more information.</td>
  * </tr>
+ *
+ * <tr>
+ *   <td>accessSystemModules</td>
+ *   <td>Access system modules in the runtime image.</td>
+ *   <td>This grants the permission to access resources in the
+ *   {@linkplain ModuleFinder#ofSystem system modules} in the runtime image.</td>
+ * </tr>
+ *
  * </table>
  *
  * @implNote
--- a/src/java.base/share/classes/java/lang/StackStreamFactory.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/java/lang/StackStreamFactory.java	Thu Mar 23 22:57:12 2017 +0000
@@ -982,13 +982,6 @@
     }
 
     private static boolean isReflectionFrame(Class<?> c) {
-        if (c.getName().startsWith("jdk.internal.reflect") &&
-                !MethodAccessor.class.isAssignableFrom(c) &&
-                !ConstructorAccessor.class.isAssignableFrom(c)) {
-            throw new InternalError("Not jdk.internal.reflect.MethodAccessor"
-                    + " or jdk.internal.reflect.ConstructorAccessor: "
-                    + c.toString());
-        }
         // ## should filter all @Hidden frames?
         return c == Method.class ||
                c == Constructor.class ||
--- a/src/java.base/share/classes/java/lang/System.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/java/lang/System.java	Thu Mar 23 22:57:12 2017 +0000
@@ -43,6 +43,7 @@
 import java.lang.reflect.Module;
 import java.net.URL;
 import java.security.AccessControlContext;
+import java.security.ProtectionDomain;
 import java.util.Properties;
 import java.util.PropertyPermission;
 import java.util.Map;
@@ -1845,6 +1846,39 @@
     }
 
     /**
+     * Logs an exception/error at initialization time to stdout or stderr.
+     *
+     * @param printToStderr to print to stderr rather than stdout
+     * @param printStackTrace to print the stack trace
+     * @param msg the message to print before the exception, can be {@code null}
+     * @param e the exception or error
+     */
+    private static void logInitException(boolean printToStderr,
+                                         boolean printStackTrace,
+                                         String msg,
+                                         Throwable e) {
+        if (VM.initLevel() < 1) {
+            throw new InternalError("system classes not initialized");
+        }
+        PrintStream log = (printToStderr) ? err : out;
+        if (msg != null) {
+            log.println(msg);
+        }
+        if (printStackTrace) {
+            e.printStackTrace(log);
+        } else {
+            log.println(e);
+            for (Throwable suppressed : e.getSuppressed()) {
+                log.println("Suppressed: " + suppressed);
+            }
+            Throwable cause = e.getCause();
+            if (cause != null) {
+                log.println("Caused by: " + cause);
+            }
+        }
+    }
+
+    /**
      * Initialize the system class.  Called after thread initialization.
      */
     private static void initPhase1() {
@@ -1922,13 +1956,25 @@
     /*
      * Invoked by VM.  Phase 2 module system initialization.
      * Only classes in java.base can be loaded in this phase.
+     *
+     * @param printToStderr print exceptions to stderr rather than stdout
+     * @param printStackTrace print stack trace when exception occurs
+     *
+     * @return JNI_OK for success, JNI_ERR for failure
      */
-    private static void initPhase2() {
-        // initialize the module system
-        System.bootLayer = ModuleBootstrap.boot();
+    private static int initPhase2(boolean printToStderr, boolean printStackTrace) {
+        try {
+            bootLayer = ModuleBootstrap.boot();
+        } catch (Exception | Error e) {
+            logInitException(printToStderr, printStackTrace,
+                             "Error occurred during initialization of boot layer", e);
+            return -1; // JNI_ERR
+        }
 
         // module system initialized
         VM.initLevel(2);
+
+        return 0; // JNI_OK
     }
 
     /*
@@ -2034,6 +2080,9 @@
             public ConcurrentHashMap<?, ?> createOrGetClassLoaderValueMap(ClassLoader cl) {
                 return cl.createOrGetClassLoaderValueMap();
             }
+            public Class<?> defineClass(ClassLoader loader, String name, byte[] b, ProtectionDomain pd, String source) {
+                return ClassLoader.defineClass1(loader, name, b, 0, b.length, pd, source);
+            }
             public Class<?> findBootstrapClassOrNull(ClassLoader cl, String name) {
                 return cl.findBootstrapClassOrNull(name);
             }
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Thu Mar 23 22:57:12 2017 +0000
@@ -25,6 +25,9 @@
 
 package java.lang.invoke;
 
+import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.IllegalAccessLogger;
+import jdk.internal.org.objectweb.asm.ClassReader;
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.Reflection;
 import jdk.internal.vm.annotation.ForceInline;
@@ -43,6 +46,9 @@
 import java.lang.reflect.Module;
 import java.lang.reflect.ReflectPermission;
 import java.nio.ByteOrder;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.BitSet;
@@ -191,6 +197,12 @@
         }
         if ((lookup.lookupModes() & Lookup.MODULE) == 0)
             throw new IllegalAccessException("lookup does not have MODULE lookup mode");
+        if (!callerModule.isNamed() && targetModule.isNamed()) {
+            IllegalAccessLogger logger = IllegalAccessLogger.illegalAccessLogger();
+            if (logger != null) {
+                logger.logIfOpenedByBackdoor(lookup, targetClass);
+            }
+        }
         return new Lookup(targetClass);
     }
 
@@ -855,6 +867,112 @@
             return new Lookup(lookupClass(), newModes);
         }
 
+        /**
+         * Defines a class to the same class loader and in the same runtime package and
+         * {@linkplain java.security.ProtectionDomain protection domain} as this lookup's
+         * {@linkplain #lookupClass() lookup class}.
+         *
+         * <p> The {@linkplain #lookupModes() lookup modes} for this lookup must include
+         * {@link #PACKAGE PACKAGE} access as default (package) members will be
+         * accessible to the class. The {@code PACKAGE} lookup mode serves to authenticate
+         * that the lookup object was created by a caller in the runtime package (or derived
+         * from a lookup originally created by suitably privileged code to a target class in
+         * the runtime package). The lookup modes cannot include {@link #PRIVATE PRIVATE}
+         * access. A lookup with {@code PRIVATE} access can be downgraded to drop this lookup
+         * mode with the {@linkplain #dropLookupMode(int) dropLookupMode} method. </p>
+         *
+         * <p> The {@code bytes} parameter is the class bytes of a valid class file (as defined
+         * by the <em>The Java Virtual Machine Specification</em>) with a class name in the
+         * same package as the lookup class. </p>
+         *
+         * <p> This method does not run the class initializer. The class initializer may
+         * run at a later time, as detailed in section 12.4 of the <em>The Java Language
+         * Specification</em>. </p>
+         *
+         * <p> If there is a security manager, its {@code checkPermission} method is first called
+         * to check {@code RuntimePermission("defineClass")}. </p>
+         *
+         * @param bytes the class bytes
+         * @return the {@code Class} object for the class
+         * @throws IllegalArgumentException the bytes are for a class in a different package
+         * to the lookup class
+         * @throws IllegalAccessException if this lookup does not have {@code PACKAGE} access
+         * @throws UnsupportedOperationException if the lookup class has {@code PRIVATE} access
+         * @throws LinkageError if the class is malformed ({@code ClassFormatError}), cannot be
+         * verified ({@code VerifyError}), is already defined, or another linkage error occurs
+         * @throws SecurityException if denied by the security manager
+         * @throws NullPointerException if {@code bytes} is {@code null}
+         * @since 9
+         * @spec JPMS
+         * @see Lookup#privateLookupIn
+         * @see Lookup#dropLookupMode
+         * @see ClassLoader#defineClass(String,byte[],int,int,ProtectionDomain)
+         */
+        public Class<?> defineClass(byte[] bytes) throws IllegalAccessException {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null)
+                sm.checkPermission(new RuntimePermission("defineClass"));
+            if (hasPrivateAccess())
+                throw new UnsupportedOperationException("PRIVATE access not supported");
+            if ((lookupModes() & PACKAGE) == 0)
+                throw new IllegalAccessException("Lookup does not have PACKAGE access");
+            assert (lookupModes() & (MODULE|PUBLIC)) != 0;
+
+            // parse class bytes to get class name (in internal form)
+            bytes = bytes.clone();
+            String name;
+            try {
+                ClassReader reader = new ClassReader(bytes);
+                name = reader.getClassName();
+            } catch (RuntimeException e) {
+                // ASM exceptions are poorly specified
+                ClassFormatError cfe = new ClassFormatError();
+                cfe.initCause(e);
+                throw cfe;
+            }
+
+            // get package and class name in binary form
+            String cn, pn;
+            int index = name.lastIndexOf('/');
+            if (index == -1) {
+                cn = name;
+                pn = "";
+            } else {
+                cn = name.replace('/', '.');
+                pn = cn.substring(0, index);
+            }
+            if (!pn.equals(lookupClass.getPackageName())) {
+                throw new IllegalArgumentException("Class not in same package as lookup class");
+            }
+
+            // invoke the class loader's defineClass method
+            ClassLoader loader = lookupClass.getClassLoader();
+            ProtectionDomain pd = (loader != null) ? lookupClassProtectionDomain() : null;
+            String source = "__Lookup_defineClass__";
+            Class<?> clazz = SharedSecrets.getJavaLangAccess().defineClass(loader, cn, bytes, pd, source);
+            assert clazz.getClassLoader() == lookupClass.getClassLoader()
+                    && clazz.getPackageName().equals(lookupClass.getPackageName())
+                    && protectionDomain(clazz) == lookupClassProtectionDomain();
+            return clazz;
+        }
+
+        private ProtectionDomain lookupClassProtectionDomain() {
+            ProtectionDomain pd = cachedProtectionDomain;
+            if (pd == null) {
+                cachedProtectionDomain = pd = protectionDomain(lookupClass);
+            }
+            return pd;
+        }
+
+        private ProtectionDomain protectionDomain(Class<?> clazz) {
+            PrivilegedAction<ProtectionDomain> pa = clazz::getProtectionDomain;
+            return AccessController.doPrivileged(pa);
+        }
+
+        // cached protection domain
+        private volatile ProtectionDomain cachedProtectionDomain;
+
+
         // Make sure outer class is initialized first.
         static { IMPL_NAMES.getClass(); }
 
@@ -1948,7 +2066,7 @@
 
         /**
          * Returns {@code true} if this lookup has {@code PRIVATE} access.
-         * @return {@code true} if this lookup has {@code PRIVATE} acesss.
+         * @return {@code true} if this lookup has {@code PRIVATE} access.
          * @since 9
          */
         public boolean hasPrivateAccess() {
--- a/src/java.base/share/classes/java/lang/module/Configuration.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/java/lang/module/Configuration.java	Thu Mar 23 22:57:12 2017 +0000
@@ -112,11 +112,9 @@
     // 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();
@@ -125,7 +123,6 @@
         this.nameToModule = Collections.emptyMap();
         this.osName = null;
         this.osArch = null;
-        this.osVersion = null;
     }
 
     private Configuration(List<Configuration> parents,
@@ -152,7 +149,6 @@
 
         this.osName = resolver.osName();
         this.osArch = resolver.osArch();
-        this.osVersion = resolver.osVersion();
     }
 
     /**
@@ -281,6 +277,7 @@
      * <em>observability-related</em> reasons: </p>
      *
      * <ul>
+     *
      *     <li><p> A root module, or a direct or transitive dependency, is not
      *     found. </p></li>
      *
@@ -289,13 +286,6 @@
      *     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
@@ -306,6 +296,10 @@
      *     <li><p> A cycle is detected, say where module {@code m1} requires
      *     module {@code m2} and {@code m2} requires {@code m1}. </p></li>
      *
+     *     <li><p> A module reads two or more modules with the same name. This
+     *     includes the case where a module reads another with the same name as
+     *     itself. </p></li>
+     *
      *     <li><p> Two or more modules in the configuration export the same
      *     package to a module that reads both. This includes the case where a
      *     module {@code M} containing package {@code p} reads another module
@@ -319,8 +313,9 @@
      * </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.
+     * on referential integrity or other checks that ensure different builds of
+     * tightly coupled modules or modules for specific operating systems or
+     * architectures are not combined in the same configuration.
      *
      * @param  before
      *         The <em>before</em> module finder to find modules
--- a/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java	Thu Mar 23 22:57:12 2017 +0000
@@ -179,8 +179,10 @@
         private final Set<Modifier> mods;
         private final String name;
         private final Version compiledVersion;
+        private final String rawCompiledVersion;
 
-        private Requires(Set<Modifier> ms, String mn, Version v) {
+        private Requires(Set<Modifier> ms, String mn, Version v, String vs) {
+            assert v == null || vs == null;
             if (ms.isEmpty()) {
                 ms = Collections.emptySet();
             } else {
@@ -189,12 +191,14 @@
             this.mods = ms;
             this.name = mn;
             this.compiledVersion = v;
+            this.rawCompiledVersion = vs;
         }
 
         private Requires(Set<Modifier> ms, String mn, Version v, boolean unused) {
             this.mods = ms;
             this.name = mn;
             this.compiledVersion = v;
+            this.rawCompiledVersion = null;
         }
 
         /**
@@ -218,13 +222,34 @@
         /**
          * Returns the version of the module if recorded at compile-time.
          *
-         * @return The version of the module if recorded at compile-time
+         * @return The version of the module if recorded at compile-time,
+         *         or an empty {@code Optional} if no version was recorded or
+         *         the version string recorded is {@linkplain Version#parse(String)
+         *         unparseable}
          */
         public Optional<Version> compiledVersion() {
             return Optional.ofNullable(compiledVersion);
         }
 
         /**
+         * Returns the string with the possibly-unparseable version of the module
+         * if recorded at compile-time.
+         *
+         * @return The string containing the version of the module if recorded
+         *         at compile-time, or an empty {@code Optional} if no version
+         *         was recorded
+         *
+         * @see #compiledVersion()
+         */
+        public Optional<String> rawCompiledVersion() {
+            if (compiledVersion != null) {
+                return Optional.of(compiledVersion.toString());
+            } else {
+                return Optional.ofNullable(rawCompiledVersion);
+            }
+        }
+
+        /**
          * Compares this module dependence to another.
          *
          * <p> Two {@code Requires} objects are compared by comparing their
@@ -236,7 +261,10 @@
          * 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>
+         * recorded version. If both recorded versions are {@linkplain
+         * Version#parse(String) unparseable} then the {@linkplain
+         * #rawCompiledVersion() raw version strings} are compared
+         * lexicographically. </p>
          *
          * @param  that
          *         The module dependence to compare
@@ -262,6 +290,10 @@
             c = compare(this.compiledVersion, that.compiledVersion);
             if (c != 0) return c;
 
+            // rawCompiledVersion
+            c = compare(this.rawCompiledVersion, that.rawCompiledVersion);
+            if (c != 0) return c;
+
             return 0;
         }
 
@@ -289,7 +321,8 @@
                 return false;
             Requires that = (Requires)ob;
             return name.equals(that.name) && mods.equals(that.mods)
-                    && Objects.equals(compiledVersion, that.compiledVersion);
+                    && Objects.equals(compiledVersion, that.compiledVersion)
+                    && Objects.equals(rawCompiledVersion, that.rawCompiledVersion);
         }
 
         /**
@@ -306,6 +339,8 @@
             int hash = name.hashCode() * 43 + mods.hashCode();
             if (compiledVersion != null)
                 hash = hash * 43 + compiledVersion.hashCode();
+            if (rawCompiledVersion != null)
+                hash = hash * 43 + rawCompiledVersion.hashCode();
             return hash;
         }
 
@@ -774,7 +809,7 @@
         /**
          * Returns the fully qualified class name of the service type.
          *
-         * @return The fully qualified class name of the service type.
+         * @return The fully qualified class name of the service type
          */
         public String service() { return service; }
 
@@ -1199,6 +1234,7 @@
 
     private final String name;
     private final Version version;
+    private final String rawVersionString;
     private final Set<Modifier> modifiers;
     private final boolean open;  // true if modifiers contains OPEN
     private final boolean automatic;  // true if modifiers contains AUTOMATIC
@@ -1209,12 +1245,10 @@
     private final Set<Provides> provides;
     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,
+                             String rawVersionString,
                              Set<Modifier> modifiers,
                              Set<Requires> requires,
                              Set<Exports> exports,
@@ -1222,13 +1256,12 @@
                              Set<String> uses,
                              Set<Provides> provides,
                              Set<String> packages,
-                             String mainClass,
-                             String osName,
-                             String osArch,
-                             String osVersion)
+                             String mainClass)
     {
+        assert version == null || rawVersionString == null;
         this.name = name;
         this.version = version;
+        this.rawVersionString = rawVersionString;
         this.modifiers = emptyOrUnmodifiableSet(modifiers);
         this.open = modifiers.contains(Modifier.OPEN);
         this.automatic = modifiers.contains(Modifier.AUTOMATIC);
@@ -1242,9 +1275,6 @@
 
         this.packages = emptyOrUnmodifiableSet(packages);
         this.mainClass = mainClass;
-        this.osName = osName;
-        this.osArch = osArch;
-        this.osVersion = osVersion;
     }
 
     /**
@@ -1261,13 +1291,11 @@
                      Set<Provides> provides,
                      Set<String> packages,
                      String mainClass,
-                     String osName,
-                     String osArch,
-                     String osVersion,
                      int hashCode,
                      boolean unused) {
         this.name = name;
         this.version = version;
+        this.rawVersionString = null;
         this.modifiers = modifiers;
         this.open = modifiers.contains(Modifier.OPEN);
         this.automatic = modifiers.contains(Modifier.AUTOMATIC);
@@ -1278,9 +1306,6 @@
         this.provides = provides;
         this.packages = packages;
         this.mainClass = mainClass;
-        this.osName = osName;
-        this.osArch = osArch;
-        this.osVersion = osVersion;
         this.hash = hashCode;
     }
 
@@ -1394,18 +1419,37 @@
     /**
      * <p> Returns the module version. </p>
      *
-     * @return This module's version
+     * @return This module's version, or an empty {@code Optional} if the
+     *         module does not have a version or the version is
+     *         {@linkplain Version#parse(String) unparseable}
      */
     public Optional<Version> version() {
         return Optional.ofNullable(version);
     }
 
     /**
+     * <p> Returns the string with the possibly-unparseable version of the
+     * module </p>
+     *
+     * @return The string containing the version of the module or an empty
+     *         {@code Optional} if the module does not have a version
+     *
+     * @see #version()
+     */
+    public Optional<String> rawVersion() {
+        if (version != null) {
+            return Optional.of(version.toString());
+        } else {
+            return Optional.ofNullable(rawVersionString);
+        }
+    }
+
+    /**
      * <p> Returns a string containing the module name and, if present, its
      * version. </p>
      *
      * @return A string containing the module name and, if present, its
-     *         version.
+     *         version
      */
     public String toNameAndVersion() {
         if (version != null) {
@@ -1425,40 +1469,11 @@
     }
 
     /**
-     * Returns the operating system name if the module is operating system
-     * specific.
+     * Returns the set of packages in the module.
      *
-     * @return The operating system name or an empty {@code Optional}
-     *         if the module is not operating system specific
-     */
-    public Optional<String> osName() {
-        return Optional.ofNullable(osName);
-    }
-
-    /**
-     * Returns the operating system architecture if the module is operating
-     * system architecture specific.
-     *
-     * @return The operating system architecture or an empty {@code Optional}
-     *         if the module is not operating system architecture specific
-     */
-    public Optional<String> osArch() {
-        return Optional.ofNullable(osArch);
-    }
-
-    /**
-     * Returns the operating system version if the module is operating
-     * system version specific.
-     *
-     * @return The operating system version or an empty {@code Optional}
-     *         if the module is not operating system version specific
-     */
-    public Optional<String> osVersion() {
-        return Optional.ofNullable(osVersion);
-    }
-
-    /**
-     * Returns the set of packages in the module.
+     * <p> The set of packages includes all exported and open packages, as well
+     * as the packages of any service providers, and the package for the main
+     * class. </p>
      *
      * @return A possibly-empty unmodifiable set of the packages in the module
      */
@@ -1518,9 +1533,7 @@
         final Set<String> uses = new HashSet<>();
         final Map<String, Provides> provides = new HashMap<>();
         Version version;
-        String osName;
-        String osArch;
-        String osVersion;
+        String rawVersionString;
         String mainClass;
 
         /**
@@ -1604,24 +1617,21 @@
             Objects.requireNonNull(compiledVersion);
             if (strict)
                 mn = requireModuleName(mn);
-            return requires(new Requires(ms, mn, compiledVersion));
+            return requires(new Requires(ms, mn, compiledVersion, null));
         }
 
         /* package */Builder requires(Set<Requires.Modifier> ms,
                                       String mn,
-                                      String compiledVersion) {
-            Version v = null;
+                                      String rawCompiledVersion) {
+            Requires r;
             try {
-                v = Version.parse(compiledVersion);
+                Version v = Version.parse(rawCompiledVersion);
+                r = new Requires(ms, mn, v, null);
             } catch (IllegalArgumentException e) {
-                // for now, drop un-parsable version when non-strict
                 if (strict) throw e;
+                r = new Requires(ms, mn, null, rawCompiledVersion);
             }
-            if (v == null) {
-                return requires(ms, mn);
-            } else {
-                return requires(ms, mn, v);
-            }
+            return requires(r);
         }
 
         /**
@@ -1646,7 +1656,7 @@
         public Builder requires(Set<Requires.Modifier> ms, String mn) {
             if (strict)
                 mn = requireModuleName(mn);
-            return requires(new Requires(ms, mn, null));
+            return requires(new Requires(ms, mn, null, null));
         }
 
         /**
@@ -1952,7 +1962,7 @@
          *         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
+         *         or this is a builder for an automatic module
          */
         public Builder uses(String service) {
             if (automatic)
@@ -2068,6 +2078,7 @@
          */
         public Builder version(Version v) {
             version = requireNonNull(v);
+            rawVersionString = null;
             return this;
         }
 
@@ -2086,18 +2097,15 @@
          * @see Version#parse(String)
          */
         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;
-                }
+            try {
+                version = Version.parse(vs);
+                rawVersionString = null;
+            } catch (IllegalArgumentException e) {
+                if (strict) throw e;
+                version = null;
+                rawVersionString = vs;
             }
-            return version(v);
+            return this;
         }
 
         /**
@@ -2132,60 +2140,6 @@
         }
 
         /**
-         * Sets the operating system name.
-         *
-         * @param  name
-         *         The operating system name
-         *
-         * @return This builder
-         *
-         * @throws IllegalArgumentException
-         *         If {@code name} is {@code null} or the empty String
-         */
-        public Builder osName(String name) {
-            if (name == null || name.isEmpty())
-                throw new IllegalArgumentException("OS name is null or empty");
-            osName = name;
-            return this;
-        }
-
-        /**
-         * Sets the operating system architecture.
-         *
-         * @param  arch
-         *         The operating system architecture
-         *
-         * @return This builder
-         *
-         * @throws IllegalArgumentException
-         *         If {@code name} is {@code null} or the empty String
-         */
-        public Builder osArch(String arch) {
-            if (arch == null || arch.isEmpty())
-                throw new IllegalArgumentException("OS arch is null or empty");
-            osArch = arch;
-            return this;
-        }
-
-        /**
-         * Sets the operating system version.
-         *
-         * @param  version
-         *         The operating system version
-         *
-         * @return This builder
-         *
-         * @throws IllegalArgumentException
-         *         If {@code name} is {@code null} or the empty String
-         */
-        public Builder osVersion(String version) {
-            if (version == null || version.isEmpty())
-                throw new IllegalArgumentException("OS version is null or empty");
-            osVersion = version;
-            return this;
-        }
-
-        /**
          * Builds and returns a {@code ModuleDescriptor} from its components.
          *
          * <p> The module will require "{@code java.base}" even if the dependence
@@ -2208,6 +2162,7 @@
                     && !this.requires.containsKey("java.base")) {
                 requires.add(new Requires(Set.of(Requires.Modifier.MANDATED),
                                           "java.base",
+                                          null,
                                           null));
             }
 
@@ -2215,6 +2170,7 @@
 
             return new ModuleDescriptor(name,
                                         version,
+                                        rawVersionString,
                                         modifiers,
                                         requires,
                                         exports,
@@ -2222,10 +2178,7 @@
                                         uses,
                                         provides,
                                         packages,
-                                        mainClass,
-                                        osName,
-                                        osArch,
-                                        osVersion);
+                                        mainClass);
         }
 
     }
@@ -2237,9 +2190,11 @@
      * 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
+     * descriptor that does not have a version. If both versions are {@linkplain
+     * Version#parse(String) unparseable} then the {@linkplain #rawVersion()
+     * raw version strings} are compared lexicographically. 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
@@ -2263,6 +2218,9 @@
         c = compare(this.version, that.version);
         if (c != 0) return c;
 
+        c = compare(this.rawVersionString, that.rawVersionString);
+        if (c != 0) return c;
+
         long v1 = modsValue(this.modifiers());
         long v2 = modsValue(that.modifiers());
         c = Long.compare(v1, v2);
@@ -2289,15 +2247,6 @@
         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;
     }
 
@@ -2333,10 +2282,8 @@
                 && uses.equals(that.uses)
                 && provides.equals(that.provides)
                 && Objects.equals(version, that.version)
-                && Objects.equals(mainClass, that.mainClass)
-                && Objects.equals(osName, that.osName)
-                && Objects.equals(osArch, that.osArch)
-                && Objects.equals(osVersion, that.osVersion));
+                && Objects.equals(rawVersionString, that.rawVersionString)
+                && Objects.equals(mainClass, that.mainClass));
     }
 
     /**
@@ -2361,10 +2308,8 @@
             hc = hc * 43 + uses.hashCode();
             hc = hc * 43 + provides.hashCode();
             hc = hc * 43 + Objects.hashCode(version);
+            hc = hc * 43 + Objects.hashCode(rawVersionString);
             hc = hc * 43 + Objects.hashCode(mainClass);
-            hc = hc * 43 + Objects.hashCode(osName);
-            hc = hc * 43 + Objects.hashCode(osArch);
-            hc = hc * 43 + Objects.hashCode(osVersion);
             if (hc == 0)
                 hc = -1;
             hash = hc;
@@ -2713,8 +2658,8 @@
                 public void requires(ModuleDescriptor.Builder builder,
                                      Set<Requires.Modifier> ms,
                                      String mn,
-                                     String compiledVersion) {
-                    builder.requires(ms, mn, compiledVersion);
+                                     String rawCompiledVersion) {
+                    builder.requires(ms, mn, rawCompiledVersion);
                 }
 
                 @Override
@@ -2762,9 +2707,6 @@
                                                             Set<Provides> provides,
                                                             Set<String> packages,
                                                             String mainClass,
-                                                            String osName,
-                                                            String osArch,
-                                                            String osVersion,
                                                             int hashCode) {
                     return new ModuleDescriptor(name,
                                                 version,
@@ -2776,9 +2718,6 @@
                                                 provides,
                                                 packages,
                                                 mainClass,
-                                                osName,
-                                                osArch,
-                                                osVersion,
                                                 hashCode,
                                                 false);
                 }
--- a/src/java.base/share/classes/java/lang/module/ModuleFinder.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/java/lang/module/ModuleFinder.java	Thu Mar 23 22:57:12 2017 +0000
@@ -25,8 +25,6 @@
 
 package java.lang.module;
 
-import java.io.File;
-import java.io.FilePermission;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
@@ -43,9 +41,9 @@
 import java.util.Set;
 
 import jdk.internal.module.ModuleBootstrap;
+import jdk.internal.module.ModulePatcher;
 import jdk.internal.module.ModulePath;
 import jdk.internal.module.SystemModuleFinder;
-import sun.security.action.GetPropertyAction;
 
 /**
  * A finder of modules. A {@code ModuleFinder} is used to find modules during
@@ -146,9 +144,9 @@
      *
      * <p> If there is a security manager set then its {@link
      * SecurityManager#checkPermission(Permission) checkPermission} method is
-     * invoked to check that the caller has been granted {@link FilePermission}
-     * to recursively read the directory that is the value of the system
-     * property {@code java.home}. </p>
+     * invoked to check that the caller has been granted
+     * {@link RuntimePermission RuntimePermission("accessSystemModules")}
+     * to access the system modules. </p>
      *
      * @return A {@code ModuleFinder} that locates the system modules
      *
@@ -156,26 +154,29 @@
      *         If denied by the security manager
      */
     static ModuleFinder ofSystem() {
-        String home;
-
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            PrivilegedAction<String> pa = new GetPropertyAction("java.home");
-            home = AccessController.doPrivileged(pa);
-            Permission p = new FilePermission(home + File.separator + "-", "read");
-            sm.checkPermission(p);
+            sm.checkPermission(new RuntimePermission("accessSystemModules"));
+            PrivilegedAction<ModuleFinder> pa = ModuleFinder::privilegedOfSystem;
+            return AccessController.doPrivileged(pa);
         } else {
-            home = System.getProperty("java.home");
+            return privilegedOfSystem();
         }
+    }
 
+    /**
+     * Returns a module finder that locates the system modules. This method
+     * assumes it has permissions to access the runtime image.
+     */
+    private static ModuleFinder privilegedOfSystem() {
+        String home = System.getProperty("java.home");
         Path modules = Paths.get(home, "lib", "modules");
         if (Files.isRegularFile(modules)) {
             return SystemModuleFinder.getInstance();
         } else {
-            Path mlib = Paths.get(home, "modules");
-            if (Files.isDirectory(mlib)) {
-                // exploded build may be patched
-                return ModulePath.of(ModuleBootstrap.patcher(), mlib);
+            Path dir = Paths.get(home, "modules");
+            if (Files.isDirectory(dir)) {
+                return privilegedOf(ModuleBootstrap.patcher(), dir);
             } else {
                 throw new InternalError("Unable to detect the run-time image");
             }
@@ -183,6 +184,26 @@
     }
 
     /**
+     * Returns a module finder that locates the system modules in an exploded
+     * image. The image may be patched.
+     */
+    private static ModuleFinder privilegedOf(ModulePatcher patcher, Path dir) {
+        ModuleFinder finder = ModulePath.of(patcher, dir);
+        return new ModuleFinder() {
+            @Override
+            public Optional<ModuleReference> find(String name) {
+                PrivilegedAction<Optional<ModuleReference>> pa = () -> finder.find(name);
+                return AccessController.doPrivileged(pa);
+            }
+            @Override
+            public Set<ModuleReference> findAll() {
+                PrivilegedAction<Set<ModuleReference>> pa = finder::findAll;
+                return AccessController.doPrivileged(pa);
+            }
+        };
+    }
+
+    /**
      * Returns a module finder that locates modules on the file system by
      * searching a sequence of directories and/or packaged modules.
      *
@@ -201,7 +222,7 @@
      *
      * <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. It it an error if a directory contains more than one
+     * exploded module. It is 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
--- a/src/java.base/share/classes/java/lang/module/ModuleReader.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/java/lang/module/ModuleReader.java	Thu Mar 23 22:57:12 2017 +0000
@@ -48,7 +48,11 @@
  * <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>
+ * class file for {@code java.lang.Object}. A module reader may treat
+ * directories in the module content as resources (whether it does or not is
+ * module reader specific). Where the module content contains a directory
+ * that can be located as a resource then its name ends with a slash ('/'). The
+ * directory can also be located with a name that drops the trailing slash. </p>
  *
  * <p> A {@code ModuleReader} is {@linkplain ModuleReference#open open} upon
  * creation and is closed by invoking the {@link #close close} method.  Failure
@@ -80,6 +84,9 @@
     /**
      * Finds a resource, returning a URI to the resource in the module.
      *
+     * <p> If the module reader can determine that the name locates a directory
+     * then the resulting URI will end with a slash ('/'). </p>
+     *
      * @param  name
      *         The name of the resource to open for reading
      *
@@ -140,7 +147,7 @@
      *
      * @apiNote This method is intended for high-performance class loading. It
      * is not capable (or intended) to read arbitrary large resources that
-     * could potentially be 2GB or larger. The rational for using this method
+     * could potentially be 2GB or larger. The rationale for using this method
      * in conjunction with the {@code release} method is to allow module reader
      * implementations manage buffers in an efficient manner.
      *
@@ -195,7 +202,9 @@
 
     /**
      * Lists the contents of the module, returning a stream of elements that
-     * are the names of all resources in the module.
+     * are the names of all resources in the module. Whether the stream of
+     * elements includes names corresponding to directories in the module is
+     * module reader specific.
      *
      * <p> In lazy implementations then an {@code IOException} may be thrown
      * when using the stream to list the module contents. If this occurs then
--- a/src/java.base/share/classes/java/lang/module/Resolver.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/java/lang/module/Resolver.java	Thu Mar 23 22:57:12 2017 +0000
@@ -47,6 +47,7 @@
 
 import jdk.internal.module.ModuleHashes;
 import jdk.internal.module.ModuleReferenceImpl;
+import jdk.internal.module.ModuleTarget;
 
 /**
  * The resolver used by {@link Configuration#resolve} and {@link
@@ -69,11 +70,9 @@
     // 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
@@ -110,16 +109,6 @@
                     }
                 }
             }
-            value = parent.osVersion();
-            if (value != null) {
-                if (osVersion == null) {
-                    osVersion  = value;
-                } else {
-                    if (!value.equals(osVersion)) {
-                        failParentConflict("OS version", osVersion, value);
-                    }
-                }
-            }
         }
     }
 
@@ -318,13 +307,15 @@
      * the target platform with the constraints of other modules.
      */
     private void addFoundModule(ModuleReference mref) {
-        ModuleDescriptor descriptor = mref.descriptor();
-        nameToReference.put(descriptor.name(), mref);
+        String mn = mref.descriptor().name();
 
-        if (descriptor.osName().isPresent()
-                || descriptor.osArch().isPresent()
-                || descriptor.osVersion().isPresent())
-            checkTargetConstraints(descriptor);
+        if (mref instanceof ModuleReferenceImpl) {
+            ModuleTarget target = ((ModuleReferenceImpl)mref).moduleTarget();
+            if (target != null)
+                checkTargetConstraints(mn, target);
+        }
+
+        nameToReference.put(mn, mref);
     }
 
     /**
@@ -332,58 +323,44 @@
      * 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);
+    private void checkTargetConstraints(String mn, ModuleTarget target) {
+        String value = target.osName();
         if (value != null) {
             if (osName == null) {
                 osName = value;
             } else {
                 if (!value.equals(osName)) {
-                    failTargetConstraint(descriptor);
+                    failTargetConstraint(mn, target);
                 }
             }
         }
-        value = descriptor.osArch().orElse(null);
+        value = target.osArch();
         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);
+                    failTargetConstraint(mn, target);
                 }
             }
         }
     }
 
-    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 void failTargetConstraint(String mn, ModuleTarget target) {
+        String s1 = targetAsString(osName, osArch);
+        String s2 = targetAsString(target.osName(), target.osArch());
+        findFail("Module %s has constraints on target platform (%s) that"
+                 + " conflict with other modules: %s", mn, 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(ModuleTarget target) {
+        return targetAsString(target.osName(), target.osArch());
     }
 
-    private String targetAsString(String osName, String osArch, String osVersion) {
+    private String targetAsString(String osName, String osArch) {
         return new StringJoiner("-")
                 .add(Objects.toString(osName, "*"))
                 .add(Objects.toString(osArch, "*"))
-                .add(Objects.toString(osVersion, "*"))
                 .toString();
     }
 
@@ -712,16 +689,30 @@
 
 
     /**
-     * Checks the readability graph to ensure that no two modules export the
-     * same package to a module. This includes the case where module M has
-     * a local package P and M reads another module that exports P to M.
-     * Also checks the uses/provides of module M to ensure that it reads a
-     * module that exports the package of the service type to M.
+     * Checks the readability graph to ensure that
+     * <ol>
+     *   <li><p> A module does not read two or more modules with the same name.
+     *   This includes the case where a module reads another another with the
+     *   same name as itself. </p></li>
+     *   <li><p> Two or more modules in the configuration don't export the same
+     *   package to a module that reads both. This includes the case where a
+     *   module {@code M} containing package {@code p} reads another module
+     *   that exports {@code p} to {@code M}. </p></li>
+     *   <li><p> A module {@code M} doesn't declare that it "{@code uses p.S}"
+     *   or "{@code provides p.S with ...}" but package {@code p} is neither
+     *   in module {@code M} nor exported to {@code M} by any module that
+     *   {@code M} reads. </p></li>
+     * </ol>
      */
     private void checkExportSuppliers(Map<ResolvedModule, Set<ResolvedModule>> graph) {
 
         for (Map.Entry<ResolvedModule, Set<ResolvedModule>> e : graph.entrySet()) {
             ModuleDescriptor descriptor1 = e.getKey().descriptor();
+            String name1 = descriptor1.name();
+
+            // the names of the modules that are read (including self)
+            Set<String> names = new HashSet<>();
+            names.add(name1);
 
             // the map of packages that are local or exported to descriptor1
             Map<String, ModuleDescriptor> packageToExporter = new HashMap<>();
@@ -737,9 +728,20 @@
             for (ResolvedModule endpoint : reads) {
                 ModuleDescriptor descriptor2 = endpoint.descriptor();
 
+                String name2 = descriptor2.name();
+                if (descriptor2 != descriptor1 && !names.add(name2)) {
+                    if (name2.equals(name1)) {
+                        resolveFail("Module %s reads another module named %s",
+                                    name1, name1);
+                    } else{
+                        resolveFail("Module %s reads more than one module named %s",
+                                     name1, name2);
+                    }
+                }
+
                 if (descriptor2.isAutomatic()) {
                     // automatic modules read self and export all packages
-                    if (descriptor2 != descriptor1){
+                    if (descriptor2 != descriptor1) {
                         for (String source : descriptor2.packages()) {
                             ModuleDescriptor supplier
                                 = packageToExporter.putIfAbsent(source, descriptor2);
--- a/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java	Thu Mar 23 22:57:12 2017 +0000
@@ -28,9 +28,12 @@
 import java.lang.annotation.Annotation;
 import java.security.AccessController;
 
+import jdk.internal.misc.VM;
+import jdk.internal.module.IllegalAccessLogger;
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.Reflection;
 import jdk.internal.reflect.ReflectionFactory;
+import sun.security.action.GetPropertyAction;
 
 /**
  * The {@code AccessibleObject} class is the base class for {@code Field},
@@ -288,27 +291,20 @@
         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)) {
-            dumpStackIfOpenedReflectively(declaringModule, pn, callerModule);
-            return true;
-        }
-
-        // package is exported to caller
-        boolean isExported = declaringModule.isExported(pn, callerModule);
-        boolean isClassPublic = Modifier.isPublic(declaringClass.getModifiers());
+        String pn = declaringClass.getPackageName();
         int modifiers;
         if (this instanceof Executable) {
             modifiers = ((Executable) this).getModifiers();
         } else {
             modifiers = ((Field) this).getModifiers();
         }
-        if (isExported && isClassPublic) {
 
+        // class is public and package is exported to caller
+        boolean isClassPublic = Modifier.isPublic(declaringClass.getModifiers());
+        if (isClassPublic && declaringModule.isExported(pn, callerModule)) {
             // member is public
             if (Modifier.isPublic(modifiers)) {
-                dumpStackIfExportedReflectively(declaringModule, pn, callerModule);
+                logIfExportedByBackdoor(caller, declaringClass);
                 return true;
             }
 
@@ -316,11 +312,17 @@
             if (Modifier.isProtected(modifiers)
                 && Modifier.isStatic(modifiers)
                 && isSubclassOf(caller, declaringClass)) {
-                dumpStackIfExportedReflectively(declaringModule, pn, callerModule);
+                logIfExportedByBackdoor(caller, declaringClass);
                 return true;
             }
         }
 
+        // package is open to caller
+        if (declaringModule.isOpen(pn, callerModule)) {
+            logIfOpenedByBackdoor(caller, declaringClass);
+            return true;
+        }
+
         if (throwExceptionIfDenied) {
             // not accessible
             String msg = "Unable to make ";
@@ -333,7 +335,7 @@
                 msg += "opens";
             msg += " " + pn + "\" to " + callerModule;
             InaccessibleObjectException e = new InaccessibleObjectException(msg);
-            if (Reflection.printStackTraceWhenAccessFails()) {
+            if (printStackTraceWhenAccessFails()) {
                 e.printStackTrace(System.err);
             }
             throw e;
@@ -351,48 +353,35 @@
         return false;
     }
 
-    private void dumpStackIfOpenedReflectively(Module module,
-                                               String pn,
-                                               Module other) {
-        dumpStackIfExposedReflectively(module, pn, other, true);
+    private void logIfOpenedByBackdoor(Class<?> caller, Class<?> declaringClass) {
+        Module callerModule = caller.getModule();
+        Module targetModule = declaringClass.getModule();
+        // callerModule is null during early startup
+        if (callerModule != null && !callerModule.isNamed() && targetModule.isNamed()) {
+            IllegalAccessLogger logger = IllegalAccessLogger.illegalAccessLogger();
+            if (logger != null) {
+                logger.logIfOpenedByBackdoor(caller, declaringClass, this::toShortString);
+            }
+        }
     }
 
-    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))
-        {
-            String msg = other + " allowed to invoke setAccessible on ";
-            if (this instanceof Field)
-                msg += "field ";
-            msg += this;
-            new Exception(msg) {
-                private static final long serialVersionUID = 42L;
-                public String toString() {
-                    return "WARNING: " + getMessage();
-                }
-            }.printStackTrace(System.err);
+    private void logIfExportedByBackdoor(Class<?> caller, Class<?> declaringClass) {
+        Module callerModule = caller.getModule();
+        Module targetModule = declaringClass.getModule();
+        // callerModule is null during early startup
+        if (callerModule != null && !callerModule.isNamed() && targetModule.isNamed()) {
+            IllegalAccessLogger logger = IllegalAccessLogger.illegalAccessLogger();
+            if (logger != null) {
+                logger.logIfExportedByBackdoor(caller, declaringClass, this::toShortString);
+            }
         }
     }
 
     /**
-     * Returns the package name of the given class.
+     * Returns a short descriptive string to describe this object in log messages.
      */
-    private static String packageName(Class<?> c) {
-        while (c.isArray()) {
-            c = c.getComponentType();
-        }
-        String pn = c.getPackageName();
-        return (pn != null) ? pn : "";
+    String toShortString() {
+        return toString();
     }
 
     /**
@@ -409,6 +398,7 @@
      * it should use {@link #canAccess(Object)}.
      *
      * @revised 9
+     * @spec JPMS
      */
     @Deprecated(since="9")
     public boolean isAccessible() {
@@ -483,10 +473,7 @@
         } else {
             targetClass = Modifier.isStatic(modifiers) ? null : obj.getClass();
         }
-        return Reflection.verifyMemberAccess(caller,
-                                             declaringClass,
-                                             targetClass,
-                                             modifiers);
+        return verifyAccess(caller, declaringClass, targetClass, modifiers);
     }
 
     /**
@@ -527,7 +514,7 @@
         return AnnotatedElement.super.isAnnotationPresent(annotationClass);
     }
 
-   /**
+    /**
      * @throws NullPointerException {@inheritDoc}
      * @since 1.8
      */
@@ -598,8 +585,21 @@
                            Class<?> targetClass, int modifiers)
         throws IllegalAccessException
     {
+        if (!verifyAccess(caller, memberClass, targetClass, modifiers)) {
+            IllegalAccessException e = Reflection.newIllegalAccessException(
+                caller, memberClass, targetClass, modifiers);
+            if (printStackTraceWhenAccessFails()) {
+                e.printStackTrace(System.err);
+            }
+            throw e;
+        }
+    }
+
+    final boolean verifyAccess(Class<?> caller, Class<?> memberClass,
+                               Class<?> targetClass, int modifiers)
+    {
         if (caller == memberClass) {  // quick check
-            return;             // ACCESS IS OK
+            return true;             // ACCESS IS OK
         }
         Object cache = securityCheckCache;  // read volatile
         if (targetClass != null // instance member or constructor
@@ -610,26 +610,31 @@
                 Class<?>[] cache2 = (Class<?>[]) cache;
                 if (cache2[1] == targetClass &&
                     cache2[0] == caller) {
-                    return;     // ACCESS IS OK
+                    return true;     // ACCESS IS OK
                 }
                 // (Test cache[1] first since range check for [1]
                 // subsumes range check for [0].)
             }
         } else if (cache == caller) {
             // Non-protected case (or targetClass == memberClass or static member).
-            return;             // ACCESS IS OK
+            return true;             // ACCESS IS OK
         }
 
         // If no return, fall through to the slow path.
-        slowCheckMemberAccess(caller, memberClass, targetClass, modifiers);
+        return slowVerifyAccess(caller, memberClass, targetClass, modifiers);
     }
 
     // Keep all this slow stuff out of line:
-    void slowCheckMemberAccess(Class<?> caller, Class<?> memberClass,
-                               Class<?> targetClass, int modifiers)
-        throws IllegalAccessException
+    private boolean slowVerifyAccess(Class<?> caller, Class<?> memberClass,
+                                     Class<?> targetClass, int modifiers)
     {
-        Reflection.ensureMemberAccess(caller, memberClass, targetClass, modifiers);
+        if (!Reflection.verifyMemberAccess(caller, memberClass, targetClass, modifiers)) {
+            // access denied
+            return false;
+        }
+
+        // access okay
+        logIfExportedByBackdoor(caller, memberClass);
 
         // Success: Update the cache.
         Object cache = (targetClass != null
@@ -643,5 +648,27 @@
         // guarantees that the initializing stores for the cache
         // elements will occur before the volatile write.
         securityCheckCache = cache;         // write volatile
+        return true;
+    }
+
+    // true to print a stack trace when access fails
+    private static volatile boolean printStackWhenAccessFails;
+
+    // true if printStack* values are initialized
+    private static volatile boolean printStackPropertiesSet;
+
+    /**
+     * Returns true if a stack trace should be printed when access fails.
+     */
+    private static boolean printStackTraceWhenAccessFails() {
+        if (!printStackPropertiesSet && VM.initLevel() >= 1) {
+            String s = GetPropertyAction.privilegedGetProperty(
+                    "sun.reflect.debugModuleAccessChecks");
+            if (s != null) {
+                printStackWhenAccessFails = !s.equalsIgnoreCase("false");
+            }
+            printStackPropertiesSet = true;
+        }
+        return printStackWhenAccessFails;
     }
 }
--- a/src/java.base/share/classes/java/lang/reflect/Constructor.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/java/lang/reflect/Constructor.java	Thu Mar 23 22:57:12 2017 +0000
@@ -38,6 +38,7 @@
 import sun.reflect.generics.scope.ConstructorScope;
 import java.lang.annotation.Annotation;
 import java.lang.annotation.AnnotationFormatError;
+import java.util.StringJoiner;
 
 /**
  * {@code Constructor} provides information about, and access to, a single
@@ -360,6 +361,20 @@
         sb.append(getDeclaringClass().getTypeName());
     }
 
+    @Override
+    String toShortString() {
+        StringBuilder sb = new StringBuilder("constructor ");
+        sb.append(getDeclaringClass().getTypeName());
+        sb.append('(');
+        StringJoiner sj = new StringJoiner(",");
+        for (Class<?> parameterType : getParameterTypes()) {
+            sj.add(parameterType.getTypeName());
+        }
+        sb.append(sj);
+        sb.append(')');
+        return sb.toString();
+    }
+
     /**
      * Returns a string describing this {@code Constructor},
      * including type parameters.  The string is formatted as the
--- a/src/java.base/share/classes/java/lang/reflect/Field.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/java/lang/reflect/Field.java	Thu Mar 23 22:57:12 2017 +0000
@@ -324,6 +324,11 @@
             + getName());
     }
 
+    @Override
+    String toShortString() {
+        return "field " + getDeclaringClass().getTypeName() + "." + getName();
+    }
+
     /**
      * Returns a string describing this {@code Field}, including
      * its generic type.  The format is the access modifiers for the
--- a/src/java.base/share/classes/java/lang/reflect/Layer.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/java/lang/reflect/Layer.java	Thu Mar 23 22:57:12 2017 +0000
@@ -66,9 +66,7 @@
  * 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 {@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>
+ * be in the same layer or a {@link #parents() parent} layer. </p>
  *
  * <p> The {@link #defineModulesWithOneLoader defineModulesWithOneLoader} and
  * {@link #defineModulesWithManyLoaders defineModulesWithManyLoaders} methods
@@ -91,6 +89,28 @@
  * built-in</a> into the Java virtual machine. The boot layer will often be
  * the {@link #parents() parent} when creating additional layers. </p>
  *
+ * <p> Each {@code Module} in a layer is created so that it {@link
+ * Module#isExported(String) exports} and {@link Module#isOpen(String) opens}
+ * the packages described by its {@link ModuleDescriptor}. Qualified exports
+ * (where a package is exported to a set of target modules rather than all
+ * modules) are reified when creating the layer as follows: </p>
+ * <ul>
+ *     <li> If module {@code X} exports a package to {@code Y}, and if the
+ *     runtime {@code Module} {@code X} reads {@code Module} {@code Y}, then
+ *     the package is exported to {@code Module} {@code Y} (which may be in
+ *     the same layer as {@code X} or a parent layer). </li>
+ *
+ *     <li> If module {@code X} exports a package to {@code Y}, and if the
+ *     runtime {@code Module} {@code X} does not read {@code Y} then target
+ *     {@code Y} is located as if by invoking {@link #findModule(String)
+ *     findModule} to find the module in the layer or its parent layers. If
+ *     {@code Y} is found then the package is exported to the instance of
+ *     {@code Y} that was found. If {@code Y} is not found then the qualified
+ *     export is ignored. </li>
+ * </ul>
+ *
+ * <p> Qualified opens are handled in same way as qualified exports. </p>
+ *
  * <p> As when creating a {@code Configuration},
  * {@link ModuleDescriptor#isAutomatic() automatic} modules receive special
  * treatment when creating a layer. An automatic module is created in the
@@ -193,7 +213,7 @@
         }
 
         private void ensureInLayer(Module source) {
-            if (!layer.modules().contains(source))
+            if (source.getLayer() != layer)
                 throw new IllegalArgumentException(source + " not in layer");
         }
 
@@ -220,9 +240,8 @@
          * @see Module#addReads
          */
         public Controller addReads(Module source, Module target) {
-            Objects.requireNonNull(source);
+            ensureInLayer(source);
             Objects.requireNonNull(target);
-            ensureInLayer(source);
             Modules.addReads(source, target);
             return this;
         }
@@ -248,9 +267,9 @@
          * @see Module#addOpens
          */
         public Controller addOpens(Module source, String pn, Module target) {
-            Objects.requireNonNull(source);
+            ensureInLayer(source);
+            Objects.requireNonNull(pn);
             Objects.requireNonNull(target);
-            ensureInLayer(source);
             Modules.addOpens(source, pn, target);
             return this;
         }
@@ -408,8 +427,8 @@
      * </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>
+     * a module named "{@code java.base}", or a module contains a package named
+     * "{@code java}" or a package with a 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
@@ -418,7 +437,7 @@
      * @param  cf
      *         The configuration for the layer
      * @param  parentLayers
-     *         The list parent layers in search order
+     *         The list of parent layers in search order
      * @param  parentLoader
      *         The parent class loader for the class loader created by this
      *         method; may be {@code null} for the bootstrap class loader
@@ -485,7 +504,7 @@
      * @param  cf
      *         The configuration for the layer
      * @param  parentLayers
-     *         The list parent layers in search order
+     *         The list of parent layers in search order
      * @param  parentLoader
      *         The parent class loader for each of the class loaders created by
      *         this method; may be {@code null} for the bootstrap class loader
@@ -497,8 +516,10 @@
      *         the parent layers, including order
      * @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.}"
+     *         a module named "{@code java.base}" or a module contains a package
+     *         named "{@code java}" or a package with a name starting with
+     *         "{@code java.}"
+     *
      * @throws SecurityException
      *         If {@code RuntimePermission("createClassLoader")} or
      *         {@code RuntimePermission("getClassLoader")} is denied by
@@ -558,10 +579,11 @@
      *
      * <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>
+     * with a package named "{@code java}" or a package name starting with
+     * "{@code java.}" and the module 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.
@@ -575,7 +597,7 @@
      * @param  cf
      *         The configuration for the layer
      * @param  parentLayers
-     *         The list parent layers in search order
+     *         The list of parent layers in search order
      * @param  clf
      *         The function to map a module name to a class loader
      *
@@ -754,10 +776,16 @@
      * @return A possibly-empty unmodifiable set of the modules in this layer
      */
     public Set<Module> modules() {
-        return Collections.unmodifiableSet(
-                nameToModule.values().stream().collect(Collectors.toSet()));
+        Set<Module> modules = this.modules;
+        if (modules == null) {
+            this.modules = modules =
+                Collections.unmodifiableSet(new HashSet<>(nameToModule.values()));
+        }
+        return modules;
     }
 
+    private volatile Set<Module> modules;
+
 
     /**
      * Returns the module with the given name in this layer, or if not in this
@@ -776,6 +804,8 @@
      */
     public Optional<Module> findModule(String name) {
         Objects.requireNonNull(name);
+        if (this == EMPTY_LAYER)
+            return Optional.empty();
         Module m = nameToModule.get(name);
         if (m != null)
             return Optional.of(m);
--- a/src/java.base/share/classes/java/lang/reflect/Method.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/java/lang/reflect/Method.java	Thu Mar 23 22:57:12 2017 +0000
@@ -42,6 +42,7 @@
 import java.lang.annotation.Annotation;
 import java.lang.annotation.AnnotationFormatError;
 import java.nio.ByteBuffer;
+import java.util.StringJoiner;
 
 /**
  * A {@code Method} provides information about, and access to, a single method
@@ -416,6 +417,21 @@
         sb.append(getName());
     }
 
+    @Override
+    String toShortString() {
+        StringBuilder sb = new StringBuilder("method ");
+        sb.append(getDeclaringClass().getTypeName()).append('.');
+        sb.append(getName());
+        sb.append('(');
+        StringJoiner sj = new StringJoiner(",");
+        for (Class<?> parameterType : getParameterTypes()) {
+            sj.add(parameterType.getTypeName());
+        }
+        sb.append(sj);
+        sb.append(')');
+        return sb.toString();
+    }
+
     /**
      * Returns a string describing this {@code Method}, including
      * type parameters.  The string is formatted as the method access
--- a/src/java.base/share/classes/java/lang/reflect/Module.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/java/lang/reflect/Module.java	Thu Mar 23 22:57:12 2017 +0000
@@ -39,8 +39,10 @@
 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.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
@@ -51,11 +53,11 @@
 
 import jdk.internal.loader.BuiltinClassLoader;
 import jdk.internal.loader.BootLoader;
-import jdk.internal.loader.ResourceHelper;
 import jdk.internal.misc.JavaLangAccess;
 import jdk.internal.misc.JavaLangReflectModuleAccess;
 import jdk.internal.misc.SharedSecrets;
 import jdk.internal.module.ServicesCatalog;
+import jdk.internal.module.Resources;
 import jdk.internal.org.objectweb.asm.AnnotationVisitor;
 import jdk.internal.org.objectweb.asm.Attribute;
 import jdk.internal.org.objectweb.asm.ClassReader;
@@ -369,28 +371,19 @@
      * If {@code syncVM} is {@code true} then the VM is notified.
      */
     private void implAddReads(Module other, boolean syncVM) {
-        Objects.requireNonNull(other);
+        if (!canRead(other)) {
+            // update VM first, just in case it fails
+            if (syncVM) {
+                if (other == ALL_UNNAMED_MODULE) {
+                    addReads0(this, null);
+                } else {
+                    addReads0(this, other);
+                }
+            }
 
-        // nothing to do
-        if (other == this || !this.isNamed())
-            return;
-
-        // check if we already read this module
-        Set<Module> reads = this.reads;
-        if (reads != null && reads.contains(other))
-            return;
-
-        // update VM first, just in case it fails
-        if (syncVM) {
-            if (other == ALL_UNNAMED_MODULE) {
-                addReads0(this, null);
-            } else {
-                addReads0(this, other);
-            }
+            // add reflective read
+            reflectivelyReads.putIfAbsent(this, other, Boolean.TRUE);
         }
-
-        // add reflective read
-        reflectivelyReads.putIfAbsent(this, other, Boolean.TRUE);
     }
 
 
@@ -553,7 +546,7 @@
      * Returns {@code true} if this module exports or opens a package to
      * the given module via its module declaration.
      */
-    boolean isStaticallyExportedOrOpen(String pn, Module other, boolean open) {
+    private boolean isStaticallyExportedOrOpen(String pn, Module other, boolean open) {
         // package is open to everyone or <other>
         Map<String, Set<Module>> openPackages = this.openPackages;
         if (openPackages != null) {
@@ -909,9 +902,7 @@
      * Returns an array of the package names of the packages in this module.
      *
      * <p> For named modules, the returned array contains an element for each
-     * package in the module. It may contain elements corresponding to packages
-     * added to the module, <a href="Proxy.html#dynamicmodule">dynamic modules</a>
-     * for example, after it was loaded.
+     * package in the module. </p>
      *
      * <p> For unnamed modules, this method is the equivalent to invoking the
      * {@link ClassLoader#getDefinedPackages() getDefinedPackages} method of
@@ -950,15 +941,6 @@
     }
 
     /**
-     * Add a package to this module.
-     *
-     * @apiNote This method is for Proxy use.
-     */
-    void addPackage(String pn) {
-        implAddPackage(pn, true);
-    }
-
-    /**
      * Add a package to this module without notifying the VM.
      *
      * @apiNote This method is VM white-box testing.
@@ -1080,20 +1062,28 @@
 
             // reads
             Set<Module> reads = new HashSet<>();
+
+            // name -> source Module when in parent layer
+            Map<String, Module> nameToSource = Collections.emptyMap();
+
             for (ResolvedModule other : resolvedModule.reads()) {
                 Module m2 = null;
                 if (other.configuration() == cf) {
-                    String dn = other.reference().descriptor().name();
-                    m2 = nameToModule.get(dn);
+                    // this configuration
+                    m2 = nameToModule.get(other.name());
+                    assert m2 != null;
                 } else {
+                    // parent layer
                     for (Layer parent: layer.parents()) {
                         m2 = findModule(parent, other);
                         if (m2 != null)
                             break;
                     }
+                    assert m2 != null;
+                    if (nameToSource.isEmpty())
+                        nameToSource = new HashMap<>();
+                    nameToSource.put(other.name(), m2);
                 }
-                assert m2 != null;
-
                 reads.add(m2);
 
                 // update VM view
@@ -1107,7 +1097,7 @@
             }
 
             // exports and opens
-            initExportsAndOpens(descriptor, nameToModule, m);
+            initExportsAndOpens(m, nameToSource, nameToModule, layer.parents());
         }
 
         // register the modules in the boot layer
@@ -1159,15 +1149,17 @@
                 .orElse(null);
     }
 
+
     /**
      * Initialize the maps of exported and open packages for module m.
      */
-    private static void initExportsAndOpens(ModuleDescriptor descriptor,
+    private static void initExportsAndOpens(Module m,
+                                            Map<String, Module> nameToSource,
                                             Map<String, Module> nameToModule,
-                                            Module m)
-    {
+                                            List<Layer> parents) {
         // The VM doesn't special case open or automatic modules so need to
         // export all packages
+        ModuleDescriptor descriptor = m.getDescriptor();
         if (descriptor.isOpen() || descriptor.isAutomatic()) {
             assert descriptor.opens().isEmpty();
             for (String source : descriptor.packages()) {
@@ -1187,8 +1179,7 @@
                 // qualified opens
                 Set<Module> targets = new HashSet<>();
                 for (String target : opens.targets()) {
-                    // only open to modules that are in this configuration
-                    Module m2 = nameToModule.get(target);
+                    Module m2 = findModule(target, nameToSource, nameToModule, parents);
                     if (m2 != null) {
                         addExports0(m, source, m2);
                         targets.add(m2);
@@ -1217,8 +1208,7 @@
                 // qualified exports
                 Set<Module> targets = new HashSet<>();
                 for (String target : exports.targets()) {
-                    // only export to modules that are in this configuration
-                    Module m2 = nameToModule.get(target);
+                    Module m2 = findModule(target, nameToSource, nameToModule, parents);
                     if (m2 != null) {
                         // skip qualified export if already open to m2
                         if (openToTargets == null || !openToTargets.contains(m2)) {
@@ -1244,6 +1234,32 @@
             m.exportedPackages = exportedPackages;
     }
 
+    /**
+     * Find the runtime Module with the given name. The module name is the
+     * name of a target module in a qualified exports or opens directive.
+     *
+     * @param target The target module to find
+     * @param nameToSource The modules in parent layers that are read
+     * @param nameToModule The modules in the layer under construction
+     * @param parents The parent layers
+     */
+    private static Module findModule(String target,
+                                     Map<String, Module> nameToSource,
+                                     Map<String, Module> nameToModule,
+                                     List<Layer> parents) {
+        Module m = nameToSource.get(target);
+        if (m == null) {
+            m = nameToModule.get(target);
+            if (m == null) {
+                for (Layer parent : parents) {
+                    m = parent.findModule(target).orElse(null);
+                    if (m != null) break;
+                }
+            }
+        }
+        return m;
+    }
+
 
     // -- annotations --
 
@@ -1428,12 +1444,12 @@
             name = name.substring(1);
         }
 
-        if (isNamed() && !ResourceHelper.isSimpleResource(name)) {
+        if (isNamed() && Resources.canEncapsulate(name)) {
             Module caller = Reflection.getCallerClass().getModule();
             if (caller != this && caller != Object.class.getModule()) {
                 // ignore packages added for proxies via addPackage
                 Set<String> packages = getDescriptor().packages();
-                String pn = ResourceHelper.getPackageName(name);
+                String pn = Resources.toPackageName(name);
                 if (packages.contains(pn) && !isOpen(pn, caller)) {
                     // resource is in package not open to caller
                     return null;
@@ -1531,24 +1547,24 @@
                     m.implAddReads(Module.ALL_UNNAMED_MODULE);
                 }
                 @Override
+                public void addExports(Module m, String pn) {
+                    m.implAddExportsOrOpens(pn, Module.EVERYONE_MODULE, false, true);
+                }
+                @Override
                 public void addExports(Module m, String pn, Module other) {
                     m.implAddExportsOrOpens(pn, other, false, true);
                 }
                 @Override
-                public void addOpens(Module m, String pn, Module other) {
-                    m.implAddExportsOrOpens(pn, other, true, true);
+                public void addExportsToAllUnnamed(Module m, String pn) {
+                    m.implAddExportsOrOpens(pn, Module.ALL_UNNAMED_MODULE, false, true);
                 }
                 @Override
-                public void addExportsToAll(Module m, String pn) {
-                    m.implAddExportsOrOpens(pn, Module.EVERYONE_MODULE, false, true);
-                }
-                @Override
-                public void addOpensToAll(Module m, String pn) {
+                public void addOpens(Module m, String pn) {
                     m.implAddExportsOrOpens(pn, Module.EVERYONE_MODULE, true, true);
                 }
                 @Override
-                public void addExportsToAllUnnamed(Module m, String pn) {
-                    m.implAddExportsOrOpens(pn, Module.ALL_UNNAMED_MODULE, false, true);
+                public void addOpens(Module m, String pn, Module other) {
+                    m.implAddExportsOrOpens(pn, other, true, true);
                 }
                 @Override
                 public void addOpensToAllUnnamed(Module m, String pn) {
@@ -1559,10 +1575,6 @@
                     m.implAddUses(service);
                 }
                 @Override
-                public void addPackage(Module m, String pn) {
-                    m.implAddPackage(pn, true);
-                }
-                @Override
                 public ServicesCatalog getServicesCatalog(Layer layer) {
                     return layer.getServicesCatalog();
                 }
@@ -1574,10 +1586,6 @@
                 public Stream<Layer> layers(ClassLoader loader) {
                     return Layer.layers(loader);
                 }
-                @Override
-                public boolean isStaticallyExported(Module module, String pn, Module other) {
-                    return module.isStaticallyExportedOrOpen(pn, other, false);
-                }
             });
     }
 }
--- a/src/java.base/share/classes/java/lang/reflect/Proxy.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/java/lang/reflect/Proxy.java	Thu Mar 23 22:57:12 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -359,10 +359,11 @@
      * @throws  NullPointerException if the {@code interfaces} array
      *          argument or any of its elements are {@code null}
      *
-     * @deprecated Proxy classes generated in a named module are encapsulated and not
-     *      accessible to code outside its module.
-     *      {@link Constructor#newInstance(Object...) Constructor.newInstance} will throw
-     *      {@code IllegalAccessException} when it is called on an inaccessible proxy class.
+     * @deprecated Proxy classes generated in a named module are encapsulated
+     *      and not accessible to code outside its module.
+     *      {@link Constructor#newInstance(Object...) Constructor.newInstance}
+     *      will throw {@code IllegalAccessException} when it is called on
+     *      an inaccessible proxy class.
      *      Use {@link #newProxyInstance(ClassLoader, Class[], InvocationHandler)}
      *      to create a proxy instance instead.
      *
@@ -511,17 +512,19 @@
                         "Unnamed package cannot be added to " + m);
             }
 
-            // add the package to the runtime module if not exists
             if (m.isNamed()) {
-                m.addPackage(proxyPkg);
+                if (!m.getDescriptor().packages().contains(proxyPkg)) {
+                    throw new InternalError(proxyPkg + " not exist in " + m.getName());
+                }
             }
 
             /*
              * Choose a name for the proxy class to generate.
              */
             long num = nextUniqueNumber.getAndIncrement();
-            String proxyName = proxyPkg.isEmpty() ? proxyClassNamePrefix + num
-                                                  : proxyPkg + "." + proxyClassNamePrefix + num;
+            String proxyName = proxyPkg.isEmpty()
+                                    ? proxyClassNamePrefix + num
+                                    : proxyPkg + "." + proxyClassNamePrefix + num;
 
             ClassLoader loader = getLoader(m);
             trace(proxyName, m, loader, interfaces);
@@ -581,9 +584,13 @@
                     c.getModule().getName(), c.getName(), access, ld);
         }
 
-        static void trace(String cn, Module module, ClassLoader loader, List<Class<?>> interfaces) {
+        static void trace(String cn,
+                          Module module,
+                          ClassLoader loader,
+                          List<Class<?>> interfaces) {
             if (isDebug()) {
-                System.out.format("PROXY: %s/%s defined by %s%n", module.getName(), cn, loader);
+                System.err.format("PROXY: %s/%s defined by %s%n",
+                                  module.getName(), cn, loader);
             }
             if (isDebug("debug")) {
                 interfaces.stream()
@@ -592,7 +599,7 @@
         }
 
         private static final String DEBUG =
-                GetPropertyAction.privilegedGetProperty("jdk.proxy.debug", "");
+            GetPropertyAction.privilegedGetProperty("jdk.proxy.debug", "");
 
         private static boolean isDebug() {
             return !DEBUG.isEmpty();
@@ -603,15 +610,16 @@
 
         // ProxyBuilder instance members start here....
 
-        private final ClassLoader loader;
         private final List<Class<?>> interfaces;
         private final Module module;
         ProxyBuilder(ClassLoader loader, List<Class<?>> interfaces) {
             if (!VM.isModuleSystemInited()) {
-                throw new InternalError("Proxy is not supported until module system is fully initialized");
+                throw new InternalError("Proxy is not supported until "
+                        + "module system is fully initialized");
             }
             if (interfaces.size() > 65535) {
-                throw new IllegalArgumentException("interface limit exceeded: " + interfaces.size());
+                throw new IllegalArgumentException("interface limit exceeded: "
+                        + interfaces.size());
             }
 
             Set<Class<?>> refTypes = referencedTypes(loader, interfaces);
@@ -619,7 +627,6 @@
             // IAE if violates any restrictions specified in newProxyInstance
             validateProxyInterfaces(loader, interfaces, refTypes);
 
-            this.loader = loader;
             this.interfaces = interfaces;
             this.module = mapToModule(loader, interfaces, refTypes);
             assert getLoader(module) == loader;
@@ -659,8 +666,8 @@
          * Validate the given proxy interfaces and the given referenced types
          * are visible to the defining loader.
          *
-         * @throws IllegalArgumentException if it violates the restrictions specified
-         *         in {@link Proxy#newProxyInstance}
+         * @throws IllegalArgumentException if it violates the restrictions
+         *         specified in {@link Proxy#newProxyInstance}
          */
         private static void validateProxyInterfaces(ClassLoader loader,
                                                     List<Class<?>> interfaces,
@@ -731,9 +738,9 @@
          * is in the same module of the package-private interface.
          *
          * If all proxy interfaces are public and at least one in a non-exported
-         * package, then the proxy class is in a dynamic module in a non-exported
-         * package.  Reads edge and qualified exports are added for
-         * dynamic module to access.
+         * package, then the proxy class is in a dynamic module in a
+         * non-exported package.  Reads edge and qualified exports are added
+         * for dynamic module to access.
          */
         private static Module mapToModule(ClassLoader loader,
                                           List<Class<?>> interfaces,
@@ -752,11 +759,12 @@
                 }
             }
 
-            // all proxy interfaces are public and exported, the proxy class is in unnamed module
-            // Such proxy class is accessible to any unnamed module and named module that
-            // can read unnamed module
+            // all proxy interfaces are public and exported, the proxy class
+            // is in unnamed module.  Such proxy class is accessible to
+            // any unnamed module and named module that can read unnamed module
             if (packagePrivateTypes.isEmpty() && modulePrivateTypes.isEmpty()) {
-                return loader != null ? loader.getUnnamedModule() : BootLoader.getUnnamedModule();
+                return loader != null ? loader.getUnnamedModule()
+                                      : BootLoader.getUnnamedModule();
             }
 
             if (packagePrivateTypes.size() > 0) {
@@ -778,7 +786,8 @@
                 Module target = null;
                 for (Module m : packagePrivateTypes.values()) {
                     if (getLoader(m) != loader) {
-                        // the specified loader is not the same class loader of the non-public interface
+                        // the specified loader is not the same class loader
+                        // of the non-public interface
                         throw new IllegalArgumentException(
                                 "non-public interface is not defined by the given loader");
                     }
@@ -799,8 +808,9 @@
                 return target;
             }
 
-            // all proxy interfaces are public and at least one in a non-exported package
-            // map to dynamic proxy module and add reads edge and qualified exports, if necessary
+            // All proxy interfaces are public and at least one in a non-exported
+            // package.  So maps to a dynamic proxy module and add reads edge
+            // and qualified exports, if necessary
             Module target = getDynamicModule(loader);
 
             // set up proxy class access to proxy interfaces and types
@@ -856,8 +866,8 @@
         private static final AtomicInteger counter = new AtomicInteger();
 
         /*
-         * Define a dynamic module for the generated proxy classes in a non-exported package
-         * named com.sun.proxy.$MODULE.
+         * Define a dynamic module for the generated proxy classes in
+         * a non-exported package named com.sun.proxy.$MODULE.
          *
          * Each class loader will have one dynamic module.
          */
--- a/src/java.base/share/classes/java/util/ServiceLoader.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/java/util/ServiceLoader.java	Thu Mar 23 22:57:12 2017 +0000
@@ -1007,6 +1007,7 @@
     {
         static final String PREFIX = "META-INF/services/";
 
+        Set<String> providerNames = new HashSet<>();  // to avoid duplicates
         Enumeration<URL> configs;
         Iterator<String> pending;
         Class<?> nextClass;
@@ -1016,7 +1017,7 @@
 
         /**
          * Parse a single line from the given configuration file, adding the
-         * name on the line to the names list.
+         * name on the line to set of names if not already seen.
          */
         private int parseLine(URL u, BufferedReader r, int lc, Set<String> names)
             throws IOException
@@ -1041,7 +1042,9 @@
                     if (!Character.isJavaIdentifierPart(cp) && (cp != '.'))
                         fail(service, u, lc, "Illegal provider-class name: " + ln);
                 }
-                names.add(ln);
+                if (providerNames.add(ln)) {
+                    names.add(ln);
+                }
             }
             return lc + 1;
         }
@@ -1072,7 +1075,7 @@
                 return true;
             }
 
-            Class<?> clazz = null;
+            Class<?> clazz;
             do {
                 if (configs == null) {
                     try {
--- a/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java	Thu Mar 23 22:57:12 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
@@ -59,7 +59,7 @@
             bis.read(magic);
             if (magic[0] != JMOD_MAGIC_NUMBER[0] ||
                 magic[1] != JMOD_MAGIC_NUMBER[1]) {
-                throw new IOException("Invalid jmod file: " + file.toString());
+                throw new IOException("Invalid JMOD file: " + file.toString());
             }
             if (magic[2] > JMOD_MAJOR_VERSION ||
                 (magic[2] == JMOD_MAJOR_VERSION && magic[3] > JMOD_MINOR_VERSION)) {
@@ -131,6 +131,13 @@
         }
 
         /**
+         * Returns true if the entry is a directory in the JMOD file.
+         */
+        public boolean isDirectory() {
+            return zipEntry.isDirectory();
+        }
+
+        /**
          * Returns the size of this entry.
          */
         public long size() {
@@ -186,12 +193,12 @@
     public Entry getEntry(Section section, String name) {
         String entry = section.jmodDir() + "/" + name;
         ZipEntry ze = zipfile.getEntry(entry);
-        return (ze == null || ze.isDirectory()) ? null : new Entry(ze);
+        return (ze != null) ? new Entry(ze) : null;
     }
 
     /**
      * Opens an {@code InputStream} for reading the named entry of the given
-     * section in this jmod file.
+     * section in this JMOD file.
      *
      * @throws IOException if the named entry is not found, or I/O error
      *         occurs when reading it
@@ -201,7 +208,7 @@
     {
         String entry = section.jmodDir() + "/" + name;
         ZipEntry e = zipfile.getEntry(entry);
-        if (e == null || e.isDirectory()) {
+        if (e == null) {
             throw new IOException(name + " not found: " + file);
         }
         return zipfile.getInputStream(e);
@@ -217,11 +224,10 @@
     }
 
     /**
-     * Returns a stream of non-directory entries in this jmod file.
+     * Returns a stream of entries in this JMOD file.
      */
     public Stream<Entry> stream() {
         return zipfile.stream()
-                      .filter(e -> !e.isDirectory())
                       .map(Entry::new);
     }
 
--- a/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java	Thu Mar 23 22:57:12 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
@@ -65,14 +65,12 @@
     }
 
     /**
-     * Need FilePermission ${java.home}/-", "read" to create or get jrt:/
+     * Need RuntimePermission "accessSystemModules" to create or get jrt:/
      */
     private void checkPermission() {
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            String home = SystemImage.RUNTIME_HOME;
-            FilePermission perm
-                    = new FilePermission(home + File.separator + "-", "read");
+            RuntimePermission perm = new RuntimePermission("accessSystemModules");
             sm.checkPermission(perm);
         }
     }
--- a/src/java.base/share/classes/jdk/internal/loader/BootLoader.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/loader/BootLoader.java	Thu Mar 23 22:57:12 2017 +0000
@@ -96,6 +96,14 @@
     }
 
     /**
+     * Returns {@code true} if there is a class path associated with the
+     * BootLoader.
+     */
+    public static boolean hasClassPath() {
+        return ClassLoaders.bootLoader().hasClassPath();
+    }
+
+    /**
      * Register a module with this class loader so that its classes (and
      * resources) become visible via this class loader.
      */
@@ -188,14 +196,6 @@
     }
 
     /**
-     * Returns {@code true} if there is a class path associated with the
-     * BootLoader.
-     */
-    public static boolean hasClassPath() {
-        return ClassLoaders.bootLoader().hasClassPath();
-    }
-
-    /**
      * Helper class to define {@code Package} objects for packages in modules
      * defined to the boot loader.
      */
--- a/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java	Thu Mar 23 22:57:12 2017 +0000
@@ -60,6 +60,7 @@
 import jdk.internal.misc.VM;
 import jdk.internal.module.ModulePatcher.PatchedModuleReader;
 import jdk.internal.module.SystemModules;
+import jdk.internal.module.Resources;
 
 
 /**
@@ -163,6 +164,14 @@
     }
 
     /**
+     * Returns {@code true} if there is a class path associated with this
+     * class loader.
+     */
+    boolean hasClassPath() {
+        return ucp != null;
+    }
+
+    /**
      * Register a module this this class loader. This has the effect of making
      * the types in the module visible.
      */
@@ -248,18 +257,24 @@
      */
     @Override
     public URL findResource(String name) {
-        String pn = ResourceHelper.getPackageName(name);
+        String pn = Resources.toPackageName(name);
         LoadedModule module = packageToModule.get(pn);
         if (module != null) {
 
             // resource is in a package of a module defined to this loader
-            if (module.loader() == this
-                && (name.endsWith(".class") || isOpen(module.mref(), pn))) {
+            if (module.loader() == this) {
+                URL url;
                 try {
-                    return findResource(module.name(), name); // checks URL
+                    url = findResource(module.name(), name); // checks URL
                 } catch (IOException ioe) {
                     return null;
                 }
+                if (url != null
+                    && (name.endsWith(".class")
+                        || url.toString().endsWith("/")
+                        || isOpen(module.mref(), pn))) {
+                    return url;
+                }
             }
 
         } else {
@@ -293,15 +308,17 @@
     public Enumeration<URL> findResources(String name) throws IOException {
         List<URL> checked = new ArrayList<>();  // list of checked URLs
 
-        String pn = ResourceHelper.getPackageName(name);
+        String pn = Resources.toPackageName(name);
         LoadedModule module = packageToModule.get(pn);
         if (module != null) {
 
             // resource is in a package of a module defined to this loader
-            if (module.loader() == this
-                && (name.endsWith(".class") || isOpen(module.mref(), pn))) {
-                URL url = findResource(module.name(), name);  // checks URL
-                if (url != null) {
+            if (module.loader() == this) {
+                URL url = findResource(module.name(), name); // checks URL
+                if (url != null
+                    && (name.endsWith(".class")
+                        || url.toString().endsWith("/")
+                        || isOpen(module.mref(), pn))) {
                     checked.add(url);
                 }
             }
@@ -351,11 +368,13 @@
                 new PrivilegedExceptionAction<>() {
                     @Override
                     public List<URL> run() throws IOException {
-                        List<URL> result = new ArrayList<>();
+                        List<URL> result = null;
                         for (ModuleReference mref : nameToModule.values()) {
                             URI u = moduleReaderFor(mref).find(name).orElse(null);
                             if (u != null) {
                                 try {
+                                    if (result == null)
+                                        result = new ArrayList<>();
                                     result.add(u.toURL());
                                 } catch (MalformedURLException |
                                          IllegalArgumentException e) {
@@ -375,7 +394,7 @@
                 map = new ConcurrentHashMap<>();
                 this.resourceCache = new SoftReference<>(map);
             }
-            if (urls.isEmpty())
+            if (urls == null)
                 urls = Collections.emptyList();
             map.putIfAbsent(name, urls);
         }
@@ -870,14 +889,6 @@
     }
 
     /**
-     * Returns {@code true} if there is a class path associated with this
-     * class loader.
-     */
-    boolean hasClassPath() {
-        return ucp != null;
-    }
-
-    /**
      * Returns {@code true} if the specified package name is sealed according to
      * the given manifest.
      */
@@ -975,7 +986,7 @@
      */
     private boolean isOpen(ModuleReference mref, String pn) {
         ModuleDescriptor descriptor = mref.descriptor();
-        if (descriptor.isOpen())
+        if (descriptor.isOpen() || descriptor.isAutomatic())
             return true;
         for (ModuleDescriptor.Opens opens : descriptor.opens()) {
             String source = opens.source();
--- a/src/java.base/share/classes/jdk/internal/loader/Loader.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/loader/Loader.java	Thu Mar 23 22:57:12 2017 +0000
@@ -60,6 +60,7 @@
 import java.util.stream.Stream;
 
 import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.Resources;
 
 
 /**
@@ -356,45 +357,52 @@
 
     @Override
     public URL findResource(String name) {
-        URL url = null;
-        String pn = ResourceHelper.getPackageName(name);
+        String pn = Resources.toPackageName(name);
         LoadedModule module = localPackageToModule.get(pn);
+
         if (module != null) {
-            if (name.endsWith(".class") || isOpen(module.mref(), pn)) {
-                try {
-                    url = findResource(module.name(), name);
-                } catch (IOException ioe) {
-                    // ignore
+            try {
+                URL url = findResource(module.name(), name);
+                if (url != null
+                    && (name.endsWith(".class")
+                        || url.toString().endsWith("/")
+                        || isOpen(module.mref(), pn))) {
+                    return url;
                 }
+            } catch (IOException ioe) {
+                // ignore
             }
+
         } else {
             for (ModuleReference mref : nameToModule.values()) {
                 try {
-                    url = findResource(mref.descriptor().name(), name);
-                    if (url != null)
-                        break;
+                    URL url = findResource(mref.descriptor().name(), name);
+                    if (url != null) return url;
                 } catch (IOException ioe) {
                     // ignore
                 }
             }
         }
-        return url;
+
+        return null;
     }
 
     @Override
     public Enumeration<URL> findResources(String name) throws IOException {
         List<URL> urls = new ArrayList<>();
-        String pn = ResourceHelper.getPackageName(name);
+        String pn = Resources.toPackageName(name);
         LoadedModule module = localPackageToModule.get(pn);
         if (module != null) {
-            if (name.endsWith(".class") || isOpen(module.mref(), pn)) {
-                try {
-                    URL url = findResource(module.name(), name);
-                    if (url != null)
-                        urls.add(url);
-                } catch (IOException ioe) {
-                    // ignore
+            try {
+                URL url = findResource(module.name(), name);
+                if (url != null
+                    && (name.endsWith(".class")
+                        || url.toString().endsWith("/")
+                        || isOpen(module.mref(), pn))) {
+                    urls.add(url);
                 }
+            } catch (IOException ioe) {
+                // ignore
             }
         } else {
             for (ModuleReference mref : nameToModule.values()) {
@@ -643,7 +651,7 @@
      */
     private boolean isOpen(ModuleReference mref, String pn) {
         ModuleDescriptor descriptor = mref.descriptor();
-        if (descriptor.isOpen())
+        if (descriptor.isOpen() || descriptor.isAutomatic())
             return true;
         for (ModuleDescriptor.Opens opens : descriptor.opens()) {
             String source = opens.source();
--- a/src/java.base/share/classes/jdk/internal/loader/ResourceHelper.java	Thu Mar 23 22:31:12 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,125 +0,0 @@
-/*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.loader;
-
-import java.io.File;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
-import jdk.internal.module.Checks;
-
-/**
- * Helper class for Class#getResource, Module#getResourceAsStream, and other
- * methods that locate a resource in a module.
- */
-public final class ResourceHelper {
-    private ResourceHelper() { }
-
-    /**
-     * Returns the <em>package name</em> for a resource or the empty package if
-     * the resource name does not contain a slash.
-     */
-    public static String getPackageName(String name) {
-        int index = name.lastIndexOf('/');
-        if (index != -1) {
-            return name.substring(0, index).replace("/", ".");
-        } else {
-            return "";
-        }
-    }
-
-    /**
-     * Returns true if the resource is a <em>simple resource</em>. 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.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 Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java	Thu Mar 23 22:57:12 2017 +0000
@@ -33,6 +33,7 @@
 import java.lang.reflect.Module;
 import java.net.URL;
 import java.security.AccessControlContext;
+import java.security.ProtectionDomain;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.stream.Stream;
@@ -150,6 +151,11 @@
     ConcurrentHashMap<?, ?> createOrGetClassLoaderValueMap(ClassLoader cl);
 
     /**
+     * Defines a class with the given name to a class loader.
+     */
+    Class<?> defineClass(ClassLoader cl, String name, byte[] b, ProtectionDomain pd, String source);
+
+    /**
      * Returns a class loaded by the bootstrap class loader.
      */
     Class<?> findBootstrapClassOrNull(ClassLoader cl, String name);
--- a/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java	Thu Mar 23 22:57:12 2017 +0000
@@ -73,7 +73,7 @@
     void requires(ModuleDescriptor.Builder builder,
                   Set<Requires.Modifier> ms,
                   String mn,
-                  String compiledVersion);
+                  String rawCompiledVersion);
 
     /**
      * Returns a {@code ModuleDescriptor.Requires} of the given modifiers
@@ -127,9 +127,6 @@
                                          Set<Provides> provides,
                                          Set<String> packages,
                                          String mainClass,
-                                         String osName,
-                                         String osArch,
-                                         String osVersion,
                                          int hashCode);
 
     /**
--- a/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java	Thu Mar 23 22:57:12 2017 +0000
@@ -66,33 +66,33 @@
     void addReadsAllUnnamed(Module m);
 
     /**
+     * Update module m to export a package to all modules.
+     */
+    void addExports(Module m, String pn);
+
+    /**
      * Updates module m1 to export a package to module m2. The export does
      * not result in a strong reference to m2 (m2 can be GC'ed).
      */
     void addExports(Module m1, String pkg, Module m2);
 
     /**
+     * Updates a module m to export a package to all unnamed modules.
+     */
+    void addExportsToAllUnnamed(Module m, String pkg);
+
+    /**
+     * Updates a module m to open a package to all modules.
+     */
+    void addOpens(Module m, String pkg);
+
+    /**
      * Updates module m1 to open a package to module m2. Opening the
      * package does not result in a strong reference to m2 (m2 can be GC'ed).
      */
     void addOpens(Module m1, String pkg, Module m2);
 
     /**
-     * Updates a module m to export a package to all modules.
-     */
-    void addExportsToAll(Module m, String pkg);
-
-    /**
-     * Updates a module m to open a package to all modules.
-     */
-    void addOpensToAll(Module m, String pkg);
-
-    /**
-     * Updates a module m to export a package to all unnamed modules.
-     */
-    void addExportsToAllUnnamed(Module m, String pkg);
-
-    /**
      * Updates a module m to open a package to all unnamed modules.
      */
     void addOpensToAllUnnamed(Module m, String pkg);
@@ -103,11 +103,6 @@
     void addUses(Module m, Class<?> service);
 
     /**
-     * Add a package to the given module.
-     */
-    void addPackage(Module m, String pkg);
-
-    /**
      * Returns the ServicesCatalog for the given Layer.
      */
     ServicesCatalog getServicesCatalog(Layer layer);
@@ -123,12 +118,4 @@
      * given class loader.
      */
     Stream<Layer> layers(ClassLoader loader);
-
-    /**
-     * Tests if a module exports a package at least {@code other} via its
-     * module declaration.
-     *
-     * @apiNote This is a temporary method for debugging features.
-     */
-    boolean isStaticallyExported(Module module, String pn, Module other);
 }
\ No newline at end of file
--- a/src/java.base/share/classes/jdk/internal/module/Builder.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/Builder.java	Thu Mar 23 22:57:12 2017 +0000
@@ -145,9 +145,6 @@
     Set<Provides> provides;
     Version version;
     String mainClass;
-    String osName;
-    String osArch;
-    String osVersion;
 
     Builder(String name) {
         this.name = name;
@@ -248,30 +245,6 @@
     }
 
     /**
-     * Sets the OS name.
-     */
-    public Builder osName(String name) {
-        this.osName = name;
-        return this;
-    }
-
-    /**
-     * Sets the OS arch.
-     */
-    public Builder osArch(String arch) {
-        this.osArch = arch;
-        return this;
-    }
-
-    /**
-     * Sets the OS version.
-     */
-    public Builder osVersion(String version) {
-        this.osVersion = version;
-        return this;
-    }
-
-    /**
      * Returns an immutable set of the module modifiers derived from the flags.
      */
     private Set<ModuleDescriptor.Modifier> modifiers() {
@@ -305,9 +278,6 @@
                                         provides,
                                         packages,
                                         mainClass,
-                                        osName,
-                                        osArch,
-                                        osVersion,
                                         hashCode);
     }
 }
--- a/src/java.base/share/classes/jdk/internal/module/Checks.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/Checks.java	Thu Mar 23 22:57:12 2017 +0000
@@ -180,41 +180,38 @@
     }
 
     /**
-     * Returns {@code true} if the last character of the given name is legal
-     * as the last character of a module name.
-     *
-     * @throws IllegalArgumentException if name is empty
+     * Returns {@code true} if a given legal module name contains an identifier
+     * that doesn't end with a Java letter.
      */
-    public static boolean hasLegalModuleNameLastCharacter(String name) {
-        if (name.isEmpty())
-            throw new IllegalArgumentException("name is empty");
-        int len = name.length();
-        if (isASCIIString(name)) {
-            char c = name.charAt(len-1);
-            return Character.isJavaIdentifierStart(c);
-        } else {
-            int i = 0;
-            int cp = -1;
-            while (i < len) {
-                cp = name.codePointAt(i);
-                i += Character.charCount(cp);
+    public static boolean hasJavaIdentifierWithTrailingDigit(String name) {
+        // quick scan to allow names that are just ASCII without digits
+        boolean needToParse = false;
+        int i = 0;
+        while (i < name.length()) {
+            int c = name.charAt(i);
+            if (c > 0x7F || (c >= '0' && c <= '9')) {
+                needToParse = true;
+                break;
             }
-            return Character.isJavaIdentifierStart(cp);
-        }
-    }
-
-    /**
-     * Returns true if the given string only contains ASCII characters.
-     */
-    private static boolean isASCIIString(String s) {
-        int i = 0;
-        while (i < s.length()) {
-            int c = s.charAt(i);
-            if (c > 0x7F)
-                return false;
             i++;
         }
-        return true;
+        if (!needToParse)
+            return false;
+
+        // slow path
+        int next;
+        int off = 0;
+        while ((next = name.indexOf('.', off)) != -1) {
+            int last = isJavaIdentifier(name, off, (next - off));
+            if (!Character.isJavaIdentifierStart(last))
+                return true;
+            off = next+1;
+        }
+        int last = isJavaIdentifier(name, off, name.length() - off);
+        if (!Character.isJavaIdentifierStart(last))
+            return true;
+        return false;
+
     }
 
     /**
--- a/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java	Thu Mar 23 22:57:12 2017 +0000
@@ -292,11 +292,11 @@
             attr.putShort(module_flags);
 
             // module_version
-            Version v = descriptor.version().orElse(null);
-            if (v == null) {
+            String vs = descriptor.rawVersion().orElse(null);
+            if (vs == null) {
                 attr.putShort(0);
             } else {
-                int module_version_index = cw.newUTF8(v.toString());
+                int module_version_index = cw.newUTF8(vs);
                 attr.putShort(module_version_index);
             }
 
@@ -320,11 +320,11 @@
                 attr.putShort(requires_flags);
 
                 int requires_version_index;
-                v = r.compiledVersion().orElse(null);
-                if (v == null) {
+                vs = r.rawCompiledVersion().orElse(null);
+                if (vs == null) {
                     requires_version_index = 0;
                 } else {
-                    requires_version_index = cw.newUTF8(v.toString());
+                    requires_version_index = cw.newUTF8(vs);
                 }
                 attr.putShort(requires_version_index);
             }
@@ -553,8 +553,6 @@
      *   u2 os_name_index;
      *   // index to CONSTANT_utf8_info structure with the OS arch
      *   u2 os_arch_index
-     *   // index to CONSTANT_utf8_info structure with the OS version
-     *   u2 os_version_index;
      * }
      *
      * } </pre>
@@ -562,17 +560,23 @@
     public static class ModuleTargetAttribute extends Attribute {
         private final String osName;
         private final String osArch;
-        private final String osVersion;
 
-        public ModuleTargetAttribute(String osName, String osArch, String osVersion) {
+        public ModuleTargetAttribute(String osName, String osArch) {
             super(MODULE_TARGET);
             this.osName = osName;
             this.osArch = osArch;
-            this.osVersion = osVersion;
         }
 
         public ModuleTargetAttribute() {
-            this(null, null, null);
+            this(null, null);
+        }
+
+        public String osName() {
+            return osName;
+        }
+
+        public String osArch() {
+            return osArch;
         }
 
         @Override
@@ -586,7 +590,6 @@
 
             String osName = null;
             String osArch = null;
-            String osVersion = null;
 
             int name_index = cr.readUnsignedShort(off);
             if (name_index != 0)
@@ -598,12 +601,7 @@
                 osArch = cr.readUTF8(off, buf);
             off += 2;
 
-            int version_index = cr.readUnsignedShort(off);
-            if (version_index != 0)
-                osVersion = cr.readUTF8(off, buf);
-            off += 2;
-
-            return new ModuleTargetAttribute(osName, osArch, osVersion);
+            return new ModuleTargetAttribute(osName, osArch);
         }
 
         @Override
@@ -625,11 +623,6 @@
                 arch_index = cw.newUTF8(osArch);
             attr.putShort(arch_index);
 
-            int version_index = 0;
-            if (osVersion != null && osVersion.length() > 0)
-                version_index = cw.newUTF8(osVersion);
-            attr.putShort(version_index);
-
             return attr;
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/IllegalAccessLogger.java	Thu Mar 23 22:57:12 2017 +0000
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.module;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Module;
+import java.net.URL;
+import java.security.AccessController;
+import java.security.CodeSource;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+/**
+ * Supports logging of access to members of API packages that are exported or
+ * opened via backdoor mechanisms to code in unnamed modules.
+ */
+
+public final class IllegalAccessLogger {
+
+    // true to print stack trace
+    private static final boolean PRINT_STACK_TRACE;
+    static {
+        String s = System.getProperty("sun.reflect.debugModuleAccessChecks");
+        PRINT_STACK_TRACE = "access".equals(s);
+    }
+
+    private static final StackWalker STACK_WALKER
+        = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);
+
+    // the maximum number of frames to capture
+    private static final int MAX_STACK_FRAMES = 32;
+
+    // lock to avoid interference when printing stack traces
+    private static final Object OUTPUT_LOCK = new Object();
+
+    // caller -> usages
+    private final Map<Class<?>, Set<Usage>> callerToUsages = new WeakHashMap<>();
+
+    // module -> (package name -> CLI option)
+    private final Map<Module, Map<String, String>> exported;
+    private final Map<Module, Map<String, String>> opened;
+
+    private IllegalAccessLogger(Map<Module, Map<String, String>> exported,
+                                Map<Module, Map<String, String>> opened) {
+        this.exported = deepCopy(exported);
+        this.opened = deepCopy(opened);
+    }
+
+    /**
+     * Returns that a Builder that is seeded with the packages known to this logger.
+     */
+    public Builder toBuilder() {
+        return new Builder(exported, opened);
+    }
+
+    /**
+     * Logs access to the member of a target class by a caller class if the class
+     * is in a package that is exported via a backdoor mechanism.
+     *
+     * The {@code whatSupplier} supplies the message that describes the member.
+     */
+    public void logIfExportedByBackdoor(Class<?> caller,
+                                        Class<?> target,
+                                        Supplier<String> whatSupplier) {
+        Map<String, String> packages = exported.get(target.getModule());
+        if (packages != null) {
+            String how = packages.get(target.getPackageName());
+            if (how != null) {
+                log(caller, whatSupplier.get(), how);
+            }
+        }
+    }
+
+    /**
+     * Logs access to the member of a target class by a caller class if the class
+     * is in a package that is opened via a backdoor mechanism.
+     *
+     * The {@code what} parameter supplies the message that describes the member.
+     */
+    public void logIfOpenedByBackdoor(Class<?> caller,
+                                      Class<?> target,
+                                      Supplier<String> whatSupplier) {
+        Map<String, String> packages = opened.get(target.getModule());
+        if (packages != null) {
+            String how = packages.get(target.getPackageName());
+            if (how != null) {
+                log(caller, whatSupplier.get(), how);
+            }
+        }
+    }
+
+    /**
+     * Logs access by a caller class. The {@code what} parameter describes
+     * the member is accessed, the {@code how} parameter is the means by which
+     * access is allocated (CLI option for example).
+     */
+    private void log(Class<?> caller, String what, String how) {
+        log(caller, what, () -> {
+            PrivilegedAction<ProtectionDomain> pa = caller::getProtectionDomain;
+            CodeSource cs = AccessController.doPrivileged(pa).getCodeSource();
+            URL url = (cs != null) ? cs.getLocation() : null;
+            String source = caller.getName();
+            if (url != null)
+                source += " (" + url + ")";
+            return "WARNING: Illegal access by " + source + " to " + what
+                    + " (permitted by " + how + ")";
+        });
+    }
+
+
+    /**
+     * Logs access to caller class if the class is in a package that is opened via
+     * a backdoor mechanism.
+     */
+    public void logIfOpenedByBackdoor(MethodHandles.Lookup caller, Class<?> target) {
+        Map<String, String> packages = opened.get(target.getModule());
+        if (packages != null) {
+            String how = packages.get(target.getPackageName());
+            if (how != null) {
+                log(caller.lookupClass(), target.getName(), () ->
+                    "WARNING: Illegal access using Lookup on " + caller.lookupClass()
+                    + " to " + target + " (permitted by " + how + ")");
+            }
+        }
+    }
+
+    /**
+     * Log access by a caller. The {@code what} parameter describes the class or
+     * member that is being accessed. The {@code msgSupplier} supplies the log
+     * message.
+     *
+     * To reduce output, this method only logs the access if it hasn't been seen
+     * previously. "Seen previously" is implemented as a map of caller class -> Usage,
+     * where a Usage is the "what" and a hash of the stack trace. The map has weak
+     * keys so it can be expunged when the caller is GC'ed/unloaded.
+     */
+    private void log(Class<?> caller, String what, Supplier<String> msgSupplier) {
+        // stack trace without the top-most frames in java.base
+        List<StackWalker.StackFrame> stack = STACK_WALKER.walk(s ->
+            s.dropWhile(this::isJavaBase)
+             .limit(MAX_STACK_FRAMES)
+             .collect(Collectors.toList())
+        );
+
+        // check if the access has already been recorded
+        Usage u = new Usage(what, hash(stack));
+        boolean firstUsage;
+        synchronized (this) {
+            firstUsage = callerToUsages.computeIfAbsent(caller, k -> new HashSet<>()).add(u);
+        }
+
+        // log message if first usage
+        if (firstUsage) {
+            String msg = msgSupplier.get();
+            if (PRINT_STACK_TRACE) {
+                synchronized (OUTPUT_LOCK) {
+                    System.err.println(msg);
+                    stack.forEach(f -> System.err.println("\tat " + f));
+                }
+            } else {
+                System.err.println(msg);
+            }
+        }
+    }
+
+    private static class Usage {
+        private final String what;
+        private final int stack;
+        Usage(String what, int stack) {
+            this.what = what;
+            this.stack = stack;
+        }
+        @Override
+        public int hashCode() {
+            return what.hashCode() ^ stack;
+        }
+        @Override
+        public boolean equals(Object ob) {
+            if (ob instanceof Usage) {
+                Usage that = (Usage)ob;
+                return what.equals(that.what) && stack == (that.stack);
+            } else {
+                return false;
+            }
+        }
+    }
+
+    /**
+     * Returns true if the stack frame is for a class in java.base.
+     */
+    private boolean isJavaBase(StackWalker.StackFrame frame) {
+        Module caller = frame.getDeclaringClass().getModule();
+        return "java.base".equals(caller.getName());
+    }
+
+    /**
+     * Computes a hash code for the give stack frames. The hash code is based
+     * on the class, method name, and BCI.
+     */
+    private int hash(List<StackWalker.StackFrame> stack) {
+        int hash = 0;
+        for (StackWalker.StackFrame frame : stack) {
+            hash = (31 * hash) + Objects.hash(frame.getDeclaringClass(),
+                                              frame.getMethodName(),
+                                              frame.getByteCodeIndex());
+        }
+        return hash;
+    }
+
+    // system-wide IllegalAccessLogger
+    private static volatile IllegalAccessLogger logger;
+
+    /**
+     * Sets the system-wide IllegalAccessLogger
+     */
+    public static void setIllegalAccessLogger(IllegalAccessLogger l) {
+        if (l.exported.isEmpty() && l.opened.isEmpty()) {
+            logger = null;
+        } else {
+            logger = l;
+        }
+    }
+
+    /**
+     * Returns the system-wide IllegalAccessLogger or {@code null} if there is
+     * no logger.
+     */
+    public static IllegalAccessLogger illegalAccessLogger() {
+        return logger;
+    }
+
+    /**
+     * A builder for IllegalAccessLogger objects.
+     */
+    public static class Builder {
+        private Map<Module, Map<String, String>> exported;
+        private Map<Module, Map<String, String>> opened;
+
+        public Builder() { }
+
+        public Builder(Map<Module, Map<String, String>> exported,
+                       Map<Module, Map<String, String>> opened) {
+            this.exported = deepCopy(exported);
+            this.opened = deepCopy(opened);
+        }
+
+        public void logAccessToExportedPackage(Module m, String pn, String how) {
+            if (!m.isExported(pn)) {
+                if (exported == null)
+                    exported = new HashMap<>();
+                exported.computeIfAbsent(m, k -> new HashMap<>()).putIfAbsent(pn, how);
+            }
+        }
+
+        public void logAccessToOpenPackage(Module m, String pn, String how) {
+            // opens implies exported at run-time.
+            logAccessToExportedPackage(m, pn, how);
+
+            if (!m.isOpen(pn)) {
+                if (opened == null)
+                    opened = new HashMap<>();
+                opened.computeIfAbsent(m, k -> new HashMap<>()).putIfAbsent(pn, how);
+            }
+        }
+
+        /**
+         * Builds the logger.
+         */
+        public IllegalAccessLogger build() {
+            return new IllegalAccessLogger(exported, opened);
+        }
+    }
+
+
+    static Map<Module, Map<String, String>> deepCopy(Map<Module, Map<String, String>> map) {
+        if (map == null || map.isEmpty()) {
+            return new HashMap<>();
+        } else {
+            Map<Module, Map<String, String>> newMap = new HashMap<>();
+            for (Map.Entry<Module, Map<String, String>> e : map.entrySet()) {
+                newMap.put(e.getKey(), new HashMap<>(e.getValue()));
+            }
+            return newMap;
+        }
+    }
+}
--- a/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java	Thu Mar 23 22:57:12 2017 +0000
@@ -33,6 +33,7 @@
 import java.lang.module.ModuleReference;
 import java.lang.module.ResolvedModule;
 import java.lang.reflect.Layer;
+import java.lang.reflect.LayerInstantiationException;
 import java.lang.reflect.Module;
 import java.net.URI;
 import java.nio.file.Path;
@@ -46,7 +47,6 @@
 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;
@@ -327,8 +327,9 @@
                 for (String p : descriptor.packages()) {
                     String other = packageToModule.putIfAbsent(p, name);
                     if (other != null) {
-                        fail("Package " + p + " in both module "
-                             + name + " and module " + other);
+                        String msg = "Package " + p + " in both module "
+                                     + name + " and module " + other;
+                        throw new LayerInstantiationException(msg);
                     }
                 }
             }
@@ -359,7 +360,7 @@
         PerfCounters.loadModulesTime.addElapsedTimeFrom(t5);
 
 
-        // --add-reads, -add-exports/-add-opens
+        // --add-reads, --add-exports/--add-opens
         addExtraReads(bootLayer);
         addExtraExportsAndOpens(bootLayer);
 
@@ -514,26 +515,44 @@
      * additional packages specified on the command-line.
      */
     private static void addExtraExportsAndOpens(Layer bootLayer) {
+        IllegalAccessLogger.Builder builder = new IllegalAccessLogger.Builder();
 
         // --add-exports
         String prefix = "jdk.module.addexports.";
         Map<String, List<String>> extraExports = decode(prefix);
         if (!extraExports.isEmpty()) {
-            addExtraExportsOrOpens(bootLayer, extraExports, false);
+            addExtraExportsOrOpens(bootLayer, extraExports, false, builder);
         }
 
         // --add-opens
         prefix = "jdk.module.addopens.";
         Map<String, List<String>> extraOpens = decode(prefix);
         if (!extraOpens.isEmpty()) {
-            addExtraExportsOrOpens(bootLayer, extraOpens, true);
+            addExtraExportsOrOpens(bootLayer, extraOpens, true, builder);
         }
 
+        // --permit-illegal-access
+        if (getAndRemoveProperty("jdk.module.permitIllegalAccess") != null) {
+            warn("--permit-illegal-access will be removed in the next major release");
+            bootLayer.modules().stream().forEach(m -> {
+                m.getDescriptor()
+                 .packages()
+                 .stream()
+                 .filter(pn -> !m.isOpen(pn))
+                 .forEach(pn -> {
+                     builder.logAccessToOpenPackage(m, pn, "--permit-illegal-access");
+                     Modules.addOpensToAllUnnamed(m, pn);
+                 });
+            });
+        }
+
+        IllegalAccessLogger.setIllegalAccessLogger(builder.build());
     }
 
     private static void addExtraExportsOrOpens(Layer bootLayer,
                                                Map<String, List<String>> map,
-                                               boolean opens)
+                                               boolean opens,
+                                               IllegalAccessLogger.Builder builder)
     {
         String option = opens ? ADD_OPENS : ADD_EXPORTS;
         for (Map.Entry<String, List<String>> e : map.entrySet()) {
@@ -542,12 +561,12 @@
             String key = e.getKey();
             String[] s = key.split("/");
             if (s.length != 2)
-                fail(unableToParse(option,  "<module>/<package>", key));
+                fail(unableToParse(option, "<module>/<package>", key));
 
             String mn = s[0];
             String pn = s[1];
             if (mn.isEmpty() || pn.isEmpty())
-                fail(unableToParse(option,  "<module>/<package>", key));
+                fail(unableToParse(option, "<module>/<package>", key));
 
             // The exporting module is in the boot layer
             Module m;
@@ -581,8 +600,10 @@
                 }
                 if (allUnnamed) {
                     if (opens) {
+                        builder.logAccessToOpenPackage(m, pn, option);
                         Modules.addOpensToAllUnnamed(m, pn);
                     } else {
+                        builder.logAccessToExportedPackage(m, pn, option);
                         Modules.addExportsToAllUnnamed(m, pn);
                     }
                 } else {
@@ -632,7 +653,7 @@
 
             // value is <module>(,<module>)* or <file>(<pathsep><file>)*
             if (!allowDuplicates && map.containsKey(key))
-                fail(key + " specified more than once in " + option(prefix));
+                fail(key + " specified more than once to " + option(prefix));
             List<String> values = map.computeIfAbsent(key, k -> new ArrayList<>());
             int ntargets = 0;
             for (String s : rhs.split(regex)) {
@@ -676,10 +697,6 @@
             ModuleReference mref = rm.reference();
             String mn = mref.descriptor().name();
 
-            // emit warning if module name ends with a non-Java letter
-            if (!Checks.hasLegalModuleNameLastCharacter(mn))
-                warn("Module name \"" + mn + "\" may soon be illegal");
-
             // emit warning if the WARN_INCUBATING module resolution bit set
             if (ModuleResolution.hasIncubatingWarning(mref)) {
                 if (incubating == null) {
@@ -705,7 +722,7 @@
     }
 
     static void warnUnknownModule(String option, String mn) {
-        warn("Unknown module: " + mn + " specified in " + option);
+        warn("Unknown module: " + mn + " specified to " + option);
     }
 
     static String unableToParse(String option, String text, String value) {
--- a/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleInfo.java	Thu Mar 23 22:57:12 2017 +0000
@@ -89,18 +89,24 @@
      */
     public static final class Attributes {
         private final ModuleDescriptor descriptor;
+        private final ModuleTarget target;
         private final ModuleHashes recordedHashes;
         private final ModuleResolution moduleResolution;
         Attributes(ModuleDescriptor descriptor,
+                   ModuleTarget target,
                    ModuleHashes recordedHashes,
                    ModuleResolution moduleResolution) {
             this.descriptor = descriptor;
+            this.target = target;
             this.recordedHashes = recordedHashes;
             this.moduleResolution = moduleResolution;
         }
         public ModuleDescriptor descriptor() {
             return descriptor;
         }
+        public ModuleTarget target() {
+            return target;
+        }
         public ModuleHashes recordedHashes() {
             return recordedHashes;
         }
@@ -221,8 +227,8 @@
         Builder builder = null;
         Set<String> allPackages = null;
         String mainClass = null;
-        String[] osValues = null;
-        ModuleHashes hashes = null;
+        ModuleTarget moduleTarget = null;
+        ModuleHashes moduelHashes = null;
         ModuleResolution moduleResolution = null;
 
         for (int i = 0; i < attributes_count ; i++) {
@@ -251,12 +257,12 @@
                     break;
 
                 case MODULE_TARGET :
-                    osValues = readModuleTargetAttribute(in, cpool);
+                    moduleTarget = readModuleTargetAttribute(in, cpool);
                     break;
 
                 case MODULE_HASHES :
                     if (parseHashes) {
-                        hashes = readModuleHashesAttribute(in, cpool);
+                        moduelHashes = readModuleHashesAttribute(in, cpool);
                     } else {
                         in.skipBytes(length);
                     }
@@ -282,15 +288,10 @@
             throw invalidModuleDescriptor(MODULE + " attribute not found");
         }
 
-        // ModuleMainClass and ModuleTarget attributes
+        // ModuleMainClass  attribute
         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
@@ -323,7 +324,10 @@
         }
 
         ModuleDescriptor descriptor = builder.build();
-        return new Attributes(descriptor, hashes, moduleResolution);
+        return new Attributes(descriptor,
+                              moduleTarget,
+                              moduelHashes,
+                              moduleResolution);
     }
 
     /**
@@ -422,7 +426,11 @@
                     Set<String> targets = new HashSet<>(exports_to_count);
                     for (int j=0; j<exports_to_count; j++) {
                         int exports_to_index = in.readUnsignedShort();
-                        targets.add(cpool.getModuleName(exports_to_index));
+                        String target = cpool.getModuleName(exports_to_index);
+                        if (!targets.add(target)) {
+                            throw invalidModuleDescriptor(pkg + " exported to "
+                                                          + target + " more than once");
+                        }
                     }
                     builder.exports(mods, pkg, targets);
                 } else {
@@ -458,7 +466,11 @@
                     Set<String> targets = new HashSet<>(open_to_count);
                     for (int j=0; j<open_to_count; j++) {
                         int opens_to_index = in.readUnsignedShort();
-                        targets.add(cpool.getModuleName(opens_to_index));
+                        String target = cpool.getModuleName(opens_to_index);
+                        if (!targets.add(target)) {
+                            throw invalidModuleDescriptor(pkg + " opened to "
+                                                          + target + " more than once");
+                        }
                     }
                     builder.opens(mods, pkg, targets);
                 } else {
@@ -486,7 +498,10 @@
                 for (int j=0; j<with_count; j++) {
                     index = in.readUnsignedShort();
                     String pn = cpool.getClassName(index);
-                    providers.add(pn);
+                    if (!providers.add(pn)) {
+                        throw invalidModuleDescriptor(sn + " provides " + pn
+                                                      + " more than once");
+                    }
                 }
                 builder.provides(sn, providers);
             }
@@ -528,24 +543,21 @@
     /**
      * Reads the ModuleTarget attribute
      */
-    private String[] readModuleTargetAttribute(DataInput in, ConstantPool cpool)
+    private ModuleTarget readModuleTargetAttribute(DataInput in, ConstantPool cpool)
         throws IOException
     {
-        String[] values = new String[3];
+        String osName = null;
+        String osArch = null;
 
         int name_index = in.readUnsignedShort();
         if (name_index != 0)
-            values[0] = cpool.getUtf8(name_index);
+            osName = cpool.getUtf8(name_index);
 
         int arch_index = in.readUnsignedShort();
         if (arch_index != 0)
-            values[1] = cpool.getUtf8(arch_index);
+            osArch = cpool.getUtf8(arch_index);
 
-        int version_index = in.readUnsignedShort();
-        if (version_index != 0)
-            values[2] = cpool.getUtf8(version_index);
-
-        return values;
+        return new ModuleTarget(osName, osArch);
     }
 
 
--- a/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java	Thu Mar 23 22:57:12 2017 +0000
@@ -65,7 +65,6 @@
     // the values for the ModuleTarget attribute
     private String osName;
     private String osArch;
-    private String osVersion;
 
     // the hashes for the ModuleHashes attribute
     private ModuleHashes hashes;
@@ -111,12 +110,9 @@
     /**
      * Sets the values for the ModuleTarget attribute.
      */
-    public ModuleInfoExtender targetPlatform(String osName,
-                                             String osArch,
-                                             String osVersion) {
+    public ModuleInfoExtender targetPlatform(String osName, String osArch) {
         this.osName = osName;
         this.osArch = osArch;
-        this.osVersion = osVersion;
         return this;
     }
 
@@ -203,8 +199,8 @@
             cv.addAttribute(new ModulePackagesAttribute(packages));
         if (mainClass != null)
             cv.addAttribute(new ModuleMainClassAttribute(mainClass));
-        if (osName != null || osArch != null || osVersion != null)
-            cv.addAttribute(new ModuleTargetAttribute(osName, osArch, osVersion));
+        if (osName != null || osArch != null)
+            cv.addAttribute(new ModuleTargetAttribute(osName, osArch));
         if (hashes != null)
             cv.addAttribute(new ModuleHashesAttribute(hashes));
         if (moduleResolution != null)
--- a/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java	Thu Mar 23 22:57:12 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
@@ -48,7 +48,7 @@
      * Writes the given module descriptor to a module-info.class file,
      * returning it in a byte array.
      */
-    private static byte[] toModuleInfo(ModuleDescriptor md) {
+    private static byte[] toModuleInfo(ModuleDescriptor md, ModuleTarget target) {
         ClassWriter cw = new ClassWriter(0);
         cw.visit(Opcodes.V1_9, ACC_MODULE, "module-info", null, null, null);
         cw.visitAttribute(new ModuleAttribute(md));
@@ -66,12 +66,10 @@
         // write ModuleMainClass if the module has a main class
         md.mainClass().ifPresent(mc -> cw.visitAttribute(new ModuleMainClassAttribute(mc)));
 
-        // write ModuleTarget attribute if have any of OS name/arch/version
-        String osName = md.osName().orElse(null);
-        String osArch = md.osArch().orElse(null);
-        String osVersion = md.osVersion().orElse(null);
-        if (osName != null || osArch != null || osVersion != null) {
-            cw.visitAttribute(new ModuleTargetAttribute(osName, osArch, osVersion));
+        // write ModuleTarget if there is a platform OS/arch
+        if (target != null) {
+            cw.visitAttribute(new ModuleTargetAttribute(target.osName(),
+                                                        target.osArch()));
         }
 
         cw.visitEnd();
@@ -82,11 +80,23 @@
      * Writes a module descriptor to the given output stream as a
      * module-info.class.
      */
+    public static void write(ModuleDescriptor descriptor,
+                             ModuleTarget target,
+                             OutputStream out)
+        throws IOException
+    {
+        byte[] bytes = toModuleInfo(descriptor, target);
+        out.write(bytes);
+    }
+
+    /**
+     * Writes a module descriptor to the given output stream as a
+     * module-info.class.
+     */
     public static void write(ModuleDescriptor descriptor, OutputStream out)
         throws IOException
     {
-        byte[] bytes = toModuleInfo(descriptor);
-        out.write(bytes);
+        write(descriptor, null, out);
     }
 
     /**
@@ -94,8 +104,7 @@
      * in module-info.class format.
      */
     public static ByteBuffer toByteBuffer(ModuleDescriptor descriptor) {
-        byte[] bytes = toModuleInfo(descriptor);
+        byte[] bytes = toModuleInfo(descriptor, null);
         return ByteBuffer.wrap(bytes);
     }
-
 }
--- a/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java	Thu Mar 23 22:57:12 2017 +0000
@@ -55,7 +55,6 @@
 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;
@@ -165,9 +164,6 @@
 
             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());
@@ -179,10 +175,12 @@
         // return a module reference to the patched module
         URI location = mref.location().orElse(null);
 
+        ModuleTarget target = null;
         ModuleHashes recordedHashes = null;
         ModuleResolution mres = null;
         if (mref instanceof ModuleReferenceImpl) {
             ModuleReferenceImpl impl = (ModuleReferenceImpl)mref;
+            target = impl.moduleTarget();
             recordedHashes = impl.recordedHashes();
             mres = impl.moduleResolution();
         }
@@ -191,6 +189,7 @@
                                        location,
                                        () -> new PatchedModuleReader(paths, mref),
                                        this,
+                                       target,
                                        recordedHashes,
                                        null,
                                        mres);
@@ -226,7 +225,7 @@
         private volatile ModuleReader delegate;
 
         /**
-         * Creates the ModuleReader to reads resources a patched module.
+         * Creates the ModuleReader to reads resources in a patched module.
          */
         PatchedModuleReader(List<Path> patches, ModuleReference mref) {
             List<ResourceFinder> finders = new ArrayList<>();
@@ -291,13 +290,16 @@
         }
 
         /**
-         * Finds a resources in the patch locations. Returns null if not found.
+         * Finds a resources in the patch locations. Returns null if not found
+         * or the name is "module-info.class" as that cannot be overridden.
          */
         private Resource findResourceInPatch(String name) throws IOException {
-            for (ResourceFinder finder : finders) {
-                Resource r = finder.find(name);
-                if (r != null)
-                    return r;
+            if (!name.equals("module-info.class")) {
+                for (ResourceFinder finder : finders) {
+                    Resource r = finder.find(name);
+                    if (r != null)
+                        return r;
+                }
             }
             return null;
         }
@@ -478,9 +480,7 @@
 
         @Override
         public Stream<String> list() throws IOException {
-            return jf.stream()
-                    .filter(e -> !e.isDirectory())
-                    .map(JarEntry::getName);
+            return jf.stream().map(JarEntry::getName);
         }
     }
 
@@ -500,14 +500,12 @@
 
         @Override
         public Resource find(String name) throws IOException {
-            Path path = ResourceHelper.toFilePath(name);
-            if (path != null) {
-                Path file = dir.resolve(path);
-                if (Files.isRegularFile(file)) {
-                    return newResource(name, dir, file);
-                }
+            Path file = Resources.toFilePath(dir, name);
+            if (file != null) {
+                return  newResource(name, dir, file);
+            } else {
+                return null;
             }
-            return null;
         }
 
         private Resource newResource(String name, Path top, Path file) {
@@ -550,11 +548,9 @@
 
         @Override
         public Stream<String> list() throws IOException {
-            return Files.find(dir, Integer.MAX_VALUE,
-                              (path, attrs) -> attrs.isRegularFile())
-                    .map(f -> dir.relativize(f)
-                                 .toString()
-                                 .replace(File.separatorChar, '/'));
+            return Files.walk(dir, Integer.MAX_VALUE)
+                        .map(f -> Resources.toResourceName(dir, f))
+                        .filter(s -> s.length() > 0);
         }
     }
 
--- a/src/java.base/share/classes/jdk/internal/module/ModulePath.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ModulePath.java	Thu Mar 23 22:57:12 2017 +0000
@@ -513,7 +513,7 @@
                         String pn = packageName(cn);
                         if (!packages.contains(pn)) {
                             String msg = "Provider class " + cn + " not in module";
-                            throw new IOException(msg);
+                            throw new InvalidModuleDescriptorException(msg);
                         }
                         providerClasses.add(cn);
                     }
@@ -533,7 +533,7 @@
                 String pn = packageName(mainClass);
                 if (!packages.contains(pn)) {
                     String msg = "Main-Class " + mainClass + " not in module";
-                    throw new IOException(msg);
+                    throw new InvalidModuleDescriptorException(msg);
                 }
                 builder.mainClass(mainClass);
             }
@@ -609,11 +609,10 @@
                 // no module-info.class so treat it as automatic module
                 try {
                     ModuleDescriptor md = deriveModuleDescriptor(jf);
-                    attrs = new ModuleInfo.Attributes(md, null, null);
-                } catch (IllegalArgumentException e) {
-                    throw new FindException(
-                        "Unable to derive module descriptor for: "
-                        + jf.getName(), e);
+                    attrs = new ModuleInfo.Attributes(md, null, null, null);
+                } catch (RuntimeException e) {
+                    throw new FindException("Unable to derive module descriptor for "
+                                            + jf.getName(), e);
                 }
 
             } else {
@@ -672,18 +671,18 @@
     /**
      * Maps the name of an entry in a JAR or ZIP file to a package name.
      *
-     * @throws IllegalArgumentException if the name is a class file in
-     *         the top-level directory of the JAR/ZIP file (and it's
-     *         not module-info.class)
+     * @throws InvalidModuleDescriptorException if the name is a class file in
+     *         the top-level directory of the JAR/ZIP file (and it's not
+     *         module-info.class)
      */
     private Optional<String> toPackageName(String name) {
         assert !name.endsWith("/");
         int index = name.lastIndexOf("/");
         if (index == -1) {
             if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
-                throw new IllegalArgumentException(name
-                        + " found in top-level directory"
-                        + " (unnamed package not allowed in module)");
+                String msg = name + " found in top-level directory"
+                             + " (unnamed package not allowed in module)";
+                throw new InvalidModuleDescriptorException(msg);
             }
             return Optional.empty();
         }
@@ -701,8 +700,8 @@
      * Maps the relative path of an entry in an exploded module to a package
      * name.
      *
-     * @throws IllegalArgumentException if the name is a class file in
-     *          the top-level directory (and it's not module-info.class)
+     * @throws InvalidModuleDescriptorException if the name is a class file in
+     *         the top-level directory (and it's not module-info.class)
      */
     private Optional<String> toPackageName(Path file) {
         assert file.getRoot() == null;
@@ -711,9 +710,9 @@
         if (parent == null) {
             String name = file.toString();
             if (name.endsWith(".class") && !name.equals(MODULE_INFO)) {
-                throw new IllegalArgumentException(name
-                        + " found in top-level directory"
-                        + " (unnamed package not allowed in module)");
+                String msg = name + " found in top-level directory"
+                             + " (unnamed package not allowed in module)";
+                throw new InvalidModuleDescriptorException(msg);
             }
             return Optional.empty();
         }
--- a/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleReferenceImpl.java	Thu Mar 23 22:57:12 2017 +0000
@@ -46,6 +46,9 @@
     // non-null if the module is patched
     private final ModulePatcher patcher;
 
+    // ModuleTarget if the module is OS/architecture specific
+    private final ModuleTarget target;
+
     // the hashes of other modules recorded in this module
     private final ModuleHashes recordedHashes;
 
@@ -65,6 +68,7 @@
                         URI location,
                         Supplier<ModuleReader> readerSupplier,
                         ModulePatcher patcher,
+                        ModuleTarget target,
                         ModuleHashes recordedHashes,
                         ModuleHashes.HashSupplier hasher,
                         ModuleResolution moduleResolution)
@@ -72,6 +76,7 @@
         super(descriptor, Objects.requireNonNull(location));
         this.readerSupplier = readerSupplier;
         this.patcher = patcher;
+        this.target = target;
         this.recordedHashes = recordedHashes;
         this.hasher = hasher;
         this.moduleResolution = moduleResolution;
@@ -94,6 +99,13 @@
     }
 
     /**
+     * Returns the ModuleTarget or {@code null} if the no target platform.
+     */
+    public ModuleTarget moduleTarget() {
+        return target;
+    }
+
+    /**
      * Returns the hashes recorded in this module or {@code null} if there
      * are no hashes recorded.
      */
--- a/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java	Thu Mar 23 22:57:12 2017 +0000
@@ -25,7 +25,6 @@
 
 package jdk.internal.module;
 
-import java.io.File;
 import java.io.IOError;
 import java.io.IOException;
 import java.io.InputStream;
@@ -50,7 +49,6 @@
 import java.util.zip.ZipFile;
 
 import jdk.internal.jmod.JmodFile;
-import jdk.internal.loader.ResourceHelper;
 import jdk.internal.misc.SharedSecrets;
 import jdk.internal.module.ModuleHashes.HashSupplier;
 import jdk.internal.util.jar.VersionedStream;
@@ -78,6 +76,7 @@
                                                        uri,
                                                        supplier,
                                                        null,
+                                                       attrs.target(),
                                                        attrs.recordedHashes(),
                                                        hasher,
                                                        attrs.moduleResolution());
@@ -242,8 +241,7 @@
         }
 
         private JarEntry getEntry(String name) {
-            JarEntry entry = jf.getJarEntry(Objects.requireNonNull(name));
-            return (entry == null || entry.isDirectory()) ? null : entry;
+            return jf.getJarEntry(Objects.requireNonNull(name));
         }
 
         @Override
@@ -252,6 +250,8 @@
             if (je != null) {
                 if (jf.isMultiRelease())
                     name = SharedSecrets.javaUtilJarAccess().getRealName(jf, je);
+                if (je.isDirectory() && !name.endsWith("/"))
+                    name += "/";
                 String encodedPath = ParseUtil.encodePath(name, false);
                 String uris = "jar:" + uri + "!/" + encodedPath;
                 return Optional.of(URI.create(uris));
@@ -274,7 +274,6 @@
         Stream<String> implList() throws IOException {
             // take snapshot to avoid async close
             List<String> names = VersionedStream.stream(jf)
-                    .filter(e -> !e.isDirectory())
                     .map(JarEntry::getName)
                     .collect(Collectors.toList());
             return names.stream();
@@ -316,6 +315,8 @@
         Optional<URI> implFind(String name) {
             JmodFile.Entry je = getEntry(name);
             if (je != null) {
+                if (je.isDirectory() && !name.endsWith("/"))
+                    name += "/";
                 String encodedPath = ParseUtil.encodePath(name, false);
                 String uris = "jmod:" + uri + "!/" + encodedPath;
                 return Optional.of(URI.create(uris));
@@ -376,26 +377,10 @@
             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 = toFilePath(name);
+            Path path = Resources.toFilePath(dir, name);
             if (path != null) {
                 try {
                     return Optional.of(path.toUri());
@@ -410,7 +395,7 @@
         @Override
         public Optional<InputStream> open(String name) throws IOException {
             ensureOpen();
-            Path path = toFilePath(name);
+            Path path = Resources.toFilePath(dir, name);
             if (path != null) {
                 return Optional.of(Files.newInputStream(path));
             } else {
@@ -421,7 +406,7 @@
         @Override
         public Optional<ByteBuffer> read(String name) throws IOException {
             ensureOpen();
-            Path path = toFilePath(name);
+            Path path = Resources.toFilePath(dir, name);
             if (path != null) {
                 return Optional.of(ByteBuffer.wrap(Files.readAllBytes(path)));
             } else {
@@ -432,12 +417,9 @@
         @Override
         public Stream<String> list() throws IOException {
             ensureOpen();
-            // sym links not followed
-            return Files.find(dir, Integer.MAX_VALUE,
-                              (path, attrs) -> attrs.isRegularFile())
-                    .map(f -> dir.relativize(f)
-                                 .toString()
-                                 .replace(File.separatorChar, '/'));
+            return Files.walk(dir, Integer.MAX_VALUE)
+                        .map(f -> Resources.toResourceName(dir, f))
+                        .filter(s -> s.length() > 0);
         }
 
         @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/ModuleTarget.java	Thu Mar 23 22:57:12 2017 +0000
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.module;
+
+public final class ModuleTarget {
+
+    private final String osName;
+    private final String osArch;
+
+    public ModuleTarget(String osName, String osArch) {
+        this.osName = osName;
+        this.osArch = osArch;
+    }
+
+    public String osName() {
+        return osName;
+    }
+
+    public String osArch() {
+        return osArch;
+    }
+
+}
--- a/src/java.base/share/classes/jdk/internal/module/Modules.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/Modules.java	Thu Mar 23 22:57:12 2017 +0000
@@ -31,7 +31,6 @@
 import java.net.URI;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
-import java.util.Set;
 
 import jdk.internal.loader.BootLoader;
 import jdk.internal.loader.ClassLoaders;
@@ -39,10 +38,10 @@
 import jdk.internal.misc.SharedSecrets;
 
 /**
- * A helper class to allow JDK classes create dynamic modules and to update
- * modules, exports and the readability graph. It is also invoked by the VM
- * to add read edges when agents are instrumenting code that need to link
- * to supporting classes.
+ * A helper class for creating and updating modules. This class is intended to
+ * support command-line options, tests, and the instrumentation API. It is also
+ * used by the VM to add read edges when agents are instrumenting code that
+ * need to link to supporting classes.
  *
  * The parameters that are package names in this API are the fully-qualified
  * names of the packages as defined in section 6.5.3 of <cite>The Java&trade;
@@ -72,25 +71,7 @@
     }
 
     /**
-     * Define a new module to the VM. The module has the given set of
-     * packages and is defined to the given class loader.
-     *
-     * The resulting Module is in a larval state in that it does not not read
-     * any other module and does not have any exports.
-     */
-    public static Module defineModule(ClassLoader loader,
-                                      String name,
-                                      Set<String> packages)
-    {
-        ModuleDescriptor descriptor = ModuleDescriptor.newModule(name)
-                .packages(packages)
-                .build();
-
-        return JLRMA.defineModule(loader, descriptor, null);
-    }
-
-    /**
-     * Adds a read-edge so that module {@code m1} reads module {@code m1}.
+     * Updates m1 to read m2.
      * Same as m1.addReads(m2) but without a caller check.
      */
     public static void addReads(Module m1, Module m2) {
@@ -98,21 +79,46 @@
     }
 
     /**
-     * Update module {@code m} to read all unnamed modules.
+     * Update module m to read all unnamed modules.
      */
     public static void addReadsAllUnnamed(Module m) {
         JLRMA.addReadsAllUnnamed(m);
     }
 
     /**
+     * Update module m to export a package to all modules.
+     *
+     * This method is for intended for use by tests only.
+     */
+    public static void addExports(Module m, String pn) {
+        JLRMA.addExports(m, pn);
+    }
+
+    /**
      * Updates module m1 to export a package to module m2.
-     * Same as m1.addExports(pn, m2) but without a caller check.
+     * Same as m1.addExports(pn, m2) but without a caller check
      */
     public static void addExports(Module m1, String pn, Module m2) {
         JLRMA.addExports(m1, pn, m2);
     }
 
     /**
+     * Updates module m to export a package to all unnamed modules.
+     */
+    public static void addExportsToAllUnnamed(Module m, String pn) {
+        JLRMA.addExportsToAllUnnamed(m, pn);
+    }
+
+    /**
+     * Update module m to open a package to all modules.
+     *
+     * This method is for intended for use by tests only.
+     */
+    public static void addOpens(Module m, String pn) {
+        JLRMA.addOpens(m, pn);
+    }
+
+    /**
      * Updates module m1 to open a package to module m2.
      * Same as m1.addOpens(pn, m2) but without a caller check.
      */
@@ -121,27 +127,6 @@
     }
 
     /**
-     * Updates a module m to export a package to all modules.
-     */
-    public static void addExportsToAll(Module m, String pn) {
-        JLRMA.addExportsToAll(m, pn);
-    }
-
-    /**
-     * Updates a module m to open a package to all modules.
-     */
-    public static void addOpensToAll(Module m, String pn) {
-        JLRMA.addOpensToAll(m, pn);
-    }
-
-    /**
-     * Updates module m to export a package to all unnamed modules.
-     */
-    public static void addExportsToAllUnnamed(Module m, String pn) {
-        JLRMA.addExportsToAllUnnamed(m, pn);
-    }
-
-    /**
      * Updates module m to open a package to all unnamed modules.
      */
     public static void addOpensToAllUnnamed(Module m, String pn) {
@@ -149,7 +134,8 @@
     }
 
     /**
-     * Updates module m to use a service
+     * Updates module m to use a service.
+     * Same as m2.addUses(service) but without a caller check.
      */
     public static void addUses(Module m, Class<?> service) {
         JLRMA.addUses(m, service);
@@ -183,16 +169,6 @@
     }
 
     /**
-     * Adds a package to a module's content.
-     *
-     * 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);
-    }
-
-    /**
      * Called by the VM when code in the given Module has been transformed by
      * an agent and so may have been instrumented to call into supporting
      * classes on the boot class path or application class path.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/Resources.java	Thu Mar 23 22:57:12 2017 +0000
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.internal.module;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.BasicFileAttributes;
+
+/**
+ * A helper class to support working with resources in modules. Also provides
+ * support for translating resource names to file paths.
+ */
+public final class Resources {
+    private Resources() { }
+
+    /**
+     * Return true if a resource can be encapsulated. Resource with names
+     * ending in ".class" or "/" cannot be encapsulated. Resource names
+     * that map to a legal package name can be encapsulated.
+     */
+    public static boolean canEncapsulate(String name) {
+        int len = name.length();
+        if (len > 6 && name.endsWith(".class")) {
+            return false;
+        } else {
+            return Checks.isPackageName(toPackageName(name));
+        }
+    }
+
+    /**
+     * Derive a <em>package name</em> for a resource. The package name
+     * returned by this method may not be a legal package name. This method
+     * returns null if the the resource name ends with a "/" (a directory)
+     * or the resource name does not contain a "/".
+     */
+    public static String toPackageName(String name) {
+        int index = name.lastIndexOf('/');
+        if (index == -1 || index == name.length()-1) {
+            return "";
+        } else {
+            return name.substring(0, index).replace("/", ".");
+        }
+    }
+
+    /**
+     * Returns a resource name corresponding to the relative file path
+     * between {@code dir} and {@code file}. If the file is a directory
+     * then the name will end with a  "/", except the top-level directory
+     * where the empty string is returned.
+     */
+    public static String toResourceName(Path dir, Path file) {
+        String s = dir.relativize(file)
+                      .toString()
+                      .replace(File.separatorChar, '/');
+        if (s.length() > 0 && Files.isDirectory(file))
+            s += "/";
+        return s;
+    }
+
+    /**
+     * Returns a file path to a resource in a file tree. If the resource
+     * name has a trailing "/" then the file path will locate a directory.
+     * Returns {@code null} if the resource does not map to a file in the
+     * tree file.
+     */
+    public static Path toFilePath(Path dir, String name) throws IOException {
+        boolean expectDirectory = name.endsWith("/");
+        if (expectDirectory) {
+            name = name.substring(0, name.length() - 1);  // drop trailing "/"
+        }
+        Path path = toSafeFilePath(name);
+        if (path != null) {
+            Path file = dir.resolve(path);
+            try {
+                BasicFileAttributes attrs;
+                attrs = Files.readAttributes(file, BasicFileAttributes.class);
+                if (attrs.isDirectory()
+                    || (!attrs.isDirectory() && !expectDirectory))
+                    return file;
+            } catch (NoSuchFileException ignore) { }
+        }
+        return null;
+    }
+
+    /**
+     * Map a resource name to a "safe" file path. Returns {@code null} if
+     * the resource name cannot be converted into a "safe" file path.
+     *
+     * Resource names with empty elements, or elements that are "." or ".."
+     * are rejected, as are resource names that translates to a file path
+     * with a root component.
+     */
+    private static Path toSafeFilePath(String name) {
+        // scan elements of resource name
+        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/module/SystemModuleFinder.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/SystemModuleFinder.java	Thu Mar 23 22:57:12 2017 +0000
@@ -150,18 +150,21 @@
             System.getProperty("jdk.system.module.finder.disabledFastPath") != null;
 
         ModuleDescriptor[] descriptors;
+        ModuleTarget[] targets;
         ModuleHashes[] recordedHashes;
         ModuleResolution[] moduleResolutions;
 
         // fast loading of ModuleDescriptor of system modules
         if (isFastPathSupported() && !disabled) {
             descriptors = SystemModules.descriptors();
+            targets = SystemModules.targets();
             recordedHashes = SystemModules.hashes();
             moduleResolutions = SystemModules.moduleResolutions();
         } else {
             // if fast loading of ModuleDescriptors is disabled
             // fallback to read module-info.class
             descriptors = new ModuleDescriptor[n];
+            targets = new ModuleTarget[n];
             recordedHashes = new ModuleHashes[n];
             moduleResolutions = new ModuleResolution[n];
             ImageReader imageReader = SystemImage.reader();
@@ -171,6 +174,7 @@
                 ModuleInfo.Attributes attrs =
                     ModuleInfo.read(imageReader.getResourceBuffer(loc), null);
                 descriptors[i] = attrs.descriptor();
+                targets[i] = attrs.target();
                 recordedHashes[i] = attrs.recordedHashes();
                 moduleResolutions[i] = attrs.moduleResolution();
             }
@@ -206,6 +210,7 @@
 
             // create the ModuleReference
             ModuleReference mref = toModuleReference(md,
+                                                     targets[i],
                                                      recordedHashes[i],
                                                      hashSupplier(names[i]),
                                                      moduleResolutions[i]);
@@ -233,6 +238,7 @@
     }
 
     private ModuleReference toModuleReference(ModuleDescriptor md,
+                                              ModuleTarget target,
                                               ModuleHashes recordedHashes,
                                               HashSupplier hasher,
                                               ModuleResolution mres) {
@@ -246,9 +252,14 @@
             }
         };
 
-        ModuleReference mref =
-            new ModuleReferenceImpl(md, uri, readerSupplier, null,
-                                    recordedHashes, hasher, mres);
+        ModuleReference mref = new ModuleReferenceImpl(md,
+                                                       uri,
+                                                       readerSupplier,
+                                                       null,
+                                                       target,
+                                                       recordedHashes,
+                                                       hasher,
+                                                       mres);
 
         // may need a reference to a patched module if --patch-module specified
         mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
--- a/src/java.base/share/classes/jdk/internal/module/SystemModules.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/module/SystemModules.java	Thu Mar 23 22:57:12 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
@@ -27,7 +27,7 @@
 
 import java.lang.module.ModuleDescriptor;
 
-/*
+/**
  * SystemModules class will be generated at link time to create
  * ModuleDescriptor for the system modules directly to improve
  * the module descriptor reconstitution time.
@@ -65,7 +65,7 @@
     }
 
     /**
-     * Returns a non-empty array of ModuleDescriptors in the run-time image.
+     * Returns a non-empty array of ModuleDescriptor objects in the run-time image.
      *
      * When running an exploded image it returns an empty array.
      */
@@ -74,6 +74,15 @@
     }
 
     /**
+     * Returns a non-empty array of ModuleTarget objects in the run-time image.
+     *
+     * When running an exploded image it returns an empty array.
+     */
+    public static ModuleTarget[] targets() {
+        throw new InternalError("expected to be overridden at link time");
+    }
+
+    /**
      * Returns a non-empty array of ModuleHashes recorded in each module
      * in the run-time image.
      *
--- a/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/org/objectweb/asm/ClassReader.java	Thu Mar 23 22:57:12 2017 +0000
@@ -2508,7 +2508,7 @@
     }
 
     /**
-     * Reads a CONSTANT_Pakcage_info item in {@code b}.  This method is
+     * Reads a CONSTANT_Package_info item in {@code b}.  This method is
      * intended for {@link Attribute} sub slasses, and is normally not needed
      * by class generators or adapters.</i>
      *
--- a/src/java.base/share/classes/jdk/internal/reflect/Reflection.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/reflect/Reflection.java	Thu Mar 23 22:57:12 2017 +0000
@@ -31,9 +31,7 @@
 import java.util.Map;
 import java.util.Objects;
 import jdk.internal.HotSpotIntrinsicCandidate;
-import jdk.internal.misc.SharedSecrets;
 import jdk.internal.misc.VM;
-import sun.security.action.GetPropertyAction;
 
 /** Common utility routines used by both java.lang and
     java.lang.reflect */
@@ -104,39 +102,40 @@
                                           int modifiers)
         throws IllegalAccessException
     {
-        if (currentClass == null || memberClass == null) {
-            throw new InternalError();
-        }
-
         if (!verifyMemberAccess(currentClass, memberClass, targetClass, modifiers)) {
-            throwIllegalAccessException(currentClass, memberClass, targetClass, modifiers);
+            throw newIllegalAccessException(currentClass, memberClass, targetClass, modifiers);
         }
     }
 
     /**
-     * Verify access to a member, returning {@code false} if no access
+     * Verify access to a member and return {@code true} if it is granted.
+     *
+     * @param currentClass the class performing the access
+     * @param memberClass the declaring class of the member being accessed
+     * @param targetClass the class of target object if accessing instance
+     *                    field or method;
+     *                    or the declaring class if accessing constructor;
+     *                    or null if accessing static field or method
+     * @param modifiers the member's access modifiers
+     * @return {@code true} if access to member is granted
      */
     public static boolean verifyMemberAccess(Class<?> currentClass,
                                              Class<?> memberClass,
                                              Class<?> targetClass,
                                              int modifiers)
     {
-        // Verify that currentClass can access a field, method, or
-        // constructor of memberClass, where that member's access bits are
-        // "modifiers".
-
-        boolean gotIsSameClassPackage = false;
-        boolean isSameClassPackage = false;
-
         if (currentClass == memberClass) {
             // Always succeeds
             return true;
         }
 
-        if (!verifyModuleAccess(currentClass, memberClass)) {
+        if (!verifyModuleAccess(currentClass.getModule(), memberClass)) {
             return false;
         }
 
+        boolean gotIsSameClassPackage = false;
+        boolean isSameClassPackage = false;
+
         if (!Modifier.isPublic(getClassAccessFlags(memberClass))) {
             isSameClassPackage = isSameClassPackage(currentClass, memberClass);
             gotIsSameClassPackage = true;
@@ -196,31 +195,20 @@
     }
 
     /**
-     * Returns {@code true} if memberClass's's module exports memberClass's
-     * package to currentClass's module.
+     * Returns {@code true} if memberClass's module exports memberClass's
+     * package to currentModule.
      */
-    public static boolean verifyModuleAccess(Class<?> currentClass,
-                                             Class<?> memberClass) {
-        return verifyModuleAccess(currentClass.getModule(), memberClass);
-    }
-
     public static boolean verifyModuleAccess(Module currentModule, Class<?> memberClass) {
         Module memberModule = memberClass.getModule();
-
-        // module may be null during startup (initLevel 0)
-        if (currentModule == memberModule)
-           return true;  // same module (named or unnamed)
-
-        String pkg = memberClass.getPackageName();
-        boolean allowed = memberModule.isExported(pkg, currentModule);
-        if (allowed && memberModule.isNamed() && printStackTraceWhenAccessSucceeds()) {
-            if (!SharedSecrets.getJavaLangReflectModuleAccess()
-                    .isStaticallyExported(memberModule, pkg, currentModule)) {
-                String msg = currentModule + " allowed access to member of " + memberClass;
-                new Exception(msg).printStackTrace(System.err);
-            }
+        if (currentModule == memberModule) {
+            // same module (named or unnamed) or both null if called
+            // before module system is initialized, which means we are
+            // dealing with java.base only.
+            return true;
+        } else {
+            String pkg = memberClass.getPackageName();
+            return memberModule.isExported(pkg, currentModule);
         }
-        return allowed;
     }
 
     /**
@@ -344,46 +332,14 @@
         return false;
     }
 
-
-    // true to print a stack trace when access fails
-    private static volatile boolean printStackWhenAccessFails;
-
-    // true to print a stack trace when access succeeds
-    private static volatile boolean printStackWhenAccessSucceeds;
-
-    // true if printStack* values are initialized
-    private static volatile boolean printStackPropertiesSet;
-
-    private static void ensurePrintStackPropertiesSet() {
-        if (!printStackPropertiesSet && VM.initLevel() >= 1) {
-            String s = GetPropertyAction.privilegedGetProperty(
-                    "sun.reflect.debugModuleAccessChecks");
-            if (s != null) {
-                printStackWhenAccessFails = !s.equalsIgnoreCase("false");
-                printStackWhenAccessSucceeds = s.equalsIgnoreCase("access");
-            }
-            printStackPropertiesSet = true;
-        }
-    }
-
-    public static boolean printStackTraceWhenAccessFails() {
-        ensurePrintStackPropertiesSet();
-        return printStackWhenAccessFails;
-    }
-
-    public static boolean printStackTraceWhenAccessSucceeds() {
-        ensurePrintStackPropertiesSet();
-        return printStackWhenAccessSucceeds;
-    }
-
     /**
-     * Throws IllegalAccessException with the an exception message based on
+     * Returns an IllegalAccessException with an exception message based on
      * the access that is denied.
      */
-    private static void throwIllegalAccessException(Class<?> currentClass,
-                                                    Class<?> memberClass,
-                                                    Object target,
-                                                    int modifiers)
+    public static IllegalAccessException newIllegalAccessException(Class<?> currentClass,
+                                                                   Class<?> memberClass,
+                                                                   Class<?> targetClass,
+                                                                   int modifiers)
         throws IllegalAccessException
     {
         String currentSuffix = "";
@@ -411,20 +367,6 @@
             if (m2.isNamed()) msg += " to " + m1;
         }
 
-        throwIllegalAccessException(msg);
-    }
-
-    /**
-     * Throws IllegalAccessException with the given exception message.
-     */
-    public static void throwIllegalAccessException(String msg)
-        throws IllegalAccessException
-    {
-        IllegalAccessException e = new IllegalAccessException(msg);
-        ensurePrintStackPropertiesSet();
-        if (printStackWhenAccessFails) {
-            e.printStackTrace(System.err);
-        }
-        throw e;
+        return new IllegalAccessException(msg);
     }
 }
--- a/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java	Thu Mar 23 22:57:12 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2016, 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
@@ -44,6 +44,7 @@
 import java.util.Objects;
 import java.util.Properties;
 
+import jdk.internal.misc.VM;
 import sun.reflect.misc.ReflectUtil;
 import sun.security.action.GetPropertyAction;
 
@@ -585,17 +586,10 @@
     private static void checkInitted() {
         if (initted) return;
 
-        // Tests to ensure the system properties table is fully
-        // initialized. This is needed because reflection code is
-        // called very early in the initialization process (before
-        // command-line arguments have been parsed and therefore
-        // these user-settable properties installed.) We assume that
-        // if System.out is non-null then the System class has been
-        // fully initialized and that the bulk of the startup code
-        // has been run.
-
-        if (System.out == null) {
-            // java.lang.System not yet fully initialized
+        // Defer initialization until module system is initialized so as
+        // to avoid inflation and spinning bytecode in unnamed modules
+        // during early startup.
+        if (!VM.isModuleSystemInited()) {
             return;
         }
 
--- a/src/java.base/share/classes/module-info.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/module-info.java	Thu Mar 23 22:57:12 2017 +0000
@@ -125,10 +125,9 @@
         jdk.jlink;
     exports jdk.internal.loader to
         java.instrument,
-        java.logging,
-        jdk.jlink;
+        java.logging;
     exports jdk.internal.jmod to
-        jdk.compiler,
+        jdk.compiler,   // reflective dependency
         jdk.jlink;
     exports jdk.internal.logger to
         java.logging;
@@ -140,10 +139,7 @@
     exports jdk.internal.org.objectweb.asm.tree to
         jdk.jlink;
     exports jdk.internal.org.objectweb.asm.util to
-        jdk.jlink,
         jdk.scripting.nashorn;
-    exports jdk.internal.org.objectweb.asm.tree.analysis to
-        jdk.jlink;
     exports jdk.internal.org.objectweb.asm.commons to
         jdk.scripting.nashorn;
     exports jdk.internal.org.objectweb.asm.signature to
@@ -157,7 +153,6 @@
         jdk.jlink;
     exports jdk.internal.misc to
         java.desktop,
-        jdk.incubator.httpclient,
         java.logging,
         java.management,
         java.naming,
@@ -166,8 +161,8 @@
         java.sql,
         java.xml,
         jdk.charsets,
-        jdk.compiler,
-        jdk.jartool,
+        jdk.compiler,   // reflective dependency
+        jdk.incubator.httpclient,
         jdk.jdeps,
         jdk.jlink,
         jdk.jshell,
@@ -210,11 +205,10 @@
         jdk.naming.dns;
     exports sun.net.util to
         java.desktop,
-        jdk.jconsole,
-        jdk.naming.dns;
+        jdk.jconsole;
     exports sun.net.www to
+        java.desktop,
         jdk.incubator.httpclient,
-        java.desktop,
         jdk.jartool;
     exports sun.net.www.protocol.http to
         java.security.jgss;
--- a/src/java.base/share/classes/sun/launcher/LauncherHelper.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/sun/launcher/LauncherHelper.java	Thu Mar 23 22:57:12 2017 +0000
@@ -85,6 +85,7 @@
 import java.util.stream.Stream;
 
 import jdk.internal.misc.VM;
+import jdk.internal.module.IllegalAccessLogger;
 import jdk.internal.module.Modules;
 
 
@@ -428,14 +429,20 @@
                 abort(null, "java.launcher.jar.error3", jarname);
             }
 
-            // Add-Exports and Add-Opens to break encapsulation
+            // Add-Exports and Add-Opens to allow illegal access
             String exports = mainAttrs.getValue(ADD_EXPORTS);
             if (exports != null) {
-                addExportsOrOpens(exports, false);
+                String warn = getLocalizedMessage("java.launcher.permitaccess.warning",
+                                                  jarname, ADD_EXPORTS);
+                System.err.println(warn);
+                addExportsOrOpens(exports, false, ADD_EXPORTS);
             }
             String opens = mainAttrs.getValue(ADD_OPENS);
             if (opens != null) {
-                addExportsOrOpens(opens, true);
+                String warn = getLocalizedMessage("java.launcher.permitaccess.warning",
+                                                   jarname, ADD_OPENS);
+                System.err.println(warn);
+                addExportsOrOpens(opens, true, ADD_OPENS);
             }
 
             /*
@@ -460,23 +467,36 @@
      * Process the Add-Exports or Add-Opens value. The value is
      * {@code <module>/<package> ( <module>/<package>)*}.
      */
-    static void addExportsOrOpens(String value, boolean open) {
+    static void addExportsOrOpens(String value, boolean open, String how) {
+        IllegalAccessLogger.Builder builder;
+        IllegalAccessLogger logger = IllegalAccessLogger.illegalAccessLogger();
+        if (logger == null) {
+            builder = new IllegalAccessLogger.Builder();
+        } else {
+            builder = logger.toBuilder();
+        }
+
         for (String moduleAndPackage : value.split(" ")) {
             String[] s = moduleAndPackage.trim().split("/");
             if (s.length == 2) {
                 String mn = s[0];
                 String pn = s[1];
+
                 Layer.boot().findModule(mn).ifPresent(m -> {
                     if (m.getDescriptor().packages().contains(pn)) {
                         if (open) {
+                            builder.logAccessToOpenPackage(m, pn, how);
                             Modules.addOpensToAllUnnamed(m, pn);
                         } else {
+                            builder.logAccessToExportedPackage(m, pn, how);
                             Modules.addExportsToAllUnnamed(m, pn);
                         }
                     }
                 });
             }
         }
+
+        IllegalAccessLogger.setIllegalAccessLogger(builder.build());
     }
 
     // From src/share/bin/java.c:
--- a/src/java.base/share/classes/sun/launcher/resources/launcher.properties	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/sun/launcher/resources/launcher.properties	Thu Mar 23 22:57:12 2017 +0000
@@ -24,12 +24,15 @@
 #
 
 # Translators please note do not translate the options themselves
-java.launcher.opt.header  =   Usage: {0} [options] class [args...]\n\
-\           (to execute a class)\n   or  {0} [options] -jar jarfile [args...]\n\
+java.launcher.opt.header  =   Usage: {0} [options] <mainclass> [args...]\n\
+\           (to execute a class)\n   or  {0} [options] -jar <jarfile> [args...]\n\
 \           (to execute a jar file)\n\
-\   or  {0} [options] -p <modulepath> -m <modulename>[/<mainclass>] [args...]\n\
+\   or  {0} [options] -m <module>[/<mainclass>] [args...]\n\
+\       {0} [options] --module <module>[/<mainclass>] [args...]\n\
 \           (to execute the main class in a module)\n\n\
-where options include:\n\n
+\ Arguments following the main class, -jar <jarfile>, -m or --module\n\
+\ <module>/<mainclass> are passed as the arguments to main class.\n\n\
+\ where options include:\n\n
 
 java.launcher.opt.datamodel  =\    -d{0}\t  Deprecated, will be removed in a future release\n
 java.launcher.opt.vmselect   =\    {0}\t  to select the "{1}" VM\n
@@ -49,10 +52,6 @@
 \                  A {0} separated list of directories, each directory\n\
 \                  is a directory of modules that replace upgradeable\n\
 \                  modules in the runtime image\n\
-\    -m <module>[/<mainclass>]\n\
-\    --module <modulename>[/<mainclass>]\n\
-\                  the initial module to resolve, and the name of the main class\n\
-\                  to execute if not specified by the module\n\
 \    --add-modules <modulename>[,<modulename>...]\n\
 \                  root modules to resolve in addition to the initial module.\n\
 \                  <modulename> can also be ALL-DEFAULT, ALL-SYSTEM,\n\
@@ -129,7 +128,7 @@
 \    -Xms<size>        set initial Java heap size\n\
 \    -Xmx<size>        set maximum Java heap size\n\
 \    -Xnoclassgc       disable class garbage collection\n\
-\    -Xprof            output cpu profiling data\n\
+\    -Xprof            output cpu profiling data (deprecated)\n\
 \    -Xrs              reduce use of OS signals by Java/VM (see documentation)\n\
 \    -Xshare:auto      use shared class data if possible (default)\n\
 \    -Xshare:off       do not attempt to use shared class data\n\
@@ -157,6 +156,10 @@
 \    --add-opens <module>/<package>=<target-module>(,<target-module>)*\n\
 \                      updates <module> to open <package> to\n\
 \                      <target-module>, regardless of module declaration.\n\
+\    --permit-illegal-access\n\
+\                      permit illegal access to members of types in named modules\n\
+\                      by code in unnamed modules. This compatibility option will\n\
+\                      be removed in the next release.\n\
 \    --disable-@files  disable further argument file expansion\n\
 \    --patch-module <module>=<file>({0}<file>)*\n\
 \                      Override or augment a module with classes and resources\n\
@@ -208,4 +211,6 @@
 java.launcher.module.error3=\
     Error: Unable to load main class {0} from module {1}\n\
     \t{2}
+java.launcher.permitaccess.warning=\
+    WARNING: Main manifest of {0} contains {1} attribute to permit illegal access
 
--- a/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java	Thu Mar 23 22:57:12 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,8 +26,6 @@
 package sun.net.www.protocol.jrt;
 
 import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FilePermission;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.MalformedURLException;
@@ -44,7 +42,6 @@
 import jdk.internal.loader.Resource;
 import sun.net.www.ParseUtil;
 import sun.net.www.URLConnection;
-import sun.security.action.GetPropertyAction;
 
 /**
  * URLConnection implementation that can be used to connect to resources
@@ -66,9 +63,6 @@
     // the Resource when connected
     private volatile Resource resource;
 
-    // the permission to access resources in the runtime image, created lazily
-    private static volatile Permission permission;
-
     JavaRuntimeURLConnection(URL url) throws IOException {
         super(url);
         String path = url.getPath();
@@ -164,14 +158,8 @@
     }
 
     @Override
-    public Permission getPermission() throws IOException {
-        Permission p = permission;
-        if (p == null) {
-            String home = GetPropertyAction.privilegedGetProperty("java.home");
-            p = new FilePermission(home + File.separator + "-", "read");
-            permission = p;
-        }
-        return p;
+    public Permission getPermission() {
+        return new RuntimePermission("accessSystemModules");
     }
 
     /**
--- a/src/java.base/share/native/libjava/ClassLoader.c	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/native/libjava/ClassLoader.c	Thu Mar 23 22:57:12 2017 +0000
@@ -72,23 +72,9 @@
     return utfStr;
 }
 
-// The existence or signature of this method is not guaranteed since it
-// supports a private method.  This method will be changed in 1.7.
-JNIEXPORT jclass JNICALL
-Java_java_lang_ClassLoader_defineClass0(JNIEnv *env,
-                                        jobject loader,
-                                        jstring name,
-                                        jbyteArray data,
-                                        jint offset,
-                                        jint length,
-                                        jobject pd)
-{
-    return Java_java_lang_ClassLoader_defineClass1(env, loader, name, data, offset,
-                                                   length, pd, NULL);
-}
-
 JNIEXPORT jclass JNICALL
 Java_java_lang_ClassLoader_defineClass1(JNIEnv *env,
+                                        jclass cls,
                                         jobject loader,
                                         jstring name,
                                         jbyteArray data,
@@ -163,6 +149,7 @@
 
 JNIEXPORT jclass JNICALL
 Java_java_lang_ClassLoader_defineClass2(JNIEnv *env,
+                                        jclass cls,
                                         jobject loader,
                                         jstring name,
                                         jobject data,
--- a/src/java.base/share/native/libjava/Module.c	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.base/share/native/libjava/Module.c	Thu Mar 23 22:57:12 2017 +0000
@@ -73,30 +73,32 @@
                                             jstring location, jobjectArray packages)
 {
     char** pkgs = NULL;
-    jsize idx;
     jsize num_packages = (*env)->GetArrayLength(env, packages);
 
     if (num_packages != 0 && (pkgs = calloc(num_packages, sizeof(char*))) == NULL) {
         JNU_ThrowOutOfMemoryError(env, NULL);
         return;
-    } else {
-        int valid = 1;
+    } else if ((*env)->EnsureLocalCapacity(env, (jint)num_packages) == 0) {
+        jboolean failed = JNI_FALSE;
+        int idx;
         for (idx = 0; idx < num_packages; idx++) {
             jstring pkg = (*env)->GetObjectArrayElement(env, packages, idx);
-            pkgs[idx] = GetInternalPackageName(env, pkg, NULL, 0);
-            if (pkgs[idx] == NULL) {
-                valid = 0;
+            char* name = GetInternalPackageName(env, pkg, NULL, 0);
+            if (name != NULL) {
+                pkgs[idx] = name;
+            } else {
+                failed = JNI_TRUE;
                 break;
             }
         }
-
-        if (valid != 0) {
+        if (!failed) {
             JVM_DefineModule(env, module, is_open, version, location,
-                    (const char* const*)pkgs, num_packages);
+                             (const char* const*)pkgs, num_packages);
         }
     }
 
     if (num_packages > 0) {
+        int idx;
         for (idx = 0; idx < num_packages; idx++) {
             if (pkgs[idx] != NULL) {
                 free(pkgs[idx]);
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonBorder.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonBorder.java	Thu Mar 23 22:57:12 2017 +0000
@@ -37,7 +37,7 @@
 import com.apple.laf.AquaUtils.*;
 
 public abstract class AquaButtonBorder extends AquaBorder implements Border, UIResource {
-    public static final RecyclableSingleton<Dynamic> fDynamic = new RecyclableSingletonFromDefaultConstructor<Dynamic>(Dynamic.class);
+    private static final RecyclableSingleton<Dynamic> fDynamic = new RecyclableSingletonFromDefaultConstructor<Dynamic>(Dynamic.class);
     public static AquaButtonBorder getDynamicButtonBorder() {
         return fDynamic.get();
     }
@@ -47,12 +47,12 @@
         return fToggle.get();
     }
 
-    public static final RecyclableSingleton<Toolbar> fToolBar = new RecyclableSingletonFromDefaultConstructor<Toolbar>(Toolbar.class);
+    private static final RecyclableSingleton<Toolbar> fToolBar = new RecyclableSingletonFromDefaultConstructor<Toolbar>(Toolbar.class);
     public static Border getToolBarButtonBorder() {
         return fToolBar.get();
     }
 
-    public static final RecyclableSingleton<Named> fBevel = new RecyclableSingleton<Named>() {
+    private static final RecyclableSingleton<Named> fBevel = new RecyclableSingleton<Named>() {
         protected Named getInstance() {
             return new Named(Widget.BUTTON_BEVEL, new SizeDescriptor(new SizeVariant().alterMargins(2, 4, 2, 4)));
         }
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonCheckBoxUI.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonCheckBoxUI.java	Thu Mar 23 22:57:12 2017 +0000
@@ -34,8 +34,8 @@
 import com.apple.laf.AquaUtils.*;
 
 public class AquaButtonCheckBoxUI extends AquaButtonLabeledUI {
-    protected static final RecyclableSingleton<AquaButtonCheckBoxUI> instance = new RecyclableSingletonFromDefaultConstructor<AquaButtonCheckBoxUI>(AquaButtonCheckBoxUI.class);
-    protected static final RecyclableSingleton<ImageIcon> sizingIcon = new RecyclableSingleton<ImageIcon>() {
+    private static final RecyclableSingleton<AquaButtonCheckBoxUI> instance = new RecyclableSingletonFromDefaultConstructor<AquaButtonCheckBoxUI>(AquaButtonCheckBoxUI.class);
+    private static final RecyclableSingleton<ImageIcon> sizingIcon = new RecyclableSingleton<ImageIcon>() {
         protected ImageIcon getInstance() {
             return new ImageIcon(AquaNativeResources.getRadioButtonSizerImage());
         }
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonExtendedTypes.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonExtendedTypes.java	Thu Mar 23 22:57:12 2017 +0000
@@ -138,7 +138,7 @@
         return typeDefinitions.get().get(name);
     }
 
-    protected static final RecyclableSingleton<Map<String, TypeSpecifier>> typeDefinitions = new RecyclableSingleton<Map<String, TypeSpecifier>>() {
+    private static final RecyclableSingleton<Map<String, TypeSpecifier>> typeDefinitions = new RecyclableSingleton<Map<String, TypeSpecifier>>() {
         protected Map<String, TypeSpecifier> getInstance() {
             return getAllTypes();
         }
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonLabeledUI.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonLabeledUI.java	Thu Mar 23 22:57:12 2017 +0000
@@ -42,9 +42,9 @@
 import com.apple.laf.AquaUtils.RecyclableSingleton;
 
 public abstract class AquaButtonLabeledUI extends AquaButtonToggleUI implements Sizeable {
-    protected static RecyclableSizingIcon regularIcon = new RecyclableSizingIcon(18);
-    protected static RecyclableSizingIcon smallIcon = new RecyclableSizingIcon(16);
-    protected static RecyclableSizingIcon miniIcon = new RecyclableSizingIcon(14);
+    private static final RecyclableSizingIcon regularIcon = new RecyclableSizingIcon(18);
+    private static final RecyclableSizingIcon smallIcon = new RecyclableSizingIcon(16);
+    private static final RecyclableSizingIcon miniIcon = new RecyclableSizingIcon(14);
 
     protected static class RecyclableSizingIcon extends RecyclableSingleton<Icon> {
         final int iconSize;
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonRadioUI.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonRadioUI.java	Thu Mar 23 22:57:12 2017 +0000
@@ -34,8 +34,8 @@
 import com.apple.laf.AquaUtils.*;
 
 public class AquaButtonRadioUI extends AquaButtonLabeledUI {
-    protected static final RecyclableSingleton<AquaButtonRadioUI> instance = new RecyclableSingletonFromDefaultConstructor<AquaButtonRadioUI>(AquaButtonRadioUI.class);
-    protected static final RecyclableSingleton<ImageIcon> sizingIcon = new RecyclableSingleton<ImageIcon>() {
+    private static final RecyclableSingleton<AquaButtonRadioUI> instance = new RecyclableSingletonFromDefaultConstructor<AquaButtonRadioUI>(AquaButtonRadioUI.class);
+    private static final RecyclableSingleton<ImageIcon> sizingIcon = new RecyclableSingleton<ImageIcon>() {
         protected ImageIcon getInstance() {
             return new ImageIcon(AquaNativeResources.getRadioButtonSizerImage());
         }
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonToggleUI.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonToggleUI.java	Thu Mar 23 22:57:12 2017 +0000
@@ -32,7 +32,7 @@
 
 public class AquaButtonToggleUI extends AquaButtonUI {
     // Create PLAF
-    static final RecyclableSingleton<AquaButtonToggleUI> aquaToggleButtonUI = new RecyclableSingletonFromDefaultConstructor<AquaButtonToggleUI>(AquaButtonToggleUI.class);
+    private static final RecyclableSingleton<AquaButtonToggleUI> aquaToggleButtonUI = new RecyclableSingletonFromDefaultConstructor<AquaButtonToggleUI>(AquaButtonToggleUI.class);
     public static ComponentUI createUI(final JComponent b) {
         return aquaToggleButtonUI.get();
     }
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonUI.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaButtonUI.java	Thu Mar 23 22:57:12 2017 +0000
@@ -48,7 +48,7 @@
     private static final String BUTTON_TYPE = "JButton.buttonType";
     private static final String SEGMENTED_BUTTON_POSITION = "JButton.segmentPosition";
 
-    protected static final RecyclableSingleton<AquaButtonUI> buttonUI = new RecyclableSingletonFromDefaultConstructor<AquaButtonUI>(AquaButtonUI.class);
+    private static final RecyclableSingleton<AquaButtonUI> buttonUI = new RecyclableSingletonFromDefaultConstructor<AquaButtonUI>(AquaButtonUI.class);
     public static ComponentUI createUI(final JComponent c) {
         return buttonUI.get();
     }
@@ -462,7 +462,7 @@
         return d;
     }
 
-    static final RecyclableSingleton<AquaHierarchyButtonListener> fHierListener = new RecyclableSingletonFromDefaultConstructor<AquaHierarchyButtonListener>(AquaHierarchyButtonListener.class);
+    private static final RecyclableSingleton<AquaHierarchyButtonListener> fHierListener = new RecyclableSingletonFromDefaultConstructor<AquaHierarchyButtonListener>(AquaHierarchyButtonListener.class);
     static AquaHierarchyButtonListener getAquaHierarchyButtonListener() {
         return fHierListener.get();
     }
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaComboBoxPopup.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaComboBoxPopup.java	Thu Mar 23 22:57:12 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,18 +25,29 @@
 
 package com.apple.laf;
 
-import java.awt.*;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
 import java.awt.Insets;
+import java.awt.Point;
 import java.awt.Rectangle;
-import java.awt.event.*;
+import java.awt.Toolkit;
+import java.awt.event.InputEvent;
+import java.awt.event.MouseEvent;
 
-import javax.swing.*;
+import javax.swing.Box;
+import javax.swing.JComboBox;
+import javax.swing.JList;
+import javax.swing.ListCellRenderer;
+import javax.swing.SwingUtilities;
 import javax.swing.plaf.basic.BasicComboPopup;
 
 import sun.lwawt.macosx.CPlatformWindow;
 
 @SuppressWarnings("serial") // Superclass is not serializable across versions
-class AquaComboBoxPopup extends BasicComboPopup {
+final class AquaComboBoxPopup extends BasicComboPopup {
     static final int FOCUS_RING_PAD_LEFT = 6;
     static final int FOCUS_RING_PAD_RIGHT = 6;
     static final int FOCUS_RING_PAD_BOTTOM = 5;
@@ -201,9 +212,6 @@
         //System.err.println("GetBestScreenBounds p: "+ p.x + ", " + p.y);
         final GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
         final GraphicsDevice[] gs = ge.getScreenDevices();
-        //System.err.println("  gs.length = " + gs.length);
-        final Rectangle comboBoxBounds = comboBox.getBounds();
-
         for (final GraphicsDevice gd : gs) {
             final GraphicsConfiguration[] gc = gd.getConfigurations();
             for (final GraphicsConfiguration element0 : gc) {
@@ -215,15 +223,14 @@
         }
 
         // Hmm.  Origin's off screen, but is any part on?
+        final Rectangle comboBoxBounds = comboBox.getBounds();
         comboBoxBounds.setLocation(p);
         for (final GraphicsDevice gd : gs) {
             final GraphicsConfiguration[] gc = gd.getConfigurations();
             for (final GraphicsConfiguration element0 : gc) {
                 final Rectangle gcBounds = element0.getBounds();
                 if (gcBounds.intersects(comboBoxBounds)) {
-                    if (gcBounds.contains(p)) {
-                        return getAvailableScreenArea(gcBounds, element0);
-                    }
+                    return getAvailableScreenArea(gcBounds, element0);
                 }
             }
         }
@@ -234,8 +241,15 @@
     private Rectangle getAvailableScreenArea(Rectangle bounds,
                                              GraphicsConfiguration gc) {
         Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc);
-        return new Rectangle(0, insets.top, bounds.width,
-                bounds.height - insets.top);
+        return new Rectangle(bounds.x + insets.left, bounds.y + insets.top,
+                             bounds.width - insets.left - insets.right,
+                             bounds.height - insets.top - insets.bottom);
+    }
+
+    private int getComboBoxEdge(int py, boolean bottom) {
+        int offset = bottom ? 9 : -9;
+        // if py is less than new y we have a clipped combo, so leave it alone.
+        return Math.min((py / 2) + offset, py);
     }
 
     @Override
@@ -246,7 +260,7 @@
         if (isPopdown && !isTableCellEditor) {
             // place the popup just below the button, which is
             // near the center of a large combo box
-            py = Math.min((py / 2) + 9, py); // if py is less than new y we have a clipped combo, so leave it alone.
+            py = getComboBoxEdge(py, true);
         }
 
         // px & py are relative to the combo box
@@ -291,8 +305,12 @@
         // Make sure it's all on the screen - shift it by the amount it's off
         p.x += px;
         p.y += py; // Screen location of px & py
-        if (p.x < scrBounds.x) px -= (p.x + scrBounds.x);
-        if (p.y < scrBounds.y) py -= (p.y + scrBounds.y);
+        if (p.x < scrBounds.x) {
+            px = px + (scrBounds.x - p.x);
+        }
+        if (p.y < scrBounds.y) {
+            py = py + (scrBounds.y - p.y);
+        }
 
         final Point top = new Point(0, 0);
         SwingUtilities.convertPointFromScreen(top, comboBox);
@@ -324,22 +342,27 @@
         }
 
         final Rectangle r = new Rectangle(px, py, pw, ph);
-        if (py + ph > scrBounds.y + scrBounds.height) {
-            if (ph <= -scrBounds.y ) {
-                // popup goes above
-                r.y = -ph ;
-            } else {
-                // a full screen height popup
-                r.y = scrBounds.y + Math.max(0, (scrBounds.height - ph) / 2 );
-                r.height = Math.min(scrBounds.height, ph);
-            }
+        if (r.y + r.height < top.y + scrBounds.y + scrBounds.height) {
+            return r;
+        }
+        // Check whether it goes below the bottom of the screen, if so flip it
+        int newY = getComboBoxEdge(comboBoxBounds.height, false) - ph - comboBoxInsets.top;
+        if (newY > top.y + scrBounds.y) {
+            return new Rectangle(px, newY, r.width, r.height);
+        } else {
+            // There are no place at top, move popup to the center of the screen
+            r.y = top.y + scrBounds.y + Math.max(0, (scrBounds.height - ph) / 2 );
+            r.height = Math.min(scrBounds.height, ph);
         }
         return r;
     }
 
     // The one to use when itemCount <= maxRowCount.  Size never adjusts for arrows
     // We want it positioned so the selected item is right above the combo box
-    protected Rectangle computePopupBoundsForMenu(final int px, final int py, final int pw, final int ph, final int itemCount, final Rectangle scrBounds) {
+    protected Rectangle computePopupBoundsForMenu(final int px, final int py,
+                                                  final int pw, final int ph,
+                                                  final int itemCount,
+                                                  final Rectangle scrBounds) {
         //System.err.println("computePopupBoundsForMenu: " + px + "," + py + " " +  pw + "," + ph);
         //System.err.println("itemCount: " +itemCount +" src: "+ scrBounds);
         int elementSize = 0; //kDefaultItemSize;
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaComboBoxUI.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaComboBoxUI.java	Thu Mar 23 22:57:12 2017 +0000
@@ -594,7 +594,7 @@
     }
 
     @SuppressWarnings("unchecked")
-    static final RecyclableSingleton<ClientPropertyApplicator<JComboBox<?>, AquaComboBoxUI>> APPLICATOR = new
+    private static final RecyclableSingleton<ClientPropertyApplicator<JComboBox<?>, AquaComboBoxUI>> APPLICATOR = new
             RecyclableSingleton<ClientPropertyApplicator<JComboBox<?>, AquaComboBoxUI>>() {
         @Override
         protected ClientPropertyApplicator<JComboBox<?>, AquaComboBoxUI> getInstance() {
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaFileView.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaFileView.java	Thu Mar 23 22:57:12 2017 +0000
@@ -75,7 +75,7 @@
     private static native int getNativeLSInfo(final byte[] pathBytes, final boolean isDirectory);
     private static native String getNativePathForResolvedAlias(final byte[] absolutePath, final boolean isDirectory);
 
-    static final RecyclableSingleton<String> machineName = new RecyclableSingleton<String>() {
+    private static final RecyclableSingleton<String> machineName = new RecyclableSingleton<String>() {
         @Override
         protected String getInstance() {
             return getNativeMachineName();
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaGroupBorder.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaGroupBorder.java	Thu Mar 23 22:57:12 2017 +0000
@@ -35,17 +35,17 @@
 import com.apple.laf.AquaUtils.RecyclableSingletonFromDefaultConstructor;
 
 public abstract class AquaGroupBorder extends AquaBorder {
-    static final RecyclableSingletonFromDefaultConstructor<? extends Border> tabbedPaneGroupBorder = new RecyclableSingletonFromDefaultConstructor<TabbedPane>(TabbedPane.class);
+    private static final RecyclableSingletonFromDefaultConstructor<? extends Border> tabbedPaneGroupBorder = new RecyclableSingletonFromDefaultConstructor<TabbedPane>(TabbedPane.class);
     public static Border getTabbedPaneGroupBorder() {
         return tabbedPaneGroupBorder.get();
     }
 
-    static final RecyclableSingletonFromDefaultConstructor<? extends Border> titleBorderGroupBorder = new RecyclableSingletonFromDefaultConstructor<Titled>(Titled.class);
+    private static final RecyclableSingletonFromDefaultConstructor<? extends Border> titleBorderGroupBorder = new RecyclableSingletonFromDefaultConstructor<Titled>(Titled.class);
     public static Border getBorderForTitledBorder() {
         return titleBorderGroupBorder.get();
     }
 
-    static final RecyclableSingletonFromDefaultConstructor<? extends Border> titlelessGroupBorder = new RecyclableSingletonFromDefaultConstructor<Titleless>(Titleless.class);
+    private static final RecyclableSingletonFromDefaultConstructor<? extends Border> titlelessGroupBorder = new RecyclableSingletonFromDefaultConstructor<Titleless>(Titleless.class);
     public static Border getTitlelessBorder() {
         return titlelessGroupBorder.get();
     }
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaHighlighter.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaHighlighter.java	Thu Mar 23 22:57:12 2017 +0000
@@ -37,7 +37,7 @@
 import com.apple.laf.AquaUtils.RecyclableSingleton;
 
 public class AquaHighlighter extends DefaultHighlighter implements UIResource {
-    static final RecyclableSingleton<LayerPainter> instance = new RecyclableSingleton<LayerPainter>() {
+    private static final RecyclableSingleton<LayerPainter> instance = new RecyclableSingleton<LayerPainter>() {
         protected LayerPainter getInstance() {
             return new AquaHighlightPainter(null);
         }
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaImageFactory.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaImageFactory.java	Thu Mar 23 22:57:12 2017 +0000
@@ -240,14 +240,14 @@
         }
     }
 
-    protected static final NamedImageSingleton northArrow = new NamedImageSingleton("NSMenuScrollUp");
-    protected static final IconUIResourceSingleton northArrowIcon = new IconUIResourceSingleton(northArrow);
-    protected static final NamedImageSingleton southArrow = new NamedImageSingleton("NSMenuScrollDown");
-    protected static final IconUIResourceSingleton southArrowIcon = new IconUIResourceSingleton(southArrow);
-    protected static final NamedImageSingleton westArrow = new NamedImageSingleton("NSMenuSubmenuLeft");
-    protected static final IconUIResourceSingleton westArrowIcon = new IconUIResourceSingleton(westArrow);
-    protected static final NamedImageSingleton eastArrow = new NamedImageSingleton("NSMenuSubmenu");
-    protected static final IconUIResourceSingleton eastArrowIcon = new IconUIResourceSingleton(eastArrow);
+    private static final NamedImageSingleton northArrow = new NamedImageSingleton("NSMenuScrollUp");
+    private static final IconUIResourceSingleton northArrowIcon = new IconUIResourceSingleton(northArrow);
+    private static final NamedImageSingleton southArrow = new NamedImageSingleton("NSMenuScrollDown");
+    private static final IconUIResourceSingleton southArrowIcon = new IconUIResourceSingleton(southArrow);
+    private static final NamedImageSingleton westArrow = new NamedImageSingleton("NSMenuSubmenuLeft");
+    private static final IconUIResourceSingleton westArrowIcon = new IconUIResourceSingleton(westArrow);
+    private static final NamedImageSingleton eastArrow = new NamedImageSingleton("NSMenuSubmenu");
+    private static final IconUIResourceSingleton eastArrowIcon = new IconUIResourceSingleton(eastArrow);
 
     static Image getArrowImageForDirection(final int direction) {
         switch(direction) {
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameBorder.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameBorder.java	Thu Mar 23 22:57:12 2017 +0000
@@ -55,7 +55,7 @@
 
     private static final int kContentTester = 100; // For getting region insets
 
-    static final RecyclableSingleton<AquaInternalFrameBorder> documentWindowFrame = new RecyclableSingleton<AquaInternalFrameBorder>() {
+    private static final RecyclableSingleton<AquaInternalFrameBorder> documentWindowFrame = new RecyclableSingleton<AquaInternalFrameBorder>() {
         protected AquaInternalFrameBorder getInstance() {
             return new AquaInternalFrameBorder(WindowType.DOCUMENT);
         }
@@ -64,7 +64,7 @@
         return documentWindowFrame.get();
     }
 
-    static final RecyclableSingleton<AquaInternalFrameBorder> utilityWindowFrame = new RecyclableSingleton<AquaInternalFrameBorder>() {
+    private static final RecyclableSingleton<AquaInternalFrameBorder> utilityWindowFrame = new RecyclableSingleton<AquaInternalFrameBorder>() {
         protected AquaInternalFrameBorder getInstance() {
             return new AquaInternalFrameBorder(WindowType.UTILITY);
         }
@@ -73,7 +73,7 @@
         return utilityWindowFrame.get();
     }
 
-    static final RecyclableSingleton<AquaInternalFrameBorder> dialogWindowFrame = new RecyclableSingleton<AquaInternalFrameBorder>() {
+    private static final RecyclableSingleton<AquaInternalFrameBorder> dialogWindowFrame = new RecyclableSingleton<AquaInternalFrameBorder>() {
         protected AquaInternalFrameBorder getInstance() {
             return new AquaInternalFrameBorder(WindowType.DOCUMENT);
         }
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameUI.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaInternalFrameUI.java	Thu Mar 23 22:57:12 2017 +0000
@@ -147,7 +147,7 @@
         southPane = c;
     }
 
-    static final RecyclableSingleton<Icon> closeIcon = new RecyclableSingleton<Icon>() {
+    private static final RecyclableSingleton<Icon> closeIcon = new RecyclableSingleton<Icon>() {
         @Override
         protected Icon getInstance() {
             return new AquaInternalFrameButtonIcon(Widget.TITLE_BAR_CLOSE_BOX);
@@ -157,7 +157,7 @@
         return closeIcon.get();
     }
 
-    static final RecyclableSingleton<Icon> minimizeIcon = new RecyclableSingleton<Icon>() {
+    private static final RecyclableSingleton<Icon> minimizeIcon = new RecyclableSingleton<Icon>() {
         @Override
         protected Icon getInstance() {
             return new AquaInternalFrameButtonIcon(Widget.TITLE_BAR_COLLAPSE_BOX);
@@ -167,7 +167,7 @@
         return minimizeIcon.get();
     }
 
-    static final RecyclableSingleton<Icon> zoomIcon = new RecyclableSingleton<Icon>() {
+    private static final RecyclableSingleton<Icon> zoomIcon = new RecyclableSingleton<Icon>() {
         @Override
         protected Icon getInstance() {
             return new AquaInternalFrameButtonIcon(Widget.TITLE_BAR_ZOOM_BOX);
@@ -738,7 +738,7 @@
         }
     } // end class PaletteListener
 
-    static final InternalFrameShadow documentWindowShadow = new InternalFrameShadow() {
+    private static final InternalFrameShadow documentWindowShadow = new InternalFrameShadow() {
         @Override
         Border getForegroundShadowBorder() {
             return new AquaUtils.SlicedShadowBorder(new Painter() {
@@ -778,7 +778,7 @@
         }
     };
 
-    static final InternalFrameShadow paletteWindowShadow = new InternalFrameShadow() {
+    private static final InternalFrameShadow paletteWindowShadow = new InternalFrameShadow() {
         @Override
         Border getForegroundShadowBorder() {
             return new AquaUtils.SlicedShadowBorder(new Painter() {
@@ -834,7 +834,7 @@
         }
     }
 
-    static final RecyclableSingleton<Icon> RESIZE_ICON = new RecyclableSingleton<Icon>() {
+    private static final RecyclableSingleton<Icon> RESIZE_ICON = new RecyclableSingleton<Icon>() {
         @Override
         protected Icon getInstance() {
             return new AquaIcon.ScalingJRSUIIcon(11, 11) {
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaKeyBindings.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaKeyBindings.java	Thu Mar 23 22:57:12 2017 +0000
@@ -37,7 +37,7 @@
 import com.apple.laf.AquaUtils.RecyclableSingletonFromDefaultConstructor;
 
 public class AquaKeyBindings {
-    static final RecyclableSingleton<AquaKeyBindings> instance = new RecyclableSingletonFromDefaultConstructor<AquaKeyBindings>(AquaKeyBindings.class);
+    private static final RecyclableSingleton<AquaKeyBindings> instance = new RecyclableSingletonFromDefaultConstructor<AquaKeyBindings>(AquaKeyBindings.class);
     static AquaKeyBindings instance() {
         return instance.get();
     }
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaLabelUI.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaLabelUI.java	Thu Mar 23 22:57:12 2017 +0000
@@ -37,7 +37,7 @@
 import com.apple.laf.AquaUtils.RecyclableSingletonFromDefaultConstructor;
 
 public class AquaLabelUI extends BasicLabelUI {
-    protected static final  RecyclableSingleton<AquaLabelUI> aquaLabelUI = new RecyclableSingletonFromDefaultConstructor<AquaLabelUI>(AquaLabelUI.class);
+    private static final RecyclableSingleton<AquaLabelUI> aquaLabelUI = new RecyclableSingletonFromDefaultConstructor<AquaLabelUI>(AquaLabelUI.class);
 
     public static ComponentUI createUI(final JComponent c) {
         return aquaLabelUI.get();
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaMenuPainter.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaMenuPainter.java	Thu Mar 23 22:57:12 2017 +0000
@@ -125,7 +125,7 @@
         return buf.toString();
     }
 
-    static final RecyclableSingleton<AquaMenuPainter> sPainter = new RecyclableSingletonFromDefaultConstructor<AquaMenuPainter>(AquaMenuPainter.class);
+    private static final RecyclableSingleton<AquaMenuPainter> sPainter = new RecyclableSingletonFromDefaultConstructor<AquaMenuPainter>(AquaMenuPainter.class);
     static AquaMenuPainter instance() {
         return sPainter.get();
     }
@@ -139,9 +139,9 @@
         protected Border getInstance() { return UIManager.getBorder(borderName); }
     }
 
-    protected final RecyclableBorder menuBarPainter = new RecyclableBorder("MenuBar.backgroundPainter");
-    protected final RecyclableBorder selectedMenuBarItemPainter = new RecyclableBorder("MenuBar.selectedBackgroundPainter");
-    protected final RecyclableBorder selectedMenuItemPainter = new RecyclableBorder("MenuItem.selectedBackgroundPainter");
+    private static final RecyclableBorder menuBarPainter = new RecyclableBorder("MenuBar.backgroundPainter");
+    private static final RecyclableBorder selectedMenuBarItemPainter = new RecyclableBorder("MenuBar.selectedBackgroundPainter");
+    private static final RecyclableBorder selectedMenuItemPainter = new RecyclableBorder("MenuItem.selectedBackgroundPainter");
 
     public void paintMenuBarBackground(final Graphics g, final int width, final int height, final JComponent c) {
         g.setColor(c == null ? Color.white : c.getBackground());
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaMnemonicHandler.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaMnemonicHandler.java	Thu Mar 23 22:57:12 2017 +0000
@@ -34,7 +34,7 @@
 import com.apple.laf.AquaUtils.RecyclableSingletonFromDefaultConstructor;
 
 public class AquaMnemonicHandler {
-    static final RecyclableSingleton<AltProcessor> altProcessor = new RecyclableSingletonFromDefaultConstructor<AltProcessor>(AltProcessor.class);
+    private static final RecyclableSingleton<AltProcessor> altProcessor = new RecyclableSingletonFromDefaultConstructor<AltProcessor>(AltProcessor.class);
     public static KeyEventPostProcessor getInstance() {
         return altProcessor.get();
     }
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaNativeResources.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaNativeResources.java	Thu Mar 23 22:57:12 2017 +0000
@@ -54,7 +54,7 @@
         }
     }
 
-    static final RecyclableSingleton<Color> sBackgroundColor = new RecyclableSingleton<Color>() {
+    private static final RecyclableSingleton<Color> sBackgroundColor = new RecyclableSingleton<Color>() {
         @Override
         protected Color getInstance() {
             final long backgroundID = getWindowBackgroundColor();
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaPanelUI.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaPanelUI.java	Thu Mar 23 22:57:12 2017 +0000
@@ -35,7 +35,7 @@
 import java.awt.Graphics;
 
 public class AquaPanelUI extends BasicPanelUI {
-    static RecyclableSingleton<AquaPanelUI> instance = new RecyclableSingletonFromDefaultConstructor<AquaPanelUI>(AquaPanelUI.class);
+    private static final RecyclableSingleton<AquaPanelUI> instance = new RecyclableSingletonFromDefaultConstructor<AquaPanelUI>(AquaPanelUI.class);
 
     public static ComponentUI createUI(final JComponent c) {
         return instance.get();
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaPopupMenuSeparatorUI.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaPopupMenuSeparatorUI.java	Thu Mar 23 22:57:12 2017 +0000
@@ -34,7 +34,7 @@
 import com.apple.laf.AquaUtils.RecyclableSingletonFromDefaultConstructor;
 
 public class AquaPopupMenuSeparatorUI extends BasicSeparatorUI {
-    protected static RecyclableSingletonFromDefaultConstructor<AquaPopupMenuSeparatorUI> instance = new RecyclableSingletonFromDefaultConstructor<AquaPopupMenuSeparatorUI>(AquaPopupMenuSeparatorUI.class);
+    private static final RecyclableSingletonFromDefaultConstructor<AquaPopupMenuSeparatorUI> instance = new RecyclableSingletonFromDefaultConstructor<AquaPopupMenuSeparatorUI>(AquaPopupMenuSeparatorUI.class);
 
     public static ComponentUI createUI(final JComponent c) {
         return instance.get();
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaProgressBarUI.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaProgressBarUI.java	Thu Mar 23 22:57:12 2017 +0000
@@ -46,7 +46,7 @@
 public class AquaProgressBarUI extends ProgressBarUI implements ChangeListener, PropertyChangeListener, AncestorListener, Sizeable {
     private static final boolean ADJUSTTIMER = true;
 
-    protected static final RecyclableSingleton<SizeDescriptor> sizeDescriptor = new RecyclableSingleton<SizeDescriptor>() {
+    private static final RecyclableSingleton<SizeDescriptor> sizeDescriptor = new RecyclableSingleton<SizeDescriptor>() {
         @Override
         protected SizeDescriptor getInstance() {
             return new SizeDescriptor(new SizeVariant(146, 20)) {
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaScrollBarUI.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaScrollBarUI.java	Thu Mar 23 22:57:12 2017 +0000
@@ -154,7 +154,7 @@
         return State.ACTIVE;
     }
 
-    static final RecyclableSingleton<Map<Hit, ScrollBarPart>> hitToPressedPartMap = new RecyclableSingleton<Map<Hit,ScrollBarPart>>(){
+    private static final RecyclableSingleton<Map<Hit, ScrollBarPart>> hitToPressedPartMap = new RecyclableSingleton<Map<Hit,ScrollBarPart>>(){
         @Override
         protected Map<Hit, ScrollBarPart> getInstance() {
             final Map<Hit, ScrollBarPart> map = new HashMap<Hit, ScrollBarPart>(7);
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaScrollRegionBorder.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaScrollRegionBorder.java	Thu Mar 23 22:57:12 2017 +0000
@@ -40,7 +40,7 @@
 import com.apple.laf.AquaUtils.RecyclableSingletonFromDefaultConstructor;
 
 public class AquaScrollRegionBorder extends AquaBorder {
-    static final RecyclableSingletonFromDefaultConstructor<AquaScrollRegionBorder> instance = new RecyclableSingletonFromDefaultConstructor<AquaScrollRegionBorder>(AquaScrollRegionBorder.class);
+    private static final RecyclableSingletonFromDefaultConstructor<AquaScrollRegionBorder> instance = new RecyclableSingletonFromDefaultConstructor<AquaScrollRegionBorder>(AquaScrollRegionBorder.class);
 
     public static AquaScrollRegionBorder getScrollRegionBorder() {
         return instance.get();
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaSliderUI.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaSliderUI.java	Thu Mar 23 22:57:12 2017 +0000
@@ -45,7 +45,7 @@
 //    static final Dimension roundThumbSize = new Dimension(21 + 4, 21 + 4); // +2px on both sides for focus fuzz
 //    static final Dimension pointingThumbSize = new Dimension(19 + 4, 22 + 4);
 
-    protected static final RecyclableSingleton<SizeDescriptor> roundThumbDescriptor = new RecyclableSingleton<SizeDescriptor>() {
+    private static final RecyclableSingleton<SizeDescriptor> roundThumbDescriptor = new RecyclableSingleton<SizeDescriptor>() {
         protected SizeDescriptor getInstance() {
             return new SizeDescriptor(new SizeVariant(25, 25)) {
                 public SizeVariant deriveSmall(final SizeVariant v) {
@@ -57,7 +57,7 @@
             };
         }
     };
-    protected static final RecyclableSingleton<SizeDescriptor> pointingThumbDescriptor = new RecyclableSingleton<SizeDescriptor>() {
+    private static final RecyclableSingleton<SizeDescriptor> pointingThumbDescriptor = new RecyclableSingleton<SizeDescriptor>() {
         protected SizeDescriptor getInstance() {
             return new SizeDescriptor(new SizeVariant(23, 26)) {
                 public SizeVariant deriveSmall(final SizeVariant v) {
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaTableHeaderBorder.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaTableHeaderBorder.java	Thu Mar 23 22:57:12 2017 +0000
@@ -126,7 +126,7 @@
         return State.ACTIVE;
     }
 
-    static final RecyclableSingleton<Border> alternateBorder = new RecyclableSingleton<Border>() {
+    private static final RecyclableSingleton<Border> alternateBorder = new RecyclableSingleton<Border>() {
         @Override
         protected Border getInstance() {
             return BorderFactory.createRaisedBevelBorder();
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaTableHeaderUI.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaTableHeaderUI.java	Thu Mar 23 22:57:12 2017 +0000
@@ -67,7 +67,7 @@
         super.uninstallDefaults();
     }
 
-    static final RecyclableSingleton<ClientPropertyApplicator<JTableHeader, JTableHeader>> TABLE_HEADER_APPLICATORS = new RecyclableSingleton<ClientPropertyApplicator<JTableHeader, JTableHeader>>() {
+    private static final RecyclableSingleton<ClientPropertyApplicator<JTableHeader, JTableHeader>> TABLE_HEADER_APPLICATORS = new RecyclableSingleton<ClientPropertyApplicator<JTableHeader, JTableHeader>>() {
         @Override
         @SuppressWarnings("unchecked")
         protected ClientPropertyApplicator<JTableHeader, JTableHeader> getInstance() {
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaTextFieldBorder.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaTextFieldBorder.java	Thu Mar 23 22:57:12 2017 +0000
@@ -36,7 +36,7 @@
 import com.apple.laf.AquaUtils.*;
 
 public class AquaTextFieldBorder extends AquaBorder {
-    protected static final RecyclableSingleton<AquaTextFieldBorder> instance = new RecyclableSingletonFromDefaultConstructor<AquaTextFieldBorder>(AquaTextFieldBorder.class);
+    private static final RecyclableSingleton<AquaTextFieldBorder> instance = new RecyclableSingletonFromDefaultConstructor<AquaTextFieldBorder>(AquaTextFieldBorder.class);
     public static AquaTextFieldBorder getTextFieldBorder() {
         return instance.get();
     }
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaTextFieldSearch.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaTextFieldSearch.java	Thu Mar 23 22:57:12 2017 +0000
@@ -90,7 +90,7 @@
         return (c.getClientProperty(FIND_POPUP_KEY) instanceof JPopupMenu);
     }
 
-    protected static final RecyclableSingleton<SearchFieldBorder> instance = new RecyclableSingletonFromDefaultConstructor<SearchFieldBorder>(SearchFieldBorder.class);
+    private static final RecyclableSingleton<SearchFieldBorder> instance = new RecyclableSingletonFromDefaultConstructor<SearchFieldBorder>(SearchFieldBorder.class);
     public static SearchFieldBorder getSearchTextFieldBorder() {
         return instance.get();
     }
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaTextPasswordFieldUI.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaTextPasswordFieldUI.java	Thu Mar 23 22:57:12 2017 +0000
@@ -38,7 +38,7 @@
 import com.apple.laf.AquaUtils.RecyclableSingletonFromDefaultConstructor;
 
 public class AquaTextPasswordFieldUI extends AquaTextFieldUI {
-    static final RecyclableSingleton<CapsLockSymbolPainter> capsLockPainter = new RecyclableSingletonFromDefaultConstructor<CapsLockSymbolPainter>(CapsLockSymbolPainter.class);
+    private static final RecyclableSingleton<CapsLockSymbolPainter> capsLockPainter = new RecyclableSingletonFromDefaultConstructor<CapsLockSymbolPainter>(CapsLockSymbolPainter.class);
     static CapsLockSymbolPainter getCapsLockPainter() {
         return capsLockPainter.get();
     }
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaToolBarSeparatorUI.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaToolBarSeparatorUI.java	Thu Mar 23 22:57:12 2017 +0000
@@ -34,7 +34,7 @@
 import com.apple.laf.AquaUtils.*;
 
 public class AquaToolBarSeparatorUI extends BasicToolBarSeparatorUI {
-    protected static RecyclableSingleton<AquaToolBarSeparatorUI> instance = new RecyclableSingletonFromDefaultConstructor<AquaToolBarSeparatorUI>(AquaToolBarSeparatorUI.class);
+    private static final RecyclableSingleton<AquaToolBarSeparatorUI> instance = new RecyclableSingletonFromDefaultConstructor<AquaToolBarSeparatorUI>(AquaToolBarSeparatorUI.class);
 
     public static ComponentUI createUI(final JComponent c) {
         return instance.get();
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaToolBarUI.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaToolBarUI.java	Thu Mar 23 22:57:12 2017 +0000
@@ -35,7 +35,7 @@
 import com.apple.laf.AquaUtils.*;
 
 public class AquaToolBarUI extends BasicToolBarUI implements SwingConstants {
-    private static RecyclableSingleton<ToolBarBorder> toolBarBorder = new RecyclableSingletonFromDefaultConstructor<ToolBarBorder>(ToolBarBorder.class);
+    private static final RecyclableSingleton<ToolBarBorder> toolBarBorder = new RecyclableSingletonFromDefaultConstructor<ToolBarBorder>(ToolBarBorder.class);
     public static Border getToolBarBorder() {
         return toolBarBorder.get();
     }
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaToolTipUI.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaToolTipUI.java	Thu Mar 23 22:57:12 2017 +0000
@@ -34,7 +34,7 @@
 import com.apple.laf.AquaUtils.RecyclableSingletonFromDefaultConstructor;
 
 public class AquaToolTipUI extends BasicToolTipUI {
-    static final RecyclableSingletonFromDefaultConstructor<AquaToolTipUI> sharedAquaInstance = new RecyclableSingletonFromDefaultConstructor<AquaToolTipUI>(AquaToolTipUI.class);
+    private static final RecyclableSingletonFromDefaultConstructor<AquaToolTipUI> sharedAquaInstance = new RecyclableSingletonFromDefaultConstructor<AquaToolTipUI>(AquaToolTipUI.class);
 
     public static ComponentUI createUI(final JComponent c) {
         return sharedAquaInstance.get();
--- a/src/java.desktop/macosx/classes/com/apple/laf/AquaUtilControlSize.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaUtilControlSize.java	Thu Mar 23 22:57:12 2017 +0000
@@ -49,7 +49,7 @@
         void applySizeFor(final JComponent c, final Size size);
     }
 
-    protected static final RecyclableSingleton<PropertySizeListener> sizeListener
+    private static final RecyclableSingleton<PropertySizeListener> sizeListener
             = new RecyclableSingletonFromDefaultConstructor<>(PropertySizeListener.class);
     protected static PropertySizeListener getSizeListener() {
         return sizeListener.get();
--- a/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.m	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.m	Thu Mar 23 22:57:12 2017 +0000
@@ -284,28 +284,21 @@
     CGFloat components[component_size];
     CGGradientRef gradient = NULL;
 
-    for (int i = 0; i < num_locations; i++) {
+    for (i = 0; i < num_locations; i++) {
         locations[i] = gradientInfo->fractionsdata[i];
-//fprintf(stderr, "locations[%d] %f\n", i, locations[i]);
     }
     for (i = 0; i < component_size; i++) {
         components[i] = gradientInfo->colordata[i];
-//fprintf(stderr, "components[%d] %f, gradientInfo->colordata[%d] %f\n",
-//                  i, components[i], i, gradientInfo->colordata[i]);
     } 
     CGContextSaveGState(cgRef);
     gradient = CGGradientCreateWithColorComponents(colorspace, components, locations, num_locations);
-//fprintf(stderr, "gradientInfo->start.x %f, gradientInfo->start.y %f\n", 
-//                 gradientInfo->start.x, gradientInfo->start.y);
-//fprintf(stderr, "gradientInfo->end.x %f, gradientInfo->end.y %f\n", 
-//                 gradientInfo->end.x, gradientInfo->end.y);
     if (qsdo->isEvenOddFill) {
         CGContextEOClip(cgRef);
     } else {
         CGContextClip(cgRef);
     }
     CGContextDrawLinearGradient(cgRef, gradient, gradientInfo->start, gradientInfo->end, kCGGradientDrawsAfterEndLocation);    
-    
+
     CGContextRestoreGState(cgRef);
     CGColorSpaceRelease(colorspace);
     CGGradientRelease(gradient);
@@ -332,27 +325,19 @@
     CGFloat startRadius = gradientInfo->radius;
     CGFloat endRadius = gradientInfo->radius;
 
-    for (int i = 0; i < num_locations; i++) {
+    for (i = 0; i < num_locations; i++) {
         locations[i] = gradientInfo->fractionsdata[i];
-//fprintf(stderr, "locations[%d] %f\n", i, locations[i]);
     }
     for (i = 0; i < component_size; i++) {
         components[i] = gradientInfo->colordata[i];
-//fprintf(stderr, "components[%d] %f, gradientInfo->colordata[%d] %f\n",
-//                  i, components[i], i, gradientInfo->colordata[i]);
     } 
     CGContextSaveGState(cgRef);
     gradient = CGGradientCreateWithColorComponents(colorspace, components, locations, num_locations);
-//fprintf(stderr, "gradientInfo->start.x %f, gradientInfo->start.y %f\n", 
-//                 gradientInfo->start.x, gradientInfo->start.y);
-//fprintf(stderr, "gradientInfo->end.x %f, gradientInfo->end.y %f\n", 
-//                 gradientInfo->end.x, gradientInfo->end.y);
     if (qsdo->isEvenOddFill) {
         CGContextEOClip(cgRef);
     } else {
         CGContextClip(cgRef);
     }
-//fprintf(stderr, "gradientInfo->startRadius %f, gradientInfo->endRadius %f\n",startRadius,endRadius);
     CGContextDrawRadialGradient(cgRef, gradient, gradientInfo->start, 0, gradientInfo->end, endRadius, kCGGradientDrawsAfterEndLocation);    
     
     CGContextRestoreGState(cgRef);
@@ -944,54 +929,41 @@
     if (colorArray != NULL)
     {
         jint length = (*env)->GetArrayLength(env, colorArray);
-//fprintf(stderr, "length %d\n", length);
 
         jint* jcolorData = (jint*)(*env)->GetPrimitiveArrayCritical(env, colorArray, NULL);
-        CGFloat* colors= (CGFloat*)calloc(0, sizeof(CGFloat)*length);
+        qsdo->gradientInfo->colordata = (CGFloat*)malloc(sizeof(CGFloat)*4*length);
+        memset(qsdo->gradientInfo->colordata, 0, sizeof(CGFloat)*4*length);
         if (jcolorData != NULL)
         {
-            jint i;
+            int i;
             for (i=0; i<length; i++)
             {
-                colors[i] = (CGFloat)jcolorData[i];
+                qsdo->gradientInfo->colordata[i*4] = ((jcolorData[i]>>16)&0xff)*kColorConversionMultiplier;
+
+                qsdo->gradientInfo->colordata[i*4+1] = ((jcolorData[i]>>8)&0xff)*kColorConversionMultiplier;
+
+                qsdo->gradientInfo->colordata[i*4+2] = ((jcolorData[i]>>0)&0xff)*kColorConversionMultiplier;
+
+                qsdo->gradientInfo->colordata[i*4+3] = ((jcolorData[i]>>24)&0xff)*kColorConversionMultiplier;
             }
         }
         (*env)->ReleasePrimitiveArrayCritical(env, colorArray, jcolorData, 0);
-        qsdo->gradientInfo->colordata = (CGFloat*)calloc(0, sizeof(CGFloat)*4*length);
-        for (int i = 0; i < length; i++) 
-        {
-            jint c1 = colors[i];
-//fprintf(stderr, "c1 %x\n", c1);
-            qsdo->gradientInfo->colordata[i*4] = ((c1>>16)&0xff)*kColorConversionMultiplier;
-//fprintf(stderr, "qsdo->gradientInfo->colordata[%d] %f\n", i*4, qsdo->gradientInfo->colordata[i*4]);
-
-            qsdo->gradientInfo->colordata[i*4+1] = ((c1>>8)&0xff)*kColorConversionMultiplier;
-//fprintf(stderr, "qsdo->gradientInfo->colordata[%d] %f\n", i*4+1, qsdo->gradientInfo->colordata[i*4+1]);
-
-            qsdo->gradientInfo->colordata[i*4+2] = ((c1>>0)&0xff)*kColorConversionMultiplier;
-//fprintf(stderr, "qsdo->gradientInfo->colordata[%d] %f\n", i*4+2, qsdo->gradientInfo->colordata[i*4+2]);
-
-            qsdo->gradientInfo->colordata[i*4+3] = ((c1>>24)&0xff)*kColorConversionMultiplier;
-//fprintf(stderr, "qsdo->gradientInfo->colordata[%d] %f\n", i*4+3, qsdo->gradientInfo->colordata[i*4+3]);
-        }
-        free(colors);
     }
     jobject fractionsArray  = ((*env)->GetObjectArrayElement(env, qsdo->javaGraphicsStatesObjects, sun_java2d_OSXSurfaceData_kFractionsArrayIndex)); 
     if (fractionsArray != NULL)
     {
         jint length = (*env)->GetArrayLength(env, fractionsArray);
-//fprintf(stderr, "fractions length %d\n", length);
         qsdo->gradientInfo->fractionsLength = length;
 
         jfloat* jfractionsData = (jfloat*)(*env)->GetPrimitiveArrayCritical(env, fractionsArray, NULL);
         if (jfractionsData != NULL)
         {
+            int i;
             qsdo->gradientInfo->fractionsdata = (CGFloat *)malloc(sizeof(CGFloat) *length);
-            jint i;
+            memset(qsdo->gradientInfo->fractionsdata, 0, sizeof(CGFloat)*length);
             for (i=0; i<length; i++)
             {
                 qsdo->gradientInfo->fractionsdata[i] = jfractionsData[i];
-//fprintf(stderr, "jfrationsData[%d] %f, qsdo->gradientInfo->fractionsdata[%d] = %f\n", i, jfractionsData[i], i, qsdo->gradientInfo->fractionsdata[i]);
             }
             (*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, jfractionsData, 0);
         }
--- a/src/java.desktop/share/classes/java/awt/Taskbar.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/share/classes/java/awt/Taskbar.java	Thu Mar 23 22:57:12 2017 +0000
@@ -274,6 +274,10 @@
     /**
      * Requests user attention to the specified window.
      *
+     * Has no effect if a window representation is not displayable in
+     * the task area. Whether it is displayable is dependent on all
+     * of window type, platform, and implementation.
+     *
      * @param w window
      * @throws SecurityException if a security manager exists and it denies the
      * {@code RuntimePermission("canProcessApplicationEvents")} permission.
@@ -375,6 +379,10 @@
      * for the specified window.
      * It may be disabled by system settings.
      *
+     * Has no effect if a window representation is not displayable in
+     * the task area. Whether it is displayable is dependent on all
+     * of window type, platform, and implementation.
+     *
      * @param w window to update
      * @param badge image to affix to the icon
      * @throws SecurityException if a security manager exists and it denies the
@@ -409,6 +417,11 @@
     /**
      * Displays a determinate progress bar in the task area for the specified
      * window.
+     *
+     * Has no effect if a window representation is not displayable in
+     * the task area. Whether it is displayable is dependent on all
+     * of window type, platform, and implementation.
+     *
      * <br>
      * The visual behavior is platform and {@link State} dependent.
      * <br>
@@ -437,6 +450,10 @@
 
     /**
      * Sets a progress state for a specified window.
+     *
+     * Has no effect if a window representation is not displayable in
+     * the task area. Whether it is displayable is dependent on all
+     * of window type, platform, and implementation.
      * <br>
      * Each state displays a progress in a platform-dependent way.
      * <br>
--- a/src/java.desktop/share/classes/javax/accessibility/AccessibleContext.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/share/classes/javax/accessibility/AccessibleContext.java	Thu Mar 23 22:57:12 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, 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
@@ -36,8 +36,6 @@
 import java.beans.PropertyChangeEvent;
 import java.awt.IllegalComponentStateException;
 
-import javax.swing.SwingContainer;
-
 /**
  * AccessibleContext represents the minimum information all accessible objects
  * return.  This information includes the accessible name, description, role,
@@ -79,7 +77,6 @@
  * @author      Lynn Monsanto
  */
 @JavaBean(description = "Minimal information that all accessible objects return")
-@SwingContainer(false)
 public abstract class AccessibleContext {
 
     /**
--- a/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalIconFactory.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalIconFactory.java	Thu Mar 23 22:57:12 2017 +0000
@@ -33,6 +33,8 @@
 import java.util.Enumeration;
 import java.util.Vector;
 import sun.swing.CachedPainter;
+import static sun.swing.SwingUtilities2.setAntialiasingHintForScaledGraphics;
+import static sun.swing.SwingUtilities2.getAndSetAntialisingHintForScaledGraphics;
 
 /**
  * Factory object that vends <code>Icon</code>s for
@@ -1247,9 +1249,15 @@
 
         protected void drawCheck(Component c, Graphics g, int x, int y) {
             int controlSize = getControlSize();
-            g.fillRect( x+3, y+5, 2, controlSize-8 );
-            g.drawLine( x+(controlSize-4), y+3, x+5, y+(controlSize-6) );
-            g.drawLine( x+(controlSize-4), y+4, x+5, y+(controlSize-5) );
+            int csx = controlSize - 3;
+            int csy1 = controlSize - 6;
+            int csy2 = controlSize - 4;
+            int csy3 = controlSize - 3;
+            int[] xPoints = {3, 5, 5, csx, csx, 5, 5, 3};
+            int[] yPoints = {5, 5, csy1, 2, 4, csy2, csy3, csy3};
+            g.translate(x, y);
+            g.fillPolygon(xPoints, yPoints, 8);
+            g.translate(-x, -y);
         }
 
         public int getIconWidth() {
@@ -1323,8 +1331,12 @@
         }
 
         public void paintIcon(Component c, Graphics g, int x, int y) {
+
+            Object aaHint = getAndSetAntialisingHintForScaledGraphics(g);
+
             if (MetalLookAndFeel.usingOcean()) {
                 paintOceanIcon(c, g, x, y);
+                setAntialiasingHintForScaledGraphics(g, aaHint);
                 return;
             }
             JRadioButton rb = (JRadioButton)c;
@@ -1358,51 +1370,25 @@
 
             // draw Dark Circle (start at top, go clockwise)
             g.setColor(darkCircle);
-            g.drawLine( 4, 0,  7, 0);
-            g.drawLine( 8, 1,  9, 1);
-            g.drawLine(10, 2, 10, 3);
-            g.drawLine(11, 4, 11, 7);
-            g.drawLine(10, 8, 10, 9);
-            g.drawLine( 9,10,  8,10);
-            g.drawLine( 7,11,  4,11);
-            g.drawLine( 3,10,  2,10);
-            g.drawLine( 1, 9,  1, 8);
-            g.drawLine( 0, 7,  0, 4);
-            g.drawLine( 1, 3,  1, 2);
-            g.drawLine( 2, 1,  3, 1);
+            g.drawOval(0, 0, 11, 11);
 
             // draw Inner Left (usually) White Arc
             //  start at lower left corner, go clockwise
             g.setColor(whiteInnerLeftArc);
-            g.drawLine( 2, 9,  2, 8);
-            g.drawLine( 1, 7,  1, 4);
-            g.drawLine( 2, 2,  2, 3);
-            g.drawLine( 2, 2,  3, 2);
-            g.drawLine( 4, 1,  7, 1);
-            g.drawLine( 8, 2,  9, 2);
+            g.drawArc(1, 1, 10, 10, 60, 160);
             // draw Outer Right White Arc
             //  start at upper right corner, go clockwise
             g.setColor(whiteOuterRightArc);
-            g.drawLine(10, 1, 10, 1);
-            g.drawLine(11, 2, 11, 3);
-            g.drawLine(12, 4, 12, 7);
-            g.drawLine(11, 8, 11, 9);
-            g.drawLine(10,10, 10,10);
-            g.drawLine( 9,11,  8,11);
-            g.drawLine( 7,12,  4,12);
-            g.drawLine( 3,11,  2,11);
+            g.drawArc(-1, -1, 13, 13, 235, 180);
 
             // selected dot
             if ( drawDot ) {
                 g.setColor(dotColor);
-                g.fillRect( 4, 4,  4, 4);
-                g.drawLine( 4, 3,  7, 3);
-                g.drawLine( 8, 4,  8, 7);
-                g.drawLine( 7, 8,  4, 8);
-                g.drawLine( 3, 7,  3, 4);
+                g.fillOval(2, 2, 7, 7);
             }
 
             g.translate(-x, -y);
+            setAntialiasingHintForScaledGraphics(g, aaHint);
         }
 
         public int getIconWidth() {
@@ -2051,16 +2037,17 @@
                     g.setColor( b.getForeground() );
                 }
             }
-            if( MetalUtils.isLeftToRight(b) ) {
-                g.drawLine( 0, 0, 0, 7 );
-                g.drawLine( 1, 1, 1, 6 );
-                g.drawLine( 2, 2, 2, 5 );
-                g.drawLine( 3, 3, 3, 4 );
+            if (MetalUtils.isLeftToRight(b)) {
+                int[] xPoints = {0, 3, 3, 0};
+                int[] yPoints = {0, 3, 4, 7};
+                g.fillPolygon(xPoints, yPoints, 4);
+                g.drawPolygon(xPoints, yPoints, 4);
+
             } else {
-                g.drawLine( 4, 0, 4, 7 );
-                g.drawLine( 3, 1, 3, 6 );
-                g.drawLine( 2, 2, 2, 5 );
-                g.drawLine( 1, 3, 1, 4 );
+                int[] xPoints = {4, 4, 1, 1};
+                int[] yPoints = {0, 7, 4, 3};
+                g.fillPolygon(xPoints, yPoints, 4);
+                g.drawPolygon(xPoints, yPoints, 4);
             }
 
             g.translate( -x, -y );
@@ -2138,10 +2125,7 @@
                     g.setColor( MetalLookAndFeel.getMenuDisabledForeground());
                 }
 
-                g.drawLine( 2, 2, 2, 6 );
-                g.drawLine( 3, 2, 3, 6 );
-                g.drawLine( 4, 4, 8, 0 );
-                g.drawLine( 4, 5, 9, 0 );
+                drawCheck(g);
             }
             g.translate( -x, -y );
         }
@@ -2217,15 +2201,18 @@
                     g.setColor( MetalLookAndFeel.getMenuDisabledForeground()  );
                 }
 
-                g.drawLine( 2, 2, 2, 6 );
-                g.drawLine( 3, 2, 3, 6 );
-                g.drawLine( 4, 4, 8, 0 );
-                g.drawLine( 4, 5, 9, 0 );
+                drawCheck(g);
             }
 
             g.translate( -x, -y );
         }
 
+        private void drawCheck(Graphics g) {
+            int[] xPoints = {2, 3, 3, 8, 9, 3, 2};
+            int[] yPoints = {2, 2, 5, 0, 0, 6, 6};
+            g.drawPolygon(xPoints, yPoints, 7);
+        }
+
         public int getIconWidth() { return menuCheckIconSize.width; }
 
         public int getIconHeight() { return menuCheckIconSize.height; }
@@ -2252,9 +2239,8 @@
                 else {
                     g.setColor(MetalLookAndFeel.getControlHighlight());
                 }
-                g.drawLine( 2, 9, 7, 9 );
-                g.drawLine( 9, 2, 9, 7 );
-                g.drawLine( 8, 8, 8, 8 );
+
+                g.drawArc(-1, -1, 10, 10, 245, 140);
 
                 if (isPressed || isArmed) {
                     g.setColor(MetalLookAndFeel.getControlInfo());
@@ -2266,14 +2252,8 @@
             else {
                 g.setColor( MetalLookAndFeel.getMenuDisabledForeground()  );
             }
-            g.drawLine( 2, 0, 6, 0 );
-            g.drawLine( 2, 8, 6, 8 );
-            g.drawLine( 0, 2, 0, 6 );
-            g.drawLine( 8, 2, 8, 6 );
-            g.drawLine( 1, 1, 1, 1 );
-            g.drawLine( 7, 1, 7, 1 );
-            g.drawLine( 1, 7, 1, 7 );
-            g.drawLine( 7, 7, 7, 7 );
+
+            g.drawOval(0, 0, 8, 8);
 
             if (isSelected) {
                 if (isEnabled) {
@@ -2288,11 +2268,9 @@
                 else {
                     g.setColor(MetalLookAndFeel.getMenuDisabledForeground());
                 }
-                g.drawLine( 3, 2, 5, 2 );
-                g.drawLine( 2, 3, 6, 3 );
-                g.drawLine( 2, 4, 6, 4 );
-                g.drawLine( 2, 5, 6, 5 );
-                g.drawLine( 3, 6, 5, 6 );
+
+                g.fillOval(2, 2, 4, 4);
+                g.drawOval(2, 2, 4, 4);
             }
 
             g.translate( -x, -y );
@@ -2300,8 +2278,12 @@
 
         public void paintIcon( Component c, Graphics g, int x, int y )
         {
+
+            Object aaHint = getAndSetAntialisingHintForScaledGraphics(g);
+
             if (MetalLookAndFeel.usingOcean()) {
                 paintOceanIcon(c, g, x, y);
+                setAntialiasingHintForScaledGraphics(g, aaHint);
                 return;
             }
             JMenuItem b = (JMenuItem) c;
@@ -2319,55 +2301,24 @@
                 if ( isPressed || isArmed )
                 {
                     g.setColor( MetalLookAndFeel.getPrimaryControl()  );
-                    g.drawLine( 3, 1, 8, 1 );
-                    g.drawLine( 2, 9, 7, 9 );
-                    g.drawLine( 1, 3, 1, 8 );
-                    g.drawLine( 9, 2, 9, 7 );
-                    g.drawLine( 2, 2, 2, 2 );
-                    g.drawLine( 8, 8, 8, 8 );
+                    g.drawOval(1, 1, 8, 8);
 
                     g.setColor( MetalLookAndFeel.getControlInfo()  );
-                    g.drawLine( 2, 0, 6, 0 );
-                    g.drawLine( 2, 8, 6, 8 );
-                    g.drawLine( 0, 2, 0, 6 );
-                    g.drawLine( 8, 2, 8, 6 );
-                    g.drawLine( 1, 1, 1, 1 );
-                    g.drawLine( 7, 1, 7, 1 );
-                    g.drawLine( 1, 7, 1, 7 );
-                    g.drawLine( 7, 7, 7, 7 );
+                    g.drawOval(0, 0, 8, 8);
                 }
                 else
                 {
                     g.setColor( MetalLookAndFeel.getControlHighlight()  );
-                    g.drawLine( 3, 1, 8, 1 );
-                    g.drawLine( 2, 9, 7, 9 );
-                    g.drawLine( 1, 3, 1, 8 );
-                    g.drawLine( 9, 2, 9, 7 );
-                    g.drawLine( 2, 2, 2, 2 );
-                    g.drawLine( 8, 8, 8, 8 );
+                    g.drawOval(1, 1, 8, 8);
 
                     g.setColor( MetalLookAndFeel.getControlDarkShadow()  );
-                    g.drawLine( 2, 0, 6, 0 );
-                    g.drawLine( 2, 8, 6, 8 );
-                    g.drawLine( 0, 2, 0, 6 );
-                    g.drawLine( 8, 2, 8, 6 );
-                    g.drawLine( 1, 1, 1, 1 );
-                    g.drawLine( 7, 1, 7, 1 );
-                    g.drawLine( 1, 7, 1, 7 );
-                    g.drawLine( 7, 7, 7, 7 );
+                    g.drawOval(0, 0, 8, 8);
                 }
             }
             else
             {
                 g.setColor( MetalLookAndFeel.getMenuDisabledForeground()  );
-                g.drawLine( 2, 0, 6, 0 );
-                g.drawLine( 2, 8, 6, 8 );
-                g.drawLine( 0, 2, 0, 6 );
-                g.drawLine( 8, 2, 8, 6 );
-                g.drawLine( 1, 1, 1, 1 );
-                g.drawLine( 7, 1, 7, 1 );
-                g.drawLine( 1, 7, 1, 7 );
-                g.drawLine( 7, 7, 7, 7 );
+                g.drawOval(0, 0, 8, 8);
             }
 
             if ( isSelected )
@@ -2388,14 +2339,12 @@
                     g.setColor( MetalLookAndFeel.getMenuDisabledForeground()  );
                 }
 
-                g.drawLine( 3, 2, 5, 2 );
-                g.drawLine( 2, 3, 6, 3 );
-                g.drawLine( 2, 4, 6, 4 );
-                g.drawLine( 2, 5, 6, 5 );
-                g.drawLine( 3, 6, 5, 6 );
+                g.fillOval(2, 2, 4, 4);
+                g.drawOval(2, 2, 4, 4);
             }
 
             g.translate( -x, -y );
+            setAntialiasingHintForScaledGraphics(g, aaHint);
         }
 
         public int getIconWidth() { return menuCheckIconSize.width; }
--- a/src/java.desktop/share/classes/javax/swing/text/DefaultStyledDocument.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/share/classes/javax/swing/text/DefaultStyledDocument.java	Thu Mar 23 22:57:12 2017 +0000
@@ -39,6 +39,7 @@
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.Serializable;
+import java.util.Arrays;
 import javax.swing.event.*;
 import javax.swing.undo.AbstractUndoableEdit;
 import javax.swing.undo.CannotRedoException;
@@ -1263,7 +1264,7 @@
                                   int offs, int len) {
             attr = a;
             this.type = type;
-            this.data = txt;
+            this.data = txt == null ? null : Arrays.copyOf(txt, txt.length);
             this.offs = offs;
             this.len = len;
             this.direction = OriginateDirection;
@@ -1323,7 +1324,7 @@
          * @return the array
          */
         public char[] getArray() {
-            return data;
+            return data == null ? null : Arrays.copyOf(data, data.length);
         }
 
 
--- a/src/java.desktop/share/classes/javax/swing/text/StyleContext.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/share/classes/javax/swing/text/StyleContext.java	Thu Mar 23 22:57:12 2017 +0000
@@ -794,7 +794,7 @@
          * @param attributes the attributes
          */
         public SmallAttributeSet(Object[] attributes) {
-            this.attributes = attributes;
+            this.attributes = Arrays.copyOf(attributes, attributes.length);
             updateResolveParent();
         }
 
--- a/src/java.desktop/share/classes/sun/awt/CustomCursor.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/share/classes/sun/awt/CustomCursor.java	Thu Mar 23 22:57:12 2017 +0000
@@ -66,7 +66,8 @@
 
         // Scale image to nearest supported size.
         Dimension nativeSize = toolkit.getBestCursorSize(width, height);
-        if (nativeSize.width != width || nativeSize.height != height) {
+        if ((nativeSize.width != width || nativeSize.height != height) &&
+            (nativeSize.width != 0 && nativeSize.height != 0)) {
             cursor = cursor.getScaledInstance(nativeSize.width,
                                               nativeSize.height,
                                               Image.SCALE_DEFAULT);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.desktop/share/classes/sun/print/DialogOnTop.java	Thu Mar 23 22:57:12 2017 +0000
@@ -0,0 +1,64 @@
+/*
+ * 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 sun.print;
+
+import javax.print.attribute.Attribute;
+import javax.print.attribute.PrintRequestAttribute;
+
+/*
+ * An implementation class used to request the dialog be set always-on-top.
+ * It needs to be read and honoured by the dialog code which will use
+ * java.awt.Window.setAlwaysOnTop(true) in cases where it is supported.
+ */
+public class DialogOnTop implements PrintRequestAttribute {
+
+    private static final long serialVersionUID = -1901909867156076547L;
+
+    long id;
+
+    public DialogOnTop() {
+    }
+
+    public DialogOnTop(long id) {
+        this.id = id;
+    }
+
+    public final Class<? extends Attribute> getCategory() {
+        return DialogOnTop.class;
+    }
+
+    public long getID() {
+        return id;
+    }
+
+    public final String getName() {
+        return "dialog-on-top";
+    }
+
+    public String toString() {
+       return "dialog-on-top";
+    }
+}
--- a/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java	Thu Mar 23 22:57:12 2017 +0000
@@ -785,7 +785,9 @@
             PrintService pservice = getPrintService();
             PageFormat pageFrmAttrib = attributeToPageFormat(pservice,
                                                              attributes);
+            setParentWindowID(attributes);
             PageFormat page = pageDialog(pageFrmAttrib);
+            clearParentWindowID();
 
             // If user cancels the dialog, pageDialog() will return the original
             // page object and as per spec, we should return null in that case.
@@ -828,6 +830,9 @@
         int x = gcBounds.x+50;
         int y = gcBounds.y+50;
         ServiceDialog pageDialog;
+        if (onTop != null) {
+            attributes.add(onTop);
+        }
         if (w instanceof Frame) {
             pageDialog = new ServiceDialog(gc, x, y, service,
                                            DocFlavor.SERVICE_FORMATTED.PAGEABLE,
@@ -837,6 +842,7 @@
                                            DocFlavor.SERVICE_FORMATTED.PAGEABLE,
                                            attributes, (Dialog)w);
         }
+
         Rectangle dlgBounds = pageDialog.getBounds();
 
         // if portion of dialog is not within the gc boundary
@@ -923,7 +929,9 @@
 
             }
 
+            setParentWindowID(attributes);
             boolean ret = printDialog();
+            clearParentWindowID();
             this.attributes = attributes;
             return ret;
 
@@ -2539,4 +2547,26 @@
             return new String(out_chars, 0, pos);
         }
     }
+
+    private DialogOnTop onTop = null;
+
+    private long parentWindowID = 0L;
+
+    /* Called from native code */
+    private long getParentWindowID() {
+        return parentWindowID;
+    }
+
+    private void clearParentWindowID() {
+        parentWindowID = 0L;
+        onTop = null;
+    }
+
+    private void setParentWindowID(PrintRequestAttributeSet attrs) {
+        parentWindowID = 0L;
+        onTop = (DialogOnTop)attrs.get(DialogOnTop.class);
+        if (onTop != null) {
+            parentWindowID = onTop.getID();
+        }
+    }
 }
--- a/src/java.desktop/share/classes/sun/print/ServiceDialog.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/share/classes/sun/print/ServiceDialog.java	Thu Mar 23 22:57:12 2017 +0000
@@ -184,6 +184,9 @@
             isAWT = true;
         }
 
+        if (attributes.get(DialogOnTop.class) != null) {
+            setAlwaysOnTop(true);
+        }
         Container c = getContentPane();
         c.setLayout(new BorderLayout());
 
@@ -275,6 +278,10 @@
         this.asOriginal = attributes;
         this.asCurrent = new HashPrintRequestAttributeSet(attributes);
 
+        if (attributes.get(DialogOnTop.class) != null) {
+            setAlwaysOnTop(true);
+        }
+
         Container c = getContentPane();
         c.setLayout(new BorderLayout());
 
--- a/src/java.desktop/share/classes/sun/swing/SwingUtilities2.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/share/classes/sun/swing/SwingUtilities2.java	Thu Mar 23 22:57:12 2017 +0000
@@ -2164,6 +2164,41 @@
         return false;
     }
 
+    /**
+     * Enables the antialiasing rendering hint for the scaled graphics and
+     * returns the previous hint value.
+     * The returned null value indicates that the passed graphics is not
+     * instance of Graphics2D.
+     *
+     * @param g the graphics
+     * @return the previous antialiasing rendering hint value if the passed
+     * graphics is instance of Graphics2D, null otherwise.
+     */
+    public static Object getAndSetAntialisingHintForScaledGraphics(Graphics g) {
+        if (isScaledGraphics(g) && isLocalDisplay()) {
+            Graphics2D g2d = (Graphics2D) g;
+            Object hint = g2d.getRenderingHint(RenderingHints.KEY_ANTIALIASING);
+            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+                    RenderingHints.VALUE_ANTIALIAS_ON);
+            return hint;
+        }
+        return null;
+    }
+
+    /**
+     * Sets the antialiasing rendering hint if its value is not null.
+     * Null hint value indicates that the passed graphics is not instance of
+     * Graphics2D.
+     *
+     * @param g the graphics
+     * @param hint the antialiasing rendering hint
+     */
+    public static void setAntialiasingHintForScaledGraphics(Graphics g, Object hint) {
+        if (hint != null) {
+            ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, hint);
+        }
+    }
+
     public static boolean isFloatingPointScale(AffineTransform tx) {
         int type = tx.getType() & ~(TYPE_FLIP | TYPE_TRANSLATION);
         if (type == 0) {
--- a/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java	Thu Mar 23 22:57:12 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
@@ -25,17 +25,34 @@
 
 package sun.awt.X11;
 
-import java.awt.*;
-import java.awt.event.*;
-import java.awt.peer.TrayIconPeer;
-import sun.awt.*;
-
-import java.awt.image.*;
+import java.awt.BorderLayout;
+import java.awt.Button;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Frame;
+import java.awt.GridLayout;
+import java.awt.Image;
+import java.awt.Insets;
+import java.awt.Label;
+import java.awt.MouseInfo;
+import java.awt.Panel;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.Toolkit;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.text.BreakIterator;
 import java.util.concurrent.ArrayBlockingQueue;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.lang.reflect.InvocationTargetException;
+
+import sun.awt.SunToolkit;
 
 /**
  * An utility window class. This is a base class for Tooltip and Balloon.
@@ -81,16 +98,16 @@
         Dimension size = getSize();
         Rectangle scrSize = getGraphicsConfiguration().getBounds();
 
-        if (corner.x < scrSize.width/2 && corner.y < scrSize.height/2) { // 1st square
+        if (corner.x < scrSize.x + scrSize.width/2 && corner.y < scrSize.y + scrSize.height/2) { // 1st square
             setLocation(corner.x + indent, corner.y + indent);
 
-        } else if (corner.x >= scrSize.width/2 && corner.y < scrSize.height/2) { // 2nd square
+        } else if (corner.x >= scrSize.x + scrSize.width/2 && corner.y < scrSize.y + scrSize.height/2) { // 2nd square
             setLocation(corner.x - indent - size.width, corner.y + indent);
 
-        } else if (corner.x < scrSize.width/2 && corner.y >= scrSize.height/2) { // 3rd square
+        } else if (corner.x < scrSize.x + scrSize.width/2 && corner.y >= scrSize.y + scrSize.height/2) { // 3rd square
             setLocation(corner.x + indent, corner.y - indent - size.height);
 
-        } else if (corner.x >= scrSize.width/2 && corner.y >= scrSize.height/2) { // 4th square
+        } else if (corner.x >= scrSize.x +scrSize.width/2 && corner.y >= scrSize.y +scrSize.height/2) { // 4th square
             setLocation(corner.x - indent - size.width, corner.y - indent - size.height);
         }
 
--- a/src/java.desktop/unix/classes/sun/awt/X11/XBaseMenuWindow.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XBaseMenuWindow.java	Thu Mar 23 22:57:12 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,17 +25,15 @@
 package sun.awt.X11;
 
 import java.awt.*;
-import java.awt.peer.*;
 import java.awt.event.*;
-import java.awt.image.ColorModel;
 
 import sun.awt.*;
 
+import java.awt.peer.ComponentPeer;
 import java.util.ArrayList;
 import java.util.Vector;
 import sun.util.logging.PlatformLogger;
 import sun.java2d.SurfaceData;
-import sun.java2d.SunGraphics2D;
 
 /**
  * The abstract class XBaseMenuWindow is the superclass
@@ -656,28 +654,37 @@
      *
      ************************************************/
 
+    GraphicsConfiguration getCurrentGraphicsConfiguration() {
+        Component hw = SunToolkit.getHeavyweightComponent(target);
+        XWindow peer = AWTAccessor.getComponentAccessor().getPeer(hw);
+        if (peer != null && peer.graphicsConfig != null) {
+            return peer.graphicsConfig;
+        }
+        return graphicsConfig;
+    }
+
     /**
      * Checks if window fits below specified item
      * returns rectangle that the window fits to or null.
      * @param itemBounds rectangle of item in global coordinates
      * @param windowSize size of submenu window to fit
-     * @param screenSize size of screen
+     * @param screenBounds size of screen
      */
-    Rectangle fitWindowBelow(Rectangle itemBounds, Dimension windowSize, Dimension screenSize) {
+    Rectangle fitWindowBelow(Rectangle itemBounds, Dimension windowSize, Rectangle screenBounds) {
         int width = windowSize.width;
         int height = windowSize.height;
         //Fix for 6267162: PIT: Popup Menu gets hidden below the screen when opened
         //near the periphery of the screen, XToolkit
         //Window should be moved if it's outside top-left screen bounds
-        int x = (itemBounds.x > 0) ? itemBounds.x : 0;
-        int y = (itemBounds.y + itemBounds.height > 0) ? itemBounds.y + itemBounds.height : 0;
-        if (y + height <= screenSize.height) {
+        int x = (itemBounds.x > screenBounds.x) ? itemBounds.x : screenBounds.x;
+        int y = (itemBounds.y + itemBounds.height > screenBounds.y) ? itemBounds.y + itemBounds.height : screenBounds.y;
+        if (y + height <= screenBounds.y + screenBounds.height) {
             //move it to the left if needed
-            if (width > screenSize.width) {
-                width = screenSize.width;
+            if (width > screenBounds.width) {
+                width = screenBounds.width;
             }
-            if (x + width > screenSize.width) {
-                x = screenSize.width - width;
+            if (x + width > screenBounds.x + screenBounds.width) {
+                x = screenBounds.x + screenBounds.width - width;
             }
             return new Rectangle(x, y, width, height);
         } else {
@@ -690,23 +697,23 @@
      * returns rectangle that the window fits to or null.
      * @param itemBounds rectangle of item in global coordinates
      * @param windowSize size of submenu window to fit
-     * @param screenSize size of screen
+     * @param screenBounds size of screen
      */
-    Rectangle fitWindowAbove(Rectangle itemBounds, Dimension windowSize, Dimension screenSize) {
+    Rectangle fitWindowAbove(Rectangle itemBounds, Dimension windowSize, Rectangle screenBounds) {
         int width = windowSize.width;
         int height = windowSize.height;
         //Fix for 6267162: PIT: Popup Menu gets hidden below the screen when opened
         //near the periphery of the screen, XToolkit
         //Window should be moved if it's outside bottom-left screen bounds
-        int x = (itemBounds.x > 0) ? itemBounds.x : 0;
-        int y = (itemBounds.y > screenSize.height) ? screenSize.height - height : itemBounds.y - height;
-        if (y >= 0) {
+        int x = (itemBounds.x > screenBounds.x) ? itemBounds.x : screenBounds.x;
+        int y = (itemBounds.y > screenBounds.y + screenBounds.height) ? screenBounds.y + screenBounds.height - height : itemBounds.y - height;
+        if (y >= screenBounds.y) {
             //move it to the left if needed
-            if (width > screenSize.width) {
-                width = screenSize.width;
+            if (width > screenBounds.width) {
+                width = screenBounds.width;
             }
-            if (x + width > screenSize.width) {
-                x = screenSize.width - width;
+            if (x + width > screenBounds.x + screenBounds.width) {
+                x = screenBounds.x + screenBounds.width - width;
             }
             return new Rectangle(x, y, width, height);
         } else {
@@ -719,23 +726,23 @@
      * returns rectangle that the window fits to or null.
      * @param itemBounds rectangle of item in global coordinates
      * @param windowSize size of submenu window to fit
-     * @param screenSize size of screen
+     * @param screenBounds size of screen
      */
-    Rectangle fitWindowRight(Rectangle itemBounds, Dimension windowSize, Dimension screenSize) {
+    Rectangle fitWindowRight(Rectangle itemBounds, Dimension windowSize, Rectangle screenBounds) {
         int width = windowSize.width;
         int height = windowSize.height;
         //Fix for 6267162: PIT: Popup Menu gets hidden below the screen when opened
         //near the periphery of the screen, XToolkit
         //Window should be moved if it's outside top-left screen bounds
-        int x = (itemBounds.x + itemBounds.width > 0) ? itemBounds.x + itemBounds.width : 0;
-        int y = (itemBounds.y > 0) ? itemBounds.y : 0;
-        if (x + width <= screenSize.width) {
+        int x = (itemBounds.x + itemBounds.width > screenBounds.x) ? itemBounds.x + itemBounds.width : screenBounds.x;
+        int y = (itemBounds.y > screenBounds.y) ? itemBounds.y : screenBounds.y;
+        if (x + width <= screenBounds.x + screenBounds.width) {
             //move it to the top if needed
-            if (height > screenSize.height) {
-                height = screenSize.height;
+            if (height > screenBounds.height) {
+                height = screenBounds.height;
             }
-            if (y + height > screenSize.height) {
-                y = screenSize.height - height;
+            if (y + height > screenBounds.y + screenBounds.height) {
+                y = screenBounds.y + screenBounds.height - height;
             }
             return new Rectangle(x, y, width, height);
         } else {
@@ -748,23 +755,23 @@
      * returns rectangle that the window fits to or null.
      * @param itemBounds rectangle of item in global coordinates
      * @param windowSize size of submenu window to fit
-     * @param screenSize size of screen
+     * @param screenBounds size of screen
      */
-    Rectangle fitWindowLeft(Rectangle itemBounds, Dimension windowSize, Dimension screenSize) {
+    Rectangle fitWindowLeft(Rectangle itemBounds, Dimension windowSize, Rectangle screenBounds) {
         int width = windowSize.width;
         int height = windowSize.height;
         //Fix for 6267162: PIT: Popup Menu gets hidden below the screen when opened
         //near the periphery of the screen, XToolkit
         //Window should be moved if it's outside top-right screen bounds
-        int x = (itemBounds.x < screenSize.width) ? itemBounds.x - width : screenSize.width - width;
-        int y = (itemBounds.y > 0) ? itemBounds.y : 0;
-        if (x >= 0) {
+        int x = (itemBounds.x < screenBounds.x + screenBounds.width) ? itemBounds.x - width : screenBounds.x + screenBounds.width - width;
+        int y = (itemBounds.y > screenBounds.y) ? itemBounds.y : screenBounds.y;
+        if (x >= screenBounds.x) {
             //move it to the top if needed
-            if (height > screenSize.height) {
-                height = screenSize.height;
+            if (height > screenBounds.height) {
+                height = screenBounds.height;
             }
-            if (y + height > screenSize.height) {
-                y = screenSize.height - height;
+            if (y + height > screenBounds.y + screenBounds.height) {
+                y = screenBounds.y + screenBounds.height - height;
             }
             return new Rectangle(x, y, width, height);
         } else {
@@ -777,12 +784,12 @@
      * to fit it on screen - move it to the
      * top-left edge and cut by screen dimensions
      * @param windowSize size of submenu window to fit
-     * @param screenSize size of screen
+     * @param screenBounds size of screen
      */
-    Rectangle fitWindowToScreen(Dimension windowSize, Dimension screenSize) {
-        int width = (windowSize.width < screenSize.width) ? windowSize.width : screenSize.width;
-        int height = (windowSize.height < screenSize.height) ? windowSize.height : screenSize.height;
-        return new Rectangle(0, 0, width, height);
+    Rectangle fitWindowToScreen(Dimension windowSize, Rectangle screenBounds) {
+        int width = (windowSize.width < screenBounds.width) ? windowSize.width : screenBounds.width;
+        int height = (windowSize.height < screenBounds.height) ? windowSize.height : screenBounds.height;
+        return new Rectangle(screenBounds.x, screenBounds.y, width, height);
     }
 
 
--- a/src/java.desktop/unix/classes/sun/awt/X11/XChoicePeer.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XChoicePeer.java	Thu Mar 23 22:57:12 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -42,7 +42,7 @@
 
 // TODO: make painting more efficient (i.e. when down arrow is pressed, only two items should need to be repainted.
 
-public class XChoicePeer extends XComponentPeer implements ChoicePeer, ToplevelStateListener {
+public final class XChoicePeer extends XComponentPeer implements ChoicePeer, ToplevelStateListener {
     private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XChoicePeer");
 
     private static final int MAX_UNFURLED_ITEMS = 10;  // Maximum number of
@@ -741,6 +741,16 @@
         }
     }
 
+    @Override
+    protected void initGraphicsConfiguration() {
+        super.initGraphicsConfiguration();
+        // The popup have the same graphic config, so update it at the same time
+        if (unfurledChoice != null) {
+            unfurledChoice.initGraphicsConfiguration();
+            unfurledChoice.doValidateSurface();
+        }
+    }
+
     /**************************************************************************/
     /* Common functionality between List & Choice
        /**************************************************************************/
@@ -749,7 +759,7 @@
      * Inner class for the unfurled Choice list
      * Much, much more docs
      */
-    class UnfurledChoice extends XWindow /*implements XScrollbarClient*/ {
+    final class UnfurledChoice extends XWindow /*implements XScrollbarClient*/ {
 
         // First try - use Choice as the target
 
@@ -785,7 +795,7 @@
                 numItemsDisplayed = Math.min(MAX_UNFURLED_ITEMS, numItems);
             }
             Point global = XChoicePeer.this.toGlobal(0,0);
-            Rectangle screen = graphicsConfig.getBounds();
+            Rectangle screenBounds = graphicsConfig.getBounds();
 
             if (alignUnder != null) {
                 Rectangle choiceRec = XChoicePeer.this.getBounds();
@@ -807,19 +817,19 @@
                 height = 2*BORDER_WIDTH +
                     numItemsDisplayed*(helper.getItemHeight()+2*ITEM_MARGIN);
             }
-            // Don't run off the edge of the screen
-            if (x < 0) {
-                x = 0;
+            // Don't run off the edge of the screenBounds
+            if (x < screenBounds.x) {
+                x = screenBounds.x;
             }
-            else if (x + width > screen.width) {
-                x = screen.width - width;
+            else if (x + width > screenBounds.x + screenBounds.width) {
+                x = screenBounds.x + screenBounds.width - width;
             }
 
-            if (y + height > screen.height) {
+            if (y + height > screenBounds.y + screenBounds.height) {
                 y = global.y - height;
             }
-            if (y < 0) {
-                y = 0;
+            if (y < screenBounds.y) {
+                y = screenBounds.y;
             }
             return new Rectangle(x, y, width, height);
         }
--- a/src/java.desktop/unix/classes/sun/awt/X11/XMenuBarPeer.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XMenuBarPeer.java	Thu Mar 23 22:57:12 2017 +0000
@@ -298,25 +298,25 @@
      */
     protected Rectangle getSubmenuBounds(Rectangle itemBounds, Dimension windowSize) {
         Rectangle globalBounds = toGlobal(itemBounds);
-        Dimension screenSize = graphicsConfig.getBounds().getSize();
+        Rectangle screenBounds = getCurrentGraphicsConfiguration().getBounds();
         Rectangle res;
-        res = fitWindowBelow(globalBounds, windowSize, screenSize);
+        res = fitWindowBelow(globalBounds, windowSize, screenBounds);
         if (res != null) {
             return res;
         }
-        res = fitWindowAbove(globalBounds, windowSize, screenSize);
+        res = fitWindowAbove(globalBounds, windowSize, screenBounds);
         if (res != null) {
             return res;
         }
-        res = fitWindowRight(globalBounds, windowSize, screenSize);
+        res = fitWindowRight(globalBounds, windowSize, screenBounds);
         if (res != null) {
             return res;
         }
-        res = fitWindowLeft(globalBounds, windowSize, screenSize);
+        res = fitWindowLeft(globalBounds, windowSize, screenBounds);
         if (res != null) {
             return res;
         }
-        return fitWindowToScreen(windowSize, screenSize);
+        return fitWindowToScreen(windowSize, screenBounds);
     }
 
     /**
--- a/src/java.desktop/unix/classes/sun/awt/X11/XMenuWindow.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XMenuWindow.java	Thu Mar 23 22:57:12 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -278,25 +278,25 @@
      */
     protected Rectangle getSubmenuBounds(Rectangle itemBounds, Dimension windowSize) {
         Rectangle globalBounds = toGlobal(itemBounds);
-        Dimension screenSize = graphicsConfig.getBounds().getSize();
+        Rectangle screenBounds = getCurrentGraphicsConfiguration().getBounds();
         Rectangle res;
-        res = fitWindowRight(globalBounds, windowSize, screenSize);
+        res = fitWindowRight(globalBounds, windowSize, screenBounds);
         if (res != null) {
             return res;
         }
-        res = fitWindowBelow(globalBounds, windowSize, screenSize);
+        res = fitWindowBelow(globalBounds, windowSize, screenBounds);
         if (res != null) {
             return res;
         }
-        res = fitWindowAbove(globalBounds, windowSize, screenSize);
+        res = fitWindowAbove(globalBounds, windowSize, screenBounds);
         if (res != null) {
             return res;
         }
-        res = fitWindowLeft(globalBounds, windowSize, screenSize);
+        res = fitWindowLeft(globalBounds, windowSize, screenBounds);
         if (res != null) {
             return res;
         }
-        return fitWindowToScreen(windowSize, screenSize);
+        return fitWindowToScreen(windowSize, screenBounds);
    }
 
     /**
--- a/src/java.desktop/unix/classes/sun/awt/X11/XPopupMenuPeer.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XPopupMenuPeer.java	Thu Mar 23 22:57:12 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -216,25 +216,25 @@
      */
     protected Rectangle getWindowBounds(Point origin, Dimension windowSize) {
         Rectangle globalBounds = new Rectangle(origin.x, origin.y, 0, 0);
-        Dimension screenSize = graphicsConfig.getBounds().getSize();
+        Rectangle screenBounds = getCurrentGraphicsConfiguration().getBounds();
         Rectangle res;
-        res = fitWindowRight(globalBounds, windowSize, screenSize);
+        res = fitWindowRight(globalBounds, windowSize, screenBounds);
         if (res != null) {
             return res;
         }
-        res = fitWindowLeft(globalBounds, windowSize, screenSize);
+        res = fitWindowLeft(globalBounds, windowSize, screenBounds);
         if (res != null) {
             return res;
         }
-        res = fitWindowBelow(globalBounds, windowSize, screenSize);
+        res = fitWindowBelow(globalBounds, windowSize, screenBounds);
         if (res != null) {
             return res;
         }
-        res = fitWindowAbove(globalBounds, windowSize, screenSize);
+        res = fitWindowAbove(globalBounds, windowSize, screenBounds);
         if (res != null) {
             return res;
         }
-        return fitWindowToScreen(windowSize, screenSize);
+        return fitWindowToScreen(windowSize, screenBounds);
    }
 
     /************************************************
--- a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DGraphicsConfig.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DGraphicsConfig.java	Thu Mar 23 22:57:12 2017 +0000
@@ -186,7 +186,17 @@
         SurfaceData sd = d3dvsm.getPrimarySurfaceData();
         if (sd instanceof D3DSurfaceData) {
             D3DSurfaceData d3dsd = (D3DSurfaceData)sd;
-            D3DSurfaceData.swapBuffers(d3dsd, x1, y1, x2, y2);
+            double scaleX = sd.getDefaultScaleX();
+            double scaleY = sd.getDefaultScaleY();
+            if (scaleX > 1 || scaleY > 1) {
+                int sx1 = (int) Math.floor(x1 * scaleX);
+                int sy1 = (int) Math.floor(y1 * scaleY);
+                int sx2 = (int) Math.ceil(x2 * scaleX);
+                int sy2 = (int) Math.ceil(y2 * scaleY);
+                D3DSurfaceData.swapBuffers(d3dsd, sx1, sy1, sx2, sy2);
+            } else {
+                D3DSurfaceData.swapBuffers(d3dsd, x1, y1, x2, y2);
+            }
         } else {
             // the surface was likely lost could not have been restored
             Graphics g = peer.getGraphics();
--- a/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceData.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceData.java	Thu Mar 23 22:57:12 2017 +0000
@@ -766,7 +766,17 @@
                 final Component target = (Component)sd.getPeer().getTarget();
                 SunToolkit.executeOnEventHandlerThread(target, new Runnable() {
                     public void run() {
-                        target.repaint(x1, y1, x2, y2);
+                        double scaleX = sd.getDefaultScaleX();
+                        double scaleY = sd.getDefaultScaleY();
+                        if (scaleX > 1 || scaleY > 1) {
+                            int sx1 = (int) Math.floor(x1 / scaleX);
+                            int sy1 = (int) Math.floor(y1 / scaleY);
+                            int sx2 = (int) Math.ceil(x2 / scaleX);
+                            int sy2 = (int) Math.ceil(y2 / scaleY);
+                            target.repaint(sx1, sy1, sx2 - sx1, sy2 - sy1);
+                        } else {
+                            target.repaint(x1, y1, x2 - x1, y2 - y1);
+                        }
                     }
                 });
                 return;
--- a/src/java.desktop/windows/native/libawt/windows/awt_PrintControl.cpp	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/windows/native/libawt/windows/awt_PrintControl.cpp	Thu Mar 23 22:57:12 2017 +0000
@@ -54,6 +54,7 @@
 jmethodID AwtPrintControl::setDevmodeID;
 jmethodID AwtPrintControl::getDevnamesID;
 jmethodID AwtPrintControl::setDevnamesID;
+jmethodID AwtPrintControl::getParentWindowID;
 jfieldID  AwtPrintControl::driverDoesMultipleCopiesID;
 jfieldID  AwtPrintControl::driverDoesCollationID;
 jmethodID AwtPrintControl::getWin32MediaID;
@@ -240,6 +241,11 @@
     DASSERT(AwtPrintControl::dialogOwnerPeerID != NULL);
     CHECK_NULL(AwtPrintControl::dialogOwnerPeerID);
 
+    AwtPrintControl::getParentWindowID = env->GetMethodID(cls,
+                                       "getParentWindowID", "()J");
+    DASSERT(AwtPrintControl::getParentWindowID != NULL);
+    CHECK_NULL(AwtPrintControl::getParentWindowID);
+
     AwtPrintControl::getPrintDCID = env->GetMethodID(cls, "getPrintDC", "()J");
     DASSERT(AwtPrintControl::getPrintDCID != NULL);
     CHECK_NULL(AwtPrintControl::getPrintDCID);
--- a/src/java.desktop/windows/native/libawt/windows/awt_PrintControl.h	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/windows/native/libawt/windows/awt_PrintControl.h	Thu Mar 23 22:57:12 2017 +0000
@@ -47,6 +47,7 @@
     static jmethodID setDevmodeID;
     static jmethodID getDevnamesID;
     static jmethodID setDevnamesID;
+    static jmethodID getParentWindowID;
     static jmethodID getWin32MediaID;
     static jmethodID setWin32MediaID;
     static jmethodID getWin32MediaTrayID;
@@ -97,6 +98,10 @@
                                  LPTSTR pPrinterName,
                                  LPDEVMODE *pDevMode);
 
+    inline static HWND getParentID(JNIEnv *env, jobject self) {
+      return (HWND)env->CallLongMethod(self, getParentWindowID);
+    }
+
     inline static  HDC getPrintDC(JNIEnv *env, jobject self) {
       return (HDC)env->CallLongMethod(self, getPrintDCID);
     }
--- a/src/java.desktop/windows/native/libawt/windows/awt_PrintDialog.cpp	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/windows/native/libawt/windows/awt_PrintDialog.cpp	Thu Mar 23 22:57:12 2017 +0000
@@ -248,6 +248,11 @@
       pd.lpfnPrintHook = (LPPRINTHOOKPROC)PrintDialogHookProc;
       pd.lpfnSetupHook = (LPSETUPHOOKPROC)PrintDialogHookProc;
       pd.Flags |= PD_ENABLESETUPHOOK | PD_ENABLEPRINTHOOK;
+      HWND parent = AwtPrintControl::getParentID(env, control);
+      if (parent != NULL && ::IsWindow(parent)) {
+          // Windows native modality is requested (used by JavaFX).
+          pd.hwndOwner = parent;
+      }
       /*
           Fix for 6488834.
           To disable Win32 native parent modality we have to set
@@ -255,7 +260,7 @@
           parentless dialogs we use NULL to show them in the taskbar,
           and for all other dialogs AwtToolkit's HWND is used.
       */
-      if (awtParent != NULL)
+      else if (awtParent != NULL)
       {
           pd.hwndOwner = AwtToolkit::GetInstance().GetHWnd();
       }
--- a/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp	Thu Mar 23 22:57:12 2017 +0000
@@ -521,12 +521,18 @@
     AwtComponent *awtParent = (parent != NULL) ? (AwtComponent *)JNI_GET_PDATA(parent) : NULL;
     HWND hwndOwner = awtParent ? awtParent->GetHWnd() : NULL;
 
+
     jboolean doIt = JNI_FALSE; // Assume the user will cancel the dialog.
     PAGESETUPDLG setup;
     memset(&setup, 0, sizeof(setup));
 
     setup.lStructSize = sizeof(setup);
 
+    HWND parentID = AwtPrintControl::getParentID(env, self);
+    if (parentID != NULL && ::IsWindow(parentID)) {
+        // windows native modality is requested (used by JavaFX).
+        setup.hwndOwner = parentID;
+    }
     /*
       Fix for 6488834.
       To disable Win32 native parent modality we have to set
@@ -534,7 +540,7 @@
       parentless dialogs we use NULL to show them in the taskbar,
       and for all other dialogs AwtToolkit's HWND is used.
     */
-    if (awtParent != NULL)
+    else if (awtParent != NULL)
     {
         setup.hwndOwner = AwtToolkit::GetInstance().GetHWnd();
     }
--- a/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/java.instrument/share/classes/java/lang/instrument/ClassFileTransformer.java	Thu Mar 23 22:57:12 2017 +0000
@@ -191,6 +191,9 @@
      *         if the input does not represent a well-formed class file
      * @return a well-formed class file buffer (the result of the transform),
      *         or {@code null} if no transform is performed
+     *
+     * @revised 9
+     * @spec JPMS
      */
     default byte[]
     transform(  ClassLoader         loader,
--- a/src/jdk.jartool/share/classes/sun/tools/jar/Main.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/jdk.jartool/share/classes/sun/tools/jar/Main.java	Thu Mar 23 22:57:12 2017 +0000
@@ -64,6 +64,7 @@
 import jdk.internal.module.ModuleInfo;
 import jdk.internal.module.ModuleInfoExtender;
 import jdk.internal.module.ModuleResolution;
+import jdk.internal.module.ModuleTarget;
 import jdk.internal.util.jar.JarIndex;
 
 import static jdk.internal.util.jar.JarIndex.INDEX_NAME;
@@ -1747,7 +1748,7 @@
                 }
                 ModuleDescriptor md = mref.iterator().next().descriptor();
                 output(getMsg("out.automodule"));
-                describeModule(md, null, "automatic");
+                describeModule(md, null, null, "automatic");
             } catch (FindException e) {
                 String msg = formatMsg("error.unable.derive.automodule", fn);
                 Throwable t = e.getCause();
@@ -1800,12 +1801,14 @@
     {
         ModuleInfo.Attributes attrs = ModuleInfo.read(entryInputStream, null);
         ModuleDescriptor md = attrs.descriptor();
+        ModuleTarget target = attrs.target();
         ModuleHashes hashes = attrs.recordedHashes();
 
-        describeModule(md, hashes, ename);
+        describeModule(md, target, hashes, ename);
     }
 
     private void describeModule(ModuleDescriptor md,
+                                ModuleTarget target,
                                 ModuleHashes hashes,
                                 String ename)
         throws IOException
@@ -1852,11 +1855,14 @@
 
         md.mainClass().ifPresent(v -> sb.append("\n  main-class " + v));
 
-        md.osName().ifPresent(v -> sb.append("\n  operating-system-name " + v));
-
-        md.osArch().ifPresent(v -> sb.append("\n  operating-system-architecture " + v));
-
-        md.osVersion().ifPresent(v -> sb.append("\n  operating-system-version " + v));
+        if (target != null) {
+            String osName = target.osName();
+            if (osName != null)
+                sb.append("\n  operating-system-name " + osName);
+            String osArch = target.osArch();
+            if (osArch != null)
+                sb.append("\n  operating-system-architecture " + osArch);
+       }
 
        if (hashes != null) {
            hashes.names().stream().sorted().forEach(
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java	Thu Mar 23 22:57:12 2017 +0000
@@ -151,16 +151,8 @@
     @Override
     public void storeFiles(ResourcePool files) {
         try {
-            // populate targetOsName field up-front because it's used elsewhere.
-            Optional<ResourcePoolModule> javaBase = files.moduleView().findModule("java.base");
-            javaBase.ifPresent(mod -> {
-                // fill release information available from transformed "java.base" module!
-                ModuleDescriptor desc = mod.descriptor();
-                desc.osName().ifPresent(s -> {
-                    this.targetOsName = s;
-                });
-            });
-
+            this.targetOsName = files.moduleView().
+                findModule("java.base").get().osName();
             if (this.targetOsName == null) {
                 throw new PluginException("ModuleTarget attribute is missing for java.base module");
             }
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java	Thu Mar 23 22:57:12 2017 +0000
@@ -43,6 +43,8 @@
 import java.util.stream.Stream;
 
 import jdk.internal.jimage.decompressor.Decompressor;
+import jdk.internal.module.ModuleInfo.Attributes;
+import jdk.internal.module.ModuleTarget;
 import jdk.tools.jlink.plugin.Plugin;
 import jdk.tools.jlink.builder.ImageBuilder;
 import jdk.tools.jlink.plugin.PluginException;
@@ -298,6 +300,7 @@
             final ResourcePoolModule module;
             // lazily initialized
             ModuleDescriptor descriptor;
+            ModuleTarget target;
 
             LastModule(ResourcePoolModule module) {
                 this.module = module;
@@ -316,10 +319,28 @@
 
             @Override
             public ModuleDescriptor descriptor() {
-                if (descriptor == null) {
-                    descriptor = ResourcePoolManager.readModuleDescriptor(this);
+                initModuleAttributes();
+                return descriptor;
+            }
+
+            @Override
+            public String osName() {
+                initModuleAttributes();
+                return target != null? target.osName() : null;
+            }
+
+            @Override
+            public String osArch() {
+                initModuleAttributes();
+                return target != null? target.osArch() : null;
+            }
+
+            private void initModuleAttributes() {
+                if (this.descriptor == null) {
+                    Attributes attr = ResourcePoolManager.readModuleAttributes(this);
+                    this.descriptor = attr.descriptor();
+                    this.target = attr.target();
                 }
-                return descriptor;
             }
 
             @Override
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java	Thu Mar 23 22:57:12 2017 +0000
@@ -54,7 +54,6 @@
 import jdk.tools.jlink.plugin.PluginException;
 import jdk.tools.jlink.builder.DefaultImageBuilder;
 import jdk.tools.jlink.plugin.Plugin;
-import jdk.internal.module.Checks;
 import jdk.internal.module.ModulePath;
 import jdk.internal.module.ModuleResolution;
 
@@ -423,13 +422,6 @@
                          ModuleFinder.of(),
                          roots);
 
-        // emit warning for modules that end with a digit
-        cf.modules().stream()
-            .map(ResolvedModule::name)
-            .filter(mn -> !Checks.hasLegalModuleNameLastCharacter(mn))
-            .forEach(mn -> System.err.println("WARNING: Module name \""
-                                              + mn + "\" may soon be illegal"));
-
         // emit a warning for any incubating modules in the configuration
         if (log != null) {
             String im = cf.modules()
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolConfiguration.java	Thu Mar 23 22:57:12 2017 +0000
@@ -66,9 +66,6 @@
 
         md.version().ifPresent(builder::version);
         md.mainClass().ifPresent(builder::mainClass);
-        md.osName().ifPresent(builder::osName);
-        md.osArch().ifPresent(builder::osArch);
-        md.osVersion().ifPresent(builder::osVersion);
 
         return builder.build();
     }
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java	Thu Mar 23 22:57:12 2017 +0000
@@ -35,7 +35,10 @@
 import java.util.Set;
 import java.util.stream.Stream;
 import jdk.internal.jimage.decompressor.CompressedResourceHeader;
-import jdk.internal.loader.ResourceHelper;
+import jdk.internal.module.Resources;
+import jdk.internal.module.ModuleInfo;
+import jdk.internal.module.ModuleInfo.Attributes;
+import jdk.internal.module.ModuleTarget;
 import jdk.tools.jlink.plugin.ResourcePool;
 import jdk.tools.jlink.plugin.ResourcePoolBuilder;
 import jdk.tools.jlink.plugin.ResourcePoolEntry;
@@ -47,8 +50,8 @@
  * A manager for pool of resources.
  */
 public class ResourcePoolManager {
-    // utility to read ModuleDescriptor of the given ResourcePoolModule
-    static ModuleDescriptor readModuleDescriptor(ResourcePoolModule mod) {
+    // utility to read Module Attributes of the given ResourcePoolModule
+    static Attributes readModuleAttributes(ResourcePoolModule mod) {
         String p = "/" + mod.name() + "/module-info.class";
         Optional<ResourcePoolEntry> content = mod.findEntry(p);
         if (!content.isPresent()) {
@@ -57,9 +60,9 @@
         }
         ByteBuffer bb = ByteBuffer.wrap(content.get().contentBytes());
         try {
-            return ModuleDescriptor.read(bb);
+            return ModuleInfo.read(bb, null);
         } catch (RuntimeException re) {
-            throw new RuntimeException("module descriptor cannot be read for " + mod.name(), re);
+            throw new RuntimeException("module info cannot be read for " + mod.name(), re);
         }
     }
 
@@ -68,7 +71,7 @@
      */
     public static boolean isNamedPackageResource(String path) {
         return (path.endsWith(".class") && !path.endsWith("module-info.class")) ||
-                !ResourceHelper.isSimpleResource(path);
+                Resources.canEncapsulate(path);
     }
 
     class ResourcePoolModuleImpl implements ResourcePoolModule {
@@ -76,6 +79,8 @@
         final Map<String, ResourcePoolEntry> moduleContent = new LinkedHashMap<>();
         // lazily initialized
         private ModuleDescriptor descriptor;
+        private ModuleTarget target;
+
         final String name;
 
         private ResourcePoolModuleImpl(String name) {
@@ -100,10 +105,28 @@
 
         @Override
         public ModuleDescriptor descriptor() {
-            if (descriptor == null) {
-                descriptor = readModuleDescriptor(this);
+            initModuleAttributes();
+            return descriptor;
+        }
+
+        @Override
+        public String osName() {
+            initModuleAttributes();
+            return target != null? target.osName() : null;
+        }
+
+        @Override
+        public String osArch() {
+            initModuleAttributes();
+            return target != null? target.osArch() : null;
+        }
+
+        private void initModuleAttributes() {
+            if (this.descriptor == null) {
+                Attributes attr = readModuleAttributes(this);
+                this.descriptor = attr.descriptor();
+                this.target = attr.target();
             }
-            return descriptor;
         }
 
         @Override
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludeVMPlugin.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludeVMPlugin.java	Thu Mar 23 22:57:12 2017 +0000
@@ -115,7 +115,7 @@
     @Override
     public ResourcePool transform(ResourcePool in, ResourcePoolBuilder out) {
         ResourcePoolModule javaBase = in.moduleView().findModule("java.base").get();
-        String[] jvmlibs = jvmlibs(javaBase.descriptor().osName().get());
+        String[] jvmlibs = jvmlibs(javaBase.osName());
         TreeSet<Jvm> existing = new TreeSet<>(new JvmComparator());
         TreeSet<Jvm> removed = new TreeSet<>(new JvmComparator());
         if (!keepAll) {
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ReleaseInfoPlugin.java	Thu Mar 23 22:57:12 2017 +0000
@@ -137,15 +137,13 @@
         javaBase.ifPresent(mod -> {
             // fill release information available from transformed "java.base" module!
             ModuleDescriptor desc = mod.descriptor();
-            desc.osName().ifPresent(s -> {
-                release.put("OS_NAME", quote(s));
-            });
-            desc.osVersion().ifPresent(s -> release.put("OS_VERSION", quote(s)));
-            desc.osArch().ifPresent(s -> release.put("OS_ARCH", quote(s)));
             desc.version().ifPresent(s -> release.put("JAVA_VERSION",
                     quote(parseVersion(s.toString()))));
             desc.version().ifPresent(s -> release.put("JAVA_FULL_VERSION",
                     quote(s.toString())));
+
+            release.put("OS_NAME", quote(mod.osName()));
+            release.put("OS_ARCH", quote(mod.osArch()));
         });
 
         // put topological sorted module names separated by space
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java	Thu Mar 23 22:57:12 2017 +0000
@@ -52,6 +52,7 @@
 import jdk.internal.module.ModuleInfo.Attributes;
 import jdk.internal.module.ModuleInfoExtender;
 import jdk.internal.module.ModuleResolution;
+import jdk.internal.module.ModuleTarget;
 import jdk.internal.module.SystemModules;
 import jdk.internal.org.objectweb.asm.Attribute;
 import jdk.internal.org.objectweb.asm.ClassReader;
@@ -206,12 +207,12 @@
             // add ModulePackages attribute if this module contains some packages
             // and ModulePackages is not present
             this.addModulePackages = packages.size() > 0 && !hasModulePackages();
+
             // drop target attribute only if any OS property is present
-            if (dropModuleTarget) {
-                this.dropModuleTarget =
-                    descriptor.osName().isPresent() ||
-                    descriptor.osArch().isPresent() ||
-                    descriptor.osVersion().isPresent();
+            ModuleTarget target = attrs.target();
+            if (dropModuleTarget && target != null) {
+                this.dropModuleTarget = (target.osName() != null)
+                                        || (target.osArch() != null);
             } else {
                 this.dropModuleTarget = false;
             }
@@ -230,6 +231,10 @@
             return packages;
         }
 
+        ModuleTarget target() {
+            return attrs.target();
+        }
+
         ModuleHashes recordedHashes() {
             return attrs.recordedHashes();
         }
@@ -372,7 +377,7 @@
             }
 
             void dropModuleTarget() {
-                extender.targetPlatform("", "", "");
+                extender.targetPlatform("", "");
             }
 
             byte[] getBytes() throws IOException {
@@ -399,6 +404,10 @@
             "java/lang/module/ModuleDescriptor$Exports$Modifier";
         private static final String OPENS_MODIFIER_CLASSNAME =
             "java/lang/module/ModuleDescriptor$Opens$Modifier";
+        private static final String MODULE_TARGET_CLASSNAME  =
+            "jdk/internal/module/ModuleTarget";
+        private static final String MODULE_TARGET_ARRAY_SIGNATURE  =
+            "[Ljdk/internal/module/ModuleTarget;";
         private static final String MODULE_HASHES_ARRAY_SIGNATURE  =
             "[Ljdk/internal/module/ModuleHashes;";
         private static final String MODULE_RESOLUTION_CLASSNAME  =
@@ -414,6 +423,7 @@
 
         private final int BUILDER_VAR    = 0;
         private final int MD_VAR         = 1;  // variable for ModuleDescriptor
+        private final int MT_VAR         = 1;  // variable for ModuleTarget
         private final int MH_VAR         = 1;  // variable for ModuleHashes
         private int nextLocalVar         = 2;  // index to next local variable
 
@@ -515,11 +525,10 @@
             if (entry.moduleName().equals("java.base")) {
                 moduleInfo = new ModuleInfo(entry.contentBytes(), packages, false);
                 ModuleDescriptor md = moduleInfo.descriptor;
-                // drop Moduletarget attribute only if java.base has all OS properties
-                // otherwise, retain it
-                if (dropModuleTarget &&
-                        md.osName().isPresent() && md.osArch().isPresent() &&
-                        md.osVersion().isPresent()) {
+                // drop ModuleTarget attribute if java.base has all OS properties
+                ModuleTarget target = moduleInfo.target();
+                if (dropModuleTarget
+                    && (target.osName() != null) && (target.osArch() != null)) {
                     dropModuleTarget = true;
                 } else {
                     dropModuleTarget = false;
@@ -584,15 +593,20 @@
 
             // generate SystemModules::descriptors
             genDescriptorsMethod();
+
+            // generate SystemModules::targets
+            genTargetsMethod();
+
             // generate SystemModules::hashes
             genHashesMethod();
+
             // generate SystemModules::moduleResolutions
             genModuleResolutionsMethod();
 
             return cw;
         }
 
-        /*
+        /**
          * Generate bytecode for SystemModules::descriptors method
          */
         private void genDescriptorsMethod() {
@@ -616,10 +630,47 @@
             mv.visitInsn(ARETURN);
             mv.visitMaxs(0, 0);
             mv.visitEnd();
-
         }
 
-        /*
+        /**
+         * Generate bytecode for SystemModules::targets method
+         */
+        private void genTargetsMethod() {
+            MethodVisitor mv = cw.visitMethod(ACC_PUBLIC+ACC_STATIC,
+                                              "targets",
+                                              "()" + MODULE_TARGET_ARRAY_SIGNATURE,
+                                              "()" + MODULE_TARGET_ARRAY_SIGNATURE,
+                                              null);
+            mv.visitCode();
+            pushInt(mv, moduleInfos.size());
+            mv.visitTypeInsn(ANEWARRAY, MODULE_TARGET_CLASSNAME);
+            mv.visitVarInsn(ASTORE, MT_VAR);
+
+            for (int index=0; index < moduleInfos.size(); index++) {
+                ModuleInfo minfo = moduleInfos.get(index);
+                if (minfo.target() != null && !minfo.dropModuleTarget) {
+                    mv.visitVarInsn(ALOAD, MT_VAR);
+                    pushInt(mv, index);
+
+                    // new ModuleTarget(String, String)
+                    mv.visitTypeInsn(NEW, MODULE_TARGET_CLASSNAME);
+                    mv.visitInsn(DUP);
+                    mv.visitLdcInsn(minfo.target().osName());
+                    mv.visitLdcInsn(minfo.target().osArch());
+                    mv.visitMethodInsn(INVOKESPECIAL, MODULE_TARGET_CLASSNAME,
+                        "<init>", "(Ljava/lang/String;Ljava/lang/String;)V", false);
+
+                    mv.visitInsn(AASTORE);
+                }
+            }
+
+            mv.visitVarInsn(ALOAD, MT_VAR);
+            mv.visitInsn(ARETURN);
+            mv.visitMaxs(0, 0);
+            mv.visitEnd();
+        }
+
+        /**
          * Generate bytecode for SystemModules::hashes method
          */
         private void genHashesMethod() {
@@ -647,10 +698,9 @@
             hmv.visitInsn(ARETURN);
             hmv.visitMaxs(0, 0);
             hmv.visitEnd();
-
         }
 
-        /*
+        /**
          * Generate bytecode for SystemModules::methodResoultions method
          */
         private void genModuleResolutionsMethod() {
@@ -749,6 +799,7 @@
             final ModuleDescriptor md;
             final Set<String> packages;
             final int index;
+
             ModuleDescriptorBuilder(ModuleDescriptor md, Set<String> packages, int index) {
                 if (md.isAutomatic()) {
                     throw new InternalError("linking automatic module is not supported");
@@ -786,11 +837,6 @@
                 // main class
                 md.mainClass().ifPresent(this::mainClass);
 
-                // os name, arch, version
-                targetPlatform(md.osName().orElse(null),
-                               md.osArch().orElse(null),
-                               md.osVersion().orElse(null));
-
                 putModuleDescriptor();
             }
 
@@ -1088,25 +1134,6 @@
                 mv.visitInsn(POP);
             }
 
-            /*
-             * Invoke Builder.osName(String name)
-             *        Builder.osArch(String arch)
-             *        Builder.osVersion(String version)
-             */
-            void targetPlatform(String osName, String osArch, String osVersion) {
-                if (osName != null) {
-                    invokeBuilderMethod("osName", osName);
-                }
-
-                if (osArch != null) {
-                    invokeBuilderMethod("osArch", osArch);
-                }
-
-                if (osVersion != null) {
-                    invokeBuilderMethod("osVersion", osVersion);
-                }
-            }
-
             void invokeBuilderMethod(String methodName, String value) {
                 mv.visitVarInsn(ALOAD, BUILDER_VAR);
                 mv.visitLdcInsn(value);
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/ResourcePoolModule.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/ResourcePoolModule.java	Thu Mar 23 22:57:12 2017 +0000
@@ -28,6 +28,7 @@
 import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Stream;
+import jdk.internal.module.ModuleTarget;
 
 /**
   * Link-time representation of a module.
@@ -57,6 +58,20 @@
     public ModuleDescriptor descriptor();
 
     /**
+     * The module target OS name for this module.
+     *
+     * @return The module target OS name
+     */
+    public String osName();
+
+    /**
+     * The module target OS arch for this module.
+     *
+     * @return The module target OS arch
+     */
+    public String osArch();
+
+    /**
      * Retrieves all the packages located in this module.
      *
      * @return The set of packages.
--- a/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java	Thu Mar 23 22:57:12 2017 +0000
@@ -96,13 +96,14 @@
 import jdk.internal.joptsimple.OptionSet;
 import jdk.internal.joptsimple.OptionSpec;
 import jdk.internal.joptsimple.ValueConverter;
-import jdk.internal.loader.ResourceHelper;
 import jdk.internal.module.ModuleHashes;
 import jdk.internal.module.ModuleHashesBuilder;
 import jdk.internal.module.ModuleInfo;
 import jdk.internal.module.ModuleInfoExtender;
 import jdk.internal.module.ModulePath;
 import jdk.internal.module.ModuleResolution;
+import jdk.internal.module.ModuleTarget;
+import jdk.internal.module.Resources;
 import jdk.tools.jlink.internal.Utils;
 
 import static java.util.stream.Collectors.joining;
@@ -178,7 +179,6 @@
         String mainClass;
         String osName;
         String osArch;
-        String osVersion;
         Pattern modulesToHash;
         ModuleResolution moduleResolution;
         boolean dryrun;
@@ -311,7 +311,9 @@
         try (JmodFile jf = new JmodFile(options.jmodFile)) {
             try (InputStream in = jf.getInputStream(Section.CLASSES, MODULE_INFO)) {
                 ModuleInfo.Attributes attrs = ModuleInfo.read(in, null);
-                printModuleDescriptor(attrs.descriptor(), attrs.recordedHashes());
+                printModuleDescriptor(attrs.descriptor(),
+                                      attrs.target(),
+                                      attrs.recordedHashes());
                 return true;
             } catch (IOException e) {
                 throw new CommandException("err.module.descriptor.not.found");
@@ -325,7 +327,9 @@
                   .collect(joining(" "));
     }
 
-    private void printModuleDescriptor(ModuleDescriptor md, ModuleHashes hashes)
+    private void printModuleDescriptor(ModuleDescriptor md,
+                                       ModuleTarget target,
+                                       ModuleHashes hashes)
         throws IOException
     {
         StringBuilder sb = new StringBuilder();
@@ -365,11 +369,14 @@
 
         md.mainClass().ifPresent(v -> sb.append("\n  main-class " + v));
 
-        md.osName().ifPresent(v -> sb.append("\n  operating-system-name " + v));
-
-        md.osArch().ifPresent(v -> sb.append("\n  operating-system-architecture " + v));
-
-        md.osVersion().ifPresent(v -> sb.append("\n  operating-system-version " + v));
+        if (target != null) {
+            String osName = target.osName();
+            if (osName != null)
+                sb.append("\n  operating-system-name " + osName);
+            String osArch = target.osArch();
+            if (osArch != null)
+                sb.append("\n  operating-system-architecture " + osArch);
+        }
 
         if (hashes != null) {
             hashes.names().stream().sorted().forEach(
@@ -432,7 +439,6 @@
         final String mainClass = options.mainClass;
         final String osName = options.osName;
         final String osArch = options.osArch;
-        final String osVersion = options.osVersion;
         final List<PathMatcher> excludes = options.excludes;
         final ModuleResolution moduleResolution = options.moduleResolution;
 
@@ -528,9 +534,9 @@
                 if (mainClass != null)
                     extender.mainClass(mainClass);
 
-                // --os-name, --os-arch, --os-version
-                if (osName != null || osArch != null || osVersion != null)
-                    extender.targetPlatform(osName, osArch, osVersion);
+                // --os-name, --os-arch
+                if (osName != null || osArch != null)
+                    extender.targetPlatform(osName, osArch);
 
                 // --module-version
                 if (moduleVersion != null)
@@ -675,7 +681,7 @@
          */
         boolean isResource(String name) {
             name = name.replace(File.separatorChar, '/');
-            return name.endsWith(".class") || !ResourceHelper.isSimpleResource(name);
+            return name.endsWith(".class") || Resources.canEncapsulate(name);
         }
 
 
@@ -1331,11 +1337,6 @@
                         .withRequiredArg()
                         .describedAs(getMessage("main.opt.os-arch.arg"));
 
-        OptionSpec<String> osVersion
-                = parser.accepts("os-version", getMessage("main.opt.os-version"))
-                        .withRequiredArg()
-                        .describedAs(getMessage("main.opt.os-version.arg"));
-
         OptionSpec<Void> doNotResolveByDefault
                 = parser.accepts("do-not-resolve-by-default",
                                  getMessage("main.opt.do-not-resolve-by-default"));
@@ -1403,8 +1404,6 @@
                 options.osName = getLastElement(opts.valuesOf(osName));
             if (opts.has(osArch))
                 options.osArch = getLastElement(opts.valuesOf(osArch));
-            if (opts.has(osVersion))
-                options.osVersion = getLastElement(opts.valuesOf(osVersion));
             if (opts.has(warnIfResolved))
                 options.moduleResolution = getLastElement(opts.valuesOf(warnIfResolved));
             if (opts.has(doNotResolveByDefault)) {
--- a/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties	Thu Mar 23 22:57:12 2017 +0000
@@ -68,8 +68,6 @@
 main.opt.os-name.arg=os-name
 main.opt.os-arch=Operating system architecture
 main.opt.os-arch.arg=os-arch
-main.opt.os-version=Operating system version
-main.opt.os-version.arg=os-version
 main.opt.module-path=Module path
 main.opt.hash-modules=Compute and record hashes to tie a packaged module\
 \ with modules matching the given <regex-pattern> and depending upon it directly\
--- a/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/src/jdk.unsupported/share/classes/sun/misc/Unsafe.java	Thu Mar 23 22:57:12 2017 +0000
@@ -813,6 +813,7 @@
     /**
      * Tells the VM to define a class, without security checks.  By default, the
      * class loader and protection domain come from the caller's class.
+     * @see java.lang.invoke.MethodHandles.Lookup#defineClass(byte[])
      */
     @ForceInline
     public Class<?> defineClass(String name, byte[] b, int off, int len,
--- a/test/TEST.groups	Thu Mar 23 22:31:12 2017 +0000
+++ b/test/TEST.groups	Thu Mar 23 22:57:12 2017 +0000
@@ -28,8 +28,6 @@
 tier1 = \
     :jdk_lang \
     :jdk_util \
-    -java/util/concurrent/ThreadPoolExecutor/ConfigChanges.java \
-    -java/util/concurrent/forkjoin/FJExceptionTableLeak.java \
     sun/nio/cs/ISO8859x.java \
     java/nio/Buffer \
     com/sun/crypto/provider/Cipher \
@@ -37,8 +35,6 @@
     tools/pack200
 
 tier2 = \
-    java/util/concurrent/ThreadPoolExecutor/ConfigChanges.java \
-    java/util/concurrent/forkjoin/FJExceptionTableLeak.java \
     :jdk_io \
     :jdk_nio \
     -sun/nio/cs/ISO8859x.java \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/awt/Choice/ChoicePopupLocation/ChoicePopupLocation.java	Thu Mar 23 22:57:12 2017 +0000
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+import java.awt.Choice;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.Insets;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.Robot;
+import java.awt.Toolkit;
+import java.awt.event.InputEvent;
+
+/**
+ * @test
+ * @bug 8176448
+ * @run main/timeout=300 ChoicePopupLocation
+ */
+public final class ChoicePopupLocation {
+
+    private static final int SIZE = 350;
+    private static int frameWidth;
+
+    public static void main(final String[] args) throws Exception {
+        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+        GraphicsDevice[] sds = ge.getScreenDevices();
+        Point left = null;
+        Point right = null;
+        for (GraphicsDevice sd : sds) {
+            GraphicsConfiguration gc = sd.getDefaultConfiguration();
+            Rectangle bounds = gc.getBounds();
+            if (left == null || left.x > bounds.x) {
+                left = new Point(bounds.x, bounds.y + bounds.height / 2);
+            }
+            if (right == null || right.x < bounds.x + bounds.width) {
+                right = new Point(bounds.x + bounds.width,
+                                  bounds.y + bounds.height / 2);
+            }
+
+            Point point = new Point(bounds.x, bounds.y);
+            Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc);
+            while (point.y < bounds.y + bounds.height - insets.bottom - SIZE ) {
+                while (point.x < bounds.x + bounds.width - insets.right - SIZE) {
+                    test(point);
+                    point.translate(bounds.width / 5, 0);
+                }
+                point.setLocation(bounds.x, point.y + bounds.height / 5);
+            }
+
+        }
+        if (left != null) {
+            left.translate(-50, 0);
+            test(left);
+        }
+        if (right != null) {
+            right.translate(-frameWidth + 50, 0);
+            test(right);
+        }
+    }
+
+    private static void test(final Point tmp) throws Exception {
+        Choice choice = new Choice();
+        for (int i = 1; i < 7; i++) {
+            choice.add("Long-long-long-long-long text in the item-" + i);
+        }
+        Frame frame = new Frame();
+        try {
+            frame.setAlwaysOnTop(true);
+            frame.setLayout(new FlowLayout());
+            frame.add(choice);
+            frame.pack();
+            frameWidth = frame.getWidth();
+            frame.setSize(frameWidth, SIZE);
+            frame.setVisible(true);
+            frame.setLocation(tmp.x, tmp.y);
+            openPopup(choice);
+        } finally {
+            frame.dispose();
+        }
+    }
+
+    private static void openPopup(final Choice choice) throws Exception {
+        Robot robot = new Robot();
+        robot.setAutoDelay(100);
+        robot.setAutoWaitForIdle(true);
+        robot.waitForIdle();
+        Point pt = choice.getLocationOnScreen();
+        robot.mouseMove(pt.x + choice.getWidth() / 2,
+                        pt.y + choice.getHeight() / 2);
+        robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
+        robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
+        int x = pt.x + choice.getWidth() / 2;
+        int y = pt.y + choice.getHeight() / 2 + 70;
+        robot.mouseMove(x, y);
+        robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
+        robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
+        robot.waitForIdle();
+        if (choice.getSelectedIndex() == 0) {
+            throw new RuntimeException();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/awt/PopupMenu/PopupMenuLocation.java	Thu Mar 23 22:57:12 2017 +0000
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.Insets;
+import java.awt.Point;
+import java.awt.PopupMenu;
+import java.awt.Rectangle;
+import java.awt.Robot;
+import java.awt.Toolkit;
+import java.awt.event.InputEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.*;
+
+/**
+ * @test
+ * @bug 8160270
+ * @run main/timeout=300 PopupMenuLocation
+ */
+public final class PopupMenuLocation {
+
+    private static final int SIZE = 350;
+    public static final String TEXT =
+            "Long-long-long-long-long-long-long text in the item-";
+    private static volatile boolean action = false;
+
+    public static void main(final String[] args) throws Exception {
+        GraphicsEnvironment ge =
+                GraphicsEnvironment.getLocalGraphicsEnvironment();
+        GraphicsDevice[] sds = ge.getScreenDevices();
+        for (GraphicsDevice sd : sds) {
+            GraphicsConfiguration gc = sd.getDefaultConfiguration();
+            Rectangle bounds = gc.getBounds();
+            Point point = new Point(bounds.x, bounds.y);
+            Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc);
+            while (point.y < bounds.y + bounds.height - insets.bottom - SIZE) {
+                while (point.x
+                        < bounds.x + bounds.width - insets.right - SIZE) {
+                    test(point);
+                    point.translate(bounds.width / 5, 0);
+                }
+                point.setLocation(bounds.x, point.y + bounds.height / 5);
+            }
+        }
+    }
+
+    private static void test(final Point tmp) throws Exception {
+        PopupMenu pm = new PopupMenu();
+        for (int i = 1; i < 7; i++) {
+            pm.add(TEXT + i);
+        }
+        pm.addActionListener(e -> action = true);
+        Frame frame = new Frame();
+        try {
+            frame.setAlwaysOnTop(true);
+            frame.setLayout(new FlowLayout());
+            frame.add(pm);
+            frame.pack();
+            frame.setSize(SIZE, SIZE);
+            frame.setVisible(true);
+            frame.setLocation(tmp.x, tmp.y);
+            frame.addMouseListener(new MouseAdapter() {
+                public void mousePressed(MouseEvent e) {
+                    show(e);
+                }
+
+                public void mouseReleased(MouseEvent e) {
+                    show(e);
+                }
+
+                private void show(MouseEvent e) {
+                    if (e.isPopupTrigger()) {
+                        pm.show(frame, 0, 50);
+                    }
+                }
+            });
+            openPopup(frame);
+        } finally {
+            frame.dispose();
+        }
+    }
+
+    private static void openPopup(final Frame frame) throws Exception {
+        Robot robot = new Robot();
+        robot.setAutoDelay(200);
+        robot.waitForIdle();
+        Point pt = frame.getLocationOnScreen();
+        robot.mouseMove(pt.x + frame.getWidth() / 2, pt.y + 50);
+        robot.mousePress(InputEvent.BUTTON3_DOWN_MASK);
+        robot.mouseRelease(InputEvent.BUTTON3_DOWN_MASK);
+        int x = pt.x + frame.getWidth() / 2;
+        int y = pt.y + 130;
+        robot.mouseMove(x, y);
+        robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
+        robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
+        robot.waitForIdle();
+        if (!action) {
+            throw new RuntimeException();
+        }
+        action = false;
+    }
+}
--- a/test/java/io/FilePermission/ReadFileOnPath.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/test/java/io/FilePermission/ReadFileOnPath.java	Thu Mar 23 22:57:12 2017 +0000
@@ -26,7 +26,7 @@
  * @bug 8164705
  * @library /lib/testlibrary /test/lib
  * @modules java.base/jdk.internal.misc
- *          java.compiler
+ *          jdk.compiler
  * @run main ReadFileOnPath
  * @summary Still able to read file on the same path
  */
--- a/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/test/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java	Thu Mar 23 22:57:12 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
@@ -380,6 +380,7 @@
             permissions.add(new RuntimePermission("closeClassLoader"));
             permissions.add(new RuntimePermission("getClassLoader"));
             permissions.add(new RuntimePermission("accessDeclaredMembers"));
+            permissions.add(new RuntimePermission("accessSystemModules"));
             permissions.add(new ReflectPermission("suppressAccessChecks"));
             permissions.add(new PropertyPermission("*", "read"));
             permissions.add(new FilePermission("<<ALL FILES>>", "read"));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/ClassLoader/getResource/automaticmodules/Driver.java	Thu Mar 23 22:57:12 2017 +0000
@@ -0,0 +1,88 @@
+/*
+ * 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
+ * @library /lib/testlibrary
+ * @build Driver Main JarUtils jdk.testlibrary.ProcessTools
+ * @run main Driver
+ * @summary Test ClassLoader.getResourceXXX to locate resources in an automatic
+ *          module
+ */
+
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReference;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.jar.Attributes;
+import java.util.jar.Manifest;
+
+import jdk.testlibrary.ProcessTools;
+
+/**
+ * The driver creates a JAR file containing p/Foo.class, p/foo.properties,
+ * and p/resources/bar.properties. This ensures there are is a resource in
+ * a module package and a resource that is not in the module package. The
+ * test is then launched to locate every resource in the JAR file.
+ */
+
+public class Driver {
+
+    private static final String TEST_CLASSES = System.getProperty("test.classes");
+
+    public static void main(String[] args) throws Exception {
+        // create content for JAR file
+        Path dir = Files.createTempDirectory("classes");
+        Path p = Files.createDirectory(dir.resolve("p"));
+        Files.createFile(p.resolve("Foo.class"));
+        Files.createFile(p.resolve("foo.properties"));
+        Path resources = Files.createDirectory(p.resolve("resources"));
+        Files.createFile(resources.resolve("bar.properties"));
+
+        // create the JAR file, including a manifest
+        Path jarFile = Paths.get("library-1.0.jar");
+        Manifest man = new Manifest();
+        Attributes attrs = man.getMainAttributes();
+        attrs.put(Attributes.Name.MANIFEST_VERSION, "1.0.0");
+        JarUtils.createJarFile(jarFile, man, dir, p);
+
+        // get the module name
+        ModuleFinder finder = ModuleFinder.of(jarFile);
+        ModuleReference mref = finder.findAll().stream().findAny().orElse(null);
+        if (mref == null)
+            throw new RuntimeException("Module not found!!!");
+        String name = mref.descriptor().name();
+
+        // launch the test with the JAR file on the module path
+        if (ProcessTools.executeTestJava("-p", jarFile.toString(),
+                                         "--add-modules", name,
+                                         "-cp", TEST_CLASSES,
+                                         "Main", name)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue() != 0)
+            throw new RuntimeException("Test failed - see output");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/ClassLoader/getResource/automaticmodules/Main.java	Thu Mar 23 22:57:12 2017 +0000
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.module.ModuleReader;
+import java.lang.module.ModuleReference;
+import java.lang.module.ResolvedModule;
+import java.lang.reflect.Layer;
+import java.net.URL;
+import java.util.Enumeration;
+
+/**
+ * Usage: Main $MODULE
+ *
+ * Finds $MODULE in the boot layer and then tests that it can locate every
+ * resource in the module content (JAR file).
+ */
+
+public class Main {
+
+    static void testFind(String name) throws Exception {
+        // getResource
+        URL url = Main.class.getClassLoader().getResource(name);
+        if (url == null)
+            throw new RuntimeException("Unable to locate: " + name);
+        System.out.println(name + " => " + url);
+
+        // getResources
+        Enumeration<URL> urls = Main.class.getClassLoader().getResources(name);
+        if (!urls.hasMoreElements())
+            throw new RuntimeException("Unable to locate: " + name);
+        URL first = urls.nextElement();
+        if (!first.toURI().equals(url.toURI()))
+            throw new RuntimeException("found " + first + " ???");
+
+        // getResourceAsStream
+        if (!url.toString().endsWith("/")) {
+            InputStream in = Main.class.getClassLoader().getResourceAsStream(name);
+            if (in == null)
+                throw new RuntimeException("Unable to locate: " + name);
+            in.close();
+        }
+    }
+
+    static void testFindUnchecked(String name) {
+        try {
+            testFind(name);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        String mn = args[0];
+
+        ModuleReference mref = Layer.boot()
+                .configuration()
+                .findModule(mn)
+                .map(ResolvedModule::reference)
+                .orElseThrow(() -> new RuntimeException(mn + " not resolved!!"));
+
+        try (ModuleReader reader = mref.open()) {
+            reader.list().forEach(name -> {
+                testFindUnchecked(name);
+
+                // if the resource is a directory then find without trailing slash
+                if (name.endsWith("/")) {
+                    testFindUnchecked(name.substring(0, name.length() - 1));
+                }
+            });
+        }
+    }
+}
--- a/test/java/lang/Package/annotation/PackageInfoTest.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/test/java/lang/Package/annotation/PackageInfoTest.java	Thu Mar 23 22:57:12 2017 +0000
@@ -25,8 +25,7 @@
  * @test
  * @summary Basic test of package-info in named module and duplicate
  *          package-info in unnamed module
- * @modules java.compiler
- *          java.desktop
+ * @modules java.desktop
  *          jdk.compiler
  *          jdk.xml.dom
  * @build jdk.xml.dom/org.w3c.dom.css.Fake
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/lang/invoke/DefineClassTest.java	Thu Mar 23 22:57:12 2017 +0000
@@ -0,0 +1,352 @@
+/*
+ * 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
+ * @modules java.base/java.lang:open
+ *          java.base/jdk.internal.org.objectweb.asm
+ * @run testng/othervm test.DefineClassTest
+ * @summary Basic test for java.lang.invoke.MethodHandles.Lookup.defineClass
+ */
+
+package test;
+
+import java.lang.invoke.MethodHandles.Lookup;
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodHandles.Lookup.*;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import static jdk.internal.org.objectweb.asm.Opcodes.*;
+
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+
+public class DefineClassTest {
+    private static final String THIS_PACKAGE = DefineClassTest.class.getPackageName();
+
+    /**
+     * Test that a class has the same class loader, and is in the same package and
+     * protection domain, as a lookup class.
+     */
+    void testSameAbode(Class<?> clazz, Class<?> lc) {
+        assertTrue(clazz.getClassLoader() == lc.getClassLoader());
+        assertEquals(clazz.getPackageName(), lc.getPackageName());
+        assertTrue(clazz.getProtectionDomain() == lc.getProtectionDomain());
+    }
+
+    /**
+     * Tests that a class is discoverable by name using Class.forName and
+     * lookup.findClass
+     */
+    void testDiscoverable(Class<?> clazz, Lookup lookup) throws Exception {
+        String cn = clazz.getName();
+        ClassLoader loader = clazz.getClassLoader();
+        assertTrue(Class.forName(cn, false, loader) == clazz);
+        assertTrue(lookup.findClass(cn) == clazz);
+    }
+
+    /**
+     * Basic test of defineClass to define a class in the same package as test.
+     */
+    @Test
+    public void testDefineClass() throws Exception {
+        final String CLASS_NAME = THIS_PACKAGE + ".Foo";
+        Lookup lookup = lookup().dropLookupMode(PRIVATE);
+        Class<?> clazz = lookup.defineClass(generateClass(CLASS_NAME));
+
+        // test name
+        assertEquals(clazz.getName(), CLASS_NAME);
+
+        // test loader/package/protection-domain
+        testSameAbode(clazz, lookup.lookupClass());
+
+        // test discoverable
+        testDiscoverable(clazz, lookup);
+
+        // attempt defineClass again
+        try {
+            lookup.defineClass(generateClass(CLASS_NAME));
+            assertTrue(false);
+        } catch (LinkageError expected) { }
+    }
+
+    /**
+     * Test public/package/protected/private access from class defined with defineClass.
+     */
+    @Test
+    public void testAccess() throws Exception {
+        final String THIS_CLASS = this.getClass().getName();
+        final String CLASS_NAME = THIS_PACKAGE + ".Runner";
+        Lookup lookup = lookup().dropLookupMode(PRIVATE);
+
+        // public
+        byte[] classBytes = generateRunner(CLASS_NAME + nextNumber(), THIS_CLASS, "method1");
+        testInvoke(lookup.defineClass(classBytes));
+
+        // package
+        classBytes = generateRunner(CLASS_NAME + nextNumber(), THIS_CLASS, "method2");
+        testInvoke(lookup.defineClass(classBytes));
+
+        // protected (same package)
+        classBytes = generateRunner(CLASS_NAME + nextNumber(), THIS_CLASS, "method3");
+        testInvoke(lookup.defineClass(classBytes));
+
+        // private
+        classBytes = generateRunner(CLASS_NAME + nextNumber(), THIS_CLASS, "method4");
+        Class<?> clazz = lookup.defineClass(classBytes);
+        Runnable r = (Runnable) clazz.newInstance();
+        try {
+            r.run();
+            assertTrue(false);
+        } catch (IllegalAccessError expected) { }
+    }
+
+    public static void method1() { }
+    static void method2() { }
+    protected static void method3() { }
+    private static void method4() { }
+
+    void testInvoke(Class<?> clazz) throws Exception {
+        Object obj = clazz.newInstance();
+        ((Runnable) obj).run();
+    }
+
+    /**
+     * Test that defineClass does not run the class initializer
+     */
+    @Test
+    public void testInitializerNotRun() throws Exception {
+        final String THIS_CLASS = this.getClass().getName();
+        final String CLASS_NAME = THIS_PACKAGE + ".ClassWithClinit";
+
+        byte[] classBytes = generateClassWithInitializer(CLASS_NAME, THIS_CLASS, "fail");
+        Lookup lookup = lookup().dropLookupMode(PRIVATE);
+
+        Class<?> clazz = lookup.defineClass(classBytes);
+        // trigger initializer to run
+        try {
+            clazz.newInstance();
+            assertTrue(false);
+        } catch (ExceptionInInitializerError e) {
+            assertTrue(e.getCause() instanceof IllegalCallerException);
+        }
+    }
+
+    static void fail() { throw new IllegalCallerException(); }
+
+
+    /**
+     * Test defineClass to define classes in a package containing classes with
+     * different protection domains.
+     */
+    @Test
+    public void testTwoProtectionDomains() throws Exception {
+        // p.C1 in one exploded directory
+        Path dir1 = Files.createTempDirectory("classes");
+        Path p = Files.createDirectory(dir1.resolve("p"));
+        Files.write(p.resolve("C1.class"), generateClass("p.C1"));
+        URL url1 = dir1.toUri().toURL();
+
+        // p.C2 in another exploded directory
+        Path dir2 = Files.createTempDirectory("classes");
+        p = Files.createDirectory(dir2.resolve("p"));
+        Files.write(p.resolve("C2.class"), generateClass("p.C2"));
+        URL url2 = dir2.toUri().toURL();
+
+        // load p.C1 and p.C2
+        ClassLoader loader = new URLClassLoader(new URL[] { url1, url2 });
+        Class<?> target1 = Class.forName("p.C1", false, loader);
+        Class<?> target2 = Class.forName("p.C2", false, loader);
+        assertTrue(target1.getClassLoader() == loader);
+        assertTrue(target1.getClassLoader() == loader);
+        assertNotEquals(target1.getProtectionDomain(), target2.getProtectionDomain());
+
+        // protection domain 1
+        Lookup lookup1 = privateLookupIn(target1, lookup()).dropLookupMode(PRIVATE);
+
+        Class<?> clazz = lookup1.defineClass(generateClass("p.Foo"));
+        testSameAbode(clazz, lookup1.lookupClass());
+        testDiscoverable(clazz, lookup1);
+
+        // protection domain 2
+        Lookup lookup2 = privateLookupIn(target2, lookup()).dropLookupMode(PRIVATE);
+
+        clazz = lookup2.defineClass(generateClass("p.Bar"));
+        testSameAbode(clazz, lookup2.lookupClass());
+        testDiscoverable(clazz, lookup2);
+    }
+
+    /**
+     * Test defineClass defining a class to the boot loader
+     */
+    @Test
+    public void testBootLoader() throws Exception {
+        Lookup lookup = privateLookupIn(Thread.class, lookup()).dropLookupMode(PRIVATE);
+        assertTrue(lookup.getClass().getClassLoader() == null);
+
+        Class<?> clazz = lookup.defineClass(generateClass("java.lang.Foo"));
+        assertEquals(clazz.getName(), "java.lang.Foo");
+        testSameAbode(clazz, Thread.class);
+        testDiscoverable(clazz, lookup);
+    }
+
+    @Test(expectedExceptions = { IllegalArgumentException.class })
+    public void testWrongPackage() throws Exception {
+        Lookup lookup = lookup().dropLookupMode(PRIVATE);
+        lookup.defineClass(generateClass("other.C"));
+    }
+
+    @Test(expectedExceptions = { IllegalAccessException.class })
+    public void testNoPackageAccess() throws Exception {
+        Lookup lookup = lookup().dropLookupMode(PACKAGE);
+        lookup.defineClass(generateClass(THIS_PACKAGE + ".C"));
+    }
+
+    @Test(expectedExceptions = { UnsupportedOperationException.class })
+    public void testHasPrivateAccess() throws Exception {
+        Lookup lookup = lookup();
+        assertTrue(lookup.hasPrivateAccess());
+        lookup.defineClass(generateClass(THIS_PACKAGE + ".C"));
+    }
+
+    @Test(expectedExceptions = { ClassFormatError.class })
+    public void testTruncatedClassFile() throws Exception {
+        Lookup lookup = lookup().dropLookupMode(PRIVATE);
+        lookup.defineClass(new byte[0]);
+    }
+
+    @Test(expectedExceptions = { NullPointerException.class })
+    public void testNull() throws Exception {
+        Lookup lookup = lookup().dropLookupMode(PRIVATE);
+        lookup.defineClass(null);
+    }
+
+    /**
+     * Generates a class file with the given class name
+     */
+    byte[] generateClass(String className) {
+        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
+                                         + ClassWriter.COMPUTE_FRAMES);
+        cw.visit(V1_9,
+                ACC_PUBLIC + ACC_SUPER,
+                className.replace(".", "/"),
+                null,
+                "java/lang/Object",
+                null);
+
+        // <init>
+        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+        mv.visitInsn(RETURN);
+        mv.visitMaxs(0, 0);
+        mv.visitEnd();
+
+        cw.visitEnd();
+        return cw.toByteArray();
+    }
+
+    /**
+     * Generate a class file with the given class name. The class implements Runnable
+     * with a run method to invokestatic the given targetClass/targetMethod.
+     */
+    byte[] generateRunner(String className,
+                          String targetClass,
+                          String targetMethod) throws Exception {
+
+        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
+                                         + ClassWriter.COMPUTE_FRAMES);
+        cw.visit(V1_9,
+                ACC_PUBLIC + ACC_SUPER,
+                className.replace(".", "/"),
+                null,
+                "java/lang/Object",
+                new String[] { "java/lang/Runnable" });
+
+        // <init>
+        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+        mv.visitInsn(RETURN);
+        mv.visitMaxs(0, 0);
+        mv.visitEnd();
+
+        // run()
+        String tc = targetClass.replace(".", "/");
+        mv = cw.visitMethod(ACC_PUBLIC, "run", "()V", null, null);
+        mv.visitMethodInsn(INVOKESTATIC, tc, targetMethod, "()V", false);
+        mv.visitInsn(RETURN);
+        mv.visitMaxs(0, 0);
+        mv.visitEnd();
+
+        cw.visitEnd();
+        return cw.toByteArray();
+    }
+
+    /**
+     * Generate a class file with the given class name. The class will initializer
+     * to invokestatic the given targetClass/targetMethod.
+     */
+    byte[] generateClassWithInitializer(String className,
+                                        String targetClass,
+                                        String targetMethod) throws Exception {
+
+        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
+                                         + ClassWriter.COMPUTE_FRAMES);
+        cw.visit(V1_9,
+                ACC_PUBLIC + ACC_SUPER,
+                className.replace(".", "/"),
+                null,
+                "java/lang/Object",
+                null);
+
+        // <init>
+        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+        mv.visitInsn(RETURN);
+        mv.visitMaxs(0, 0);
+        mv.visitEnd();
+
+        // <clinit>
+        String tc = targetClass.replace(".", "/");
+        mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
+        mv.visitMethodInsn(INVOKESTATIC, tc, targetMethod, "()V", false);
+        mv.visitInsn(RETURN);
+        mv.visitMaxs(0, 0);
+        mv.visitEnd();
+
+        cw.visitEnd();
+        return cw.toByteArray();
+    }
+
+    private int nextNumber() {
+        return ++nextNumber;
+    }
+
+    private int nextNumber;
+}
--- a/test/java/lang/module/AutomaticModulesTest.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/test/java/lang/module/AutomaticModulesTest.java	Thu Mar 23 22:57:12 2017 +0000
@@ -773,9 +773,6 @@
         // test miscellaneous methods
         assertTrue(m.isAutomatic());
         assertFalse(m.modifiers().contains(ModuleDescriptor.Modifier.SYNTHETIC));
-        assertFalse(m.osName().isPresent());
-        assertFalse(m.osArch().isPresent());
-        assertFalse(m.osVersion().isPresent());
     }
 
 
--- a/test/java/lang/module/ConfigurationTest.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/test/java/lang/module/ConfigurationTest.java	Thu Mar 23 22:57:12 2017 +0000
@@ -25,25 +25,31 @@
  * @test
  * @library /lib/testlibrary
  * @modules java.base/jdk.internal.misc
+ *          java.base/jdk.internal.module
  * @build ConfigurationTest ModuleUtils
  * @run testng ConfigurationTest
  * @summary Basic tests for java.lang.module.Configuration
  */
 
+import java.io.IOException;
+import java.io.OutputStream;
 import java.lang.module.Configuration;
 import java.lang.module.FindException;
 import java.lang.module.ModuleDescriptor;
-import java.lang.module.ModuleDescriptor.Builder;
 import java.lang.module.ModuleDescriptor.Requires;
 import java.lang.module.ModuleFinder;
 import java.lang.module.ResolutionException;
 import java.lang.module.ResolvedModule;
 import java.lang.reflect.Layer;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.List;
 import java.util.Optional;
 import java.util.Set;
 
 import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ModuleInfoWriter;
+import jdk.internal.module.ModuleTarget;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 import static org.testng.Assert.*;
@@ -438,70 +444,6 @@
 
 
     /**
-     * Basic test of "requires transitive" with configurations.
-     *
-     * The test consists of three configurations:
-     * - Configuration cf1: m1, m2 requires transitive m1
-     * - Configuration cf2: m1, m3 requires transitive m1
-     * - Configuration cf3(cf1,cf2): m4 requires m2, m3
-     */
-    public void testRequiresTransitive6() {
-        ModuleDescriptor descriptor1 = newBuilder("m1")
-                .build();
-
-        ModuleDescriptor descriptor2 = newBuilder("m2")
-                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
-                .build();
-
-        ModuleDescriptor descriptor3 = newBuilder("m3")
-                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
-                .build();
-
-        ModuleDescriptor descriptor4 = newBuilder("m4")
-                .requires("m2")
-                .requires("m3")
-                .build();
-
-        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
-        Configuration cf1 = resolve(finder1, "m2");
-        assertTrue(cf1.modules().size() == 2);
-        assertTrue(cf1.findModule("m1").isPresent());
-        assertTrue(cf1.findModule("m2").isPresent());
-        assertTrue(cf1.parents().size() == 1);
-        assertTrue(cf1.parents().get(0) == Configuration.empty());
-
-        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor3);
-        Configuration cf2 = resolve(finder2, "m3");
-        assertTrue(cf2.modules().size() == 2);
-        assertTrue(cf2.findModule("m3").isPresent());
-        assertTrue(cf2.findModule("m1").isPresent());
-        assertTrue(cf2.parents().size() == 1);
-        assertTrue(cf2.parents().get(0) == Configuration.empty());
-
-        ModuleFinder finder3 = ModuleUtils.finderOf(descriptor4);
-        Configuration cf3 = Configuration.resolve(finder3,
-                List.of(cf1, cf2),
-                ModuleFinder.of(),
-                Set.of("m4"));
-        assertTrue(cf3.modules().size() == 1);
-        assertTrue(cf3.findModule("m4").isPresent());
-
-        ResolvedModule m1_l = cf1.findModule("m1").get();
-        ResolvedModule m1_r = cf2.findModule("m1").get();
-        ResolvedModule m2 = cf1.findModule("m2").get();
-        ResolvedModule m3 = cf2.findModule("m3").get();
-        ResolvedModule m4 = cf3.findModule("m4").get();
-        assertTrue(m4.configuration() == cf3);
-
-        assertTrue(m4.reads().size() == 4);
-        assertTrue(m4.reads().contains(m1_l));
-        assertTrue(m4.reads().contains(m1_r));
-        assertTrue(m4.reads().contains(m2));
-        assertTrue(m4.reads().contains(m3));
-    }
-
-
-    /**
      * Basic test of "requires static":
      *     m1 requires static m2
      *     m2 is not observable
@@ -1603,6 +1545,76 @@
 
 
     /**
+     * Basic test to detect reading a module with the same name as itself
+     *
+     * The test consists of three configurations:
+     * - Configuration cf1: m1, m2 requires transitive m1
+     * - Configuration cf2: m1 requires m2
+     */
+    @Test(expectedExceptions = { ResolutionException.class })
+    public void testReadModuleWithSameNameAsSelf() {
+        ModuleDescriptor descriptor1_v1 = newBuilder("m1")
+                .build();
+
+        ModuleDescriptor descriptor2 = newBuilder("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
+                .build();
+
+        ModuleDescriptor descriptor1_v2 = newBuilder("m1")
+                .requires("m2")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1_v1, descriptor2);
+        Configuration cf1 = resolve(finder1, "m2");
+        assertTrue(cf1.modules().size() == 2);
+
+        // resolve should throw ResolutionException
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1_v2);
+        resolve(cf1, finder2, "m1");
+    }
+
+
+    /**
+     * Basic test to detect reading two modules with the same name
+     *
+     * The test consists of three configurations:
+     * - Configuration cf1: m1, m2 requires transitive m1
+     * - Configuration cf2: m1, m3 requires transitive m1
+     * - Configuration cf3(cf1,cf2): m4 requires m2, m3
+     */
+    @Test(expectedExceptions = { ResolutionException.class })
+    public void testReadTwoModuleWithSameName() {
+        ModuleDescriptor descriptor1 = newBuilder("m1")
+                .build();
+
+        ModuleDescriptor descriptor2 = newBuilder("m2")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
+                .build();
+
+        ModuleDescriptor descriptor3 = newBuilder("m3")
+                .requires(Set.of(Requires.Modifier.TRANSITIVE), "m1")
+                .build();
+
+        ModuleDescriptor descriptor4 = newBuilder("m4")
+                .requires("m2")
+                .requires("m3")
+                .build();
+
+        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1, descriptor2);
+        Configuration cf1 = resolve(finder1, "m2");
+        assertTrue(cf1.modules().size() == 2);
+
+        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor1, descriptor3);
+        Configuration cf2 = resolve(finder2, "m3");
+        assertTrue(cf2.modules().size() == 2);
+
+        // should throw ResolutionException as m4 will read modules named "m1".
+        ModuleFinder finder3 = ModuleUtils.finderOf(descriptor4);
+        Configuration.resolve(finder3, List.of(cf1, cf2), ModuleFinder.of(), Set.of("m4"));
+    }
+
+
+    /**
      * Test two modules exporting package p to a module that reads both.
      */
     @Test(expectedExceptions = { ResolutionException.class })
@@ -1832,26 +1844,17 @@
     public Object[][] createPlatformMatches() {
         return new Object[][]{
 
-            { "linux-*-*",       "*-*-*" },
-            { "*-arm-*",         "*-*-*" },
-            { "*-*-2.6",         "*-*-*" },
-
-            { "linux-arm-*",     "*-*-*" },
-            { "linux-*-2.6",     "*-*-*" },
-            { "*-arm-2.6",       "*-*-*" },
-
-            { "linux-arm-2.6",   "*-*-*" },
-
-            { "linux-*-*",       "linux-*-*" },
-            { "*-arm-*",         "*-arm-*"   },
-            { "*-*-2.6",         "*-*-2.6"   },
-
-            { "linux-arm-*",     "linux-arm-*" },
-            { "linux-arm-*",     "linux-*-*"   },
-            { "linux-*-2.6",     "linux-*-2.6" },
-            { "linux-*-2.6",     "linux-arm-*" },
-
-            { "linux-arm-2.6",   "linux-arm-2.6" },
+            { "linux-arm",     "*-*" },
+            { "linux-*",       "*-*" },
+            { "*-arm",         "*-*" },
+
+            { "linux-*",       "linux-*" },
+            { "linux-arm",     "linux-*" },
+
+            { "*-arm",         "*-arm" },
+            { "linux-arm",     "*-arm" },
+
+            { "linux-arm",   "linux-arm" },
 
         };
 
@@ -1861,9 +1864,10 @@
     public Object[][] createBad() {
         return new Object[][] {
 
-            { "linux-*-*",        "solaris-*-*"   },
-            { "linux-x86-*",      "linux-arm-*"   },
-            { "linux-*-2.4",      "linux-x86-2.6" },
+            { "linux-*",        "solaris-*"     },
+            { "*-arm",          "*-sparc"       },
+            { "linux-x86",      "solaris-sparc" },
+
         };
     }
 
@@ -1871,21 +1875,25 @@
      * Test creating a configuration containing platform specific modules.
      */
     @Test(dataProvider = "platformmatch")
-    public void testPlatformMatch(String s1, String s2) {
-
-        Builder builder = newBuilder("m1").requires("m2");
-        addPlatformConstraints(builder, s1);
-        ModuleDescriptor descriptor1 = builder.build();
-
-        builder = newBuilder("m2");
-        addPlatformConstraints(builder, s2);
-        ModuleDescriptor descriptor2 = builder.build();
-
-        ModuleFinder finder = ModuleUtils.finderOf(descriptor1, descriptor2);
+    public void testPlatformMatch(String s1, String s2) throws IOException {
+
+        ModuleDescriptor base =  ModuleDescriptor.newModule("java.base").build();
+        Path system = writeModule(base, "*-*");
+
+        ModuleDescriptor descriptor1 = ModuleDescriptor.newModule("m1")
+                .requires("m2")
+                .build();
+        Path dir1 = writeModule(descriptor1, s1);
+
+        ModuleDescriptor descriptor2 = ModuleDescriptor.newModule("m2").build();
+        Path dir2 = writeModule(descriptor2, s2);
+
+        ModuleFinder finder = ModuleFinder.of(system, dir1, dir2);
 
         Configuration cf = resolve(finder, "m1");
 
-        assertTrue(cf.modules().size() == 2);
+        assertTrue(cf.modules().size() == 3);
+        assertTrue(cf.findModule("java.base").isPresent());
         assertTrue(cf.findModule("m1").isPresent());
         assertTrue(cf.findModule("m2").isPresent());
     }
@@ -1896,11 +1904,10 @@
      */
     @Test(dataProvider = "platformmismatch",
           expectedExceptions = FindException.class )
-    public void testPlatformMisMatch(String s1, String s2) {
+    public void testPlatformMisMatch(String s1, String s2) throws IOException {
         testPlatformMatch(s1, s2);
     }
 
-
     // no parents
 
     @Test(expectedExceptions = { IllegalArgumentException.class })
@@ -1917,21 +1924,23 @@
 
 
     // parents with modules for specific platforms
-
     @Test(dataProvider = "platformmatch")
-    public void testResolveRequiresWithCompatibleParents(String s1, String s2) {
-        Builder builder = newBuilder("m1");
-        addPlatformConstraints(builder, s1);
-        ModuleDescriptor descriptor1 = builder.build();
-
-        builder = newBuilder("m2");
-        addPlatformConstraints(builder, s2);
-        ModuleDescriptor descriptor2 = builder.build();
-
-        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
+    public void testResolveRequiresWithCompatibleParents(String s1, String s2)
+        throws IOException
+    {
+        ModuleDescriptor base =  ModuleDescriptor.newModule("java.base").build();
+        Path system = writeModule(base, "*-*");
+
+        ModuleDescriptor descriptor1 = ModuleDescriptor.newModule("m1").build();
+        Path dir1 = writeModule(descriptor1, s1);
+
+        ModuleDescriptor descriptor2 = ModuleDescriptor.newModule("m2").build();
+        Path dir2 = writeModule(descriptor2, s2);
+
+        ModuleFinder finder1 = ModuleFinder.of(system, dir1);
         Configuration cf1 = resolve(finder1, "m1");
 
-        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2);
+        ModuleFinder finder2 = ModuleFinder.of(system, dir2);
         Configuration cf2 = resolve(finder2, "m2");
 
         Configuration cf3 = Configuration.resolve(ModuleFinder.of(),
@@ -1941,32 +1950,16 @@
         assertTrue(cf3.parents().size() == 2);
     }
 
+
     @Test(dataProvider = "platformmismatch",
           expectedExceptions = IllegalArgumentException.class )
-    public void testResolveRequiresWithConflictingParents(String s1, String s2) {
-        Builder builder = newBuilder("m1");
-        addPlatformConstraints(builder, s1);
-        ModuleDescriptor descriptor1 = builder.build();
-
-        builder = newBuilder("m2");
-        addPlatformConstraints(builder, s2);
-        ModuleDescriptor descriptor2 = builder.build();
-
-        ModuleFinder finder1 = ModuleUtils.finderOf(descriptor1);
-        Configuration cf1 = resolve(finder1, "m1");
-
-        ModuleFinder finder2 = ModuleUtils.finderOf(descriptor2);
-        Configuration cf2 = resolve(finder2, "m2");
-
-        // should throw IAE
-        Configuration.resolve(ModuleFinder.of(),
-                              List.of(cf1, cf2),
-                              ModuleFinder.of(),
-                              Set.of());
+    public void testResolveRequiresWithConflictingParents(String s1, String s2)
+        throws IOException
+    {
+        testResolveRequiresWithCompatibleParents(s1, s2);
     }
 
 
-
     // null handling
 
     // finder1, finder2, roots
@@ -2121,30 +2114,23 @@
 
 
     /**
-     * Returns {@code true} if the configuration contains module mn1
-     * that reads module mn2.
-     */
-    static boolean reads(Configuration cf, String mn1, String mn2) {
-        Optional<ResolvedModule> om1 = cf.findModule(mn1);
-        if (!om1.isPresent())
-            return false;
-
-        return om1.get().reads().stream()
-                .map(ResolvedModule::name)
-                .anyMatch(mn2::equals);
-    }
-
-    /**
      * Decodes the platform string and calls the builder osName/osArch/osVersion
      * methods to set the platform constraints.
      */
-    static void addPlatformConstraints(Builder builder, String platformString) {
+    static Path writeModule(ModuleDescriptor descriptor, String platformString)
+        throws IOException
+    {
         String[] s = platformString.split("-");
-        if (!s[0].equals("*"))
-            builder.osName(s[0]);
-        if (!s[1].equals("*"))
-            builder.osArch(s[1]);
-        if (!s[2].equals("*"))
-            builder.osVersion(s[2]);
+        String osName = !s[0].equals("*") ? s[0] : null;
+        String osArch = !s[1].equals("*") ? s[1] : null;
+        ModuleTarget target = new ModuleTarget(osName, osArch);
+
+        String name = descriptor.name();
+        Path dir = Files.createTempDirectory(name);
+        Path mi = dir.resolve("module-info.class");
+        try (OutputStream out = Files.newOutputStream(mi)) {
+            ModuleInfoWriter.write(descriptor, target, out);
+        }
+        return dir;
     }
 }
--- a/test/java/lang/module/ModuleDescriptorTest.java	Thu Mar 23 22:31:12 2017 +0000
+++ b/test/java/lang/module/ModuleDescriptorTest.java	Thu Mar 23 22:57:12 2017 +0000
@@ -50,11 +50,13 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.Set;
 import java.util.stream.Collectors;
 
 import static java.lang.module.ModuleDescriptor.Requires.Modifier.*;
 
+import jdk.internal.misc.JavaLangModuleAccess;
 import jdk.internal.misc.SharedSecrets;
 import jdk.internal.module.ModuleInfoWriter;
 import org.testng.annotations.DataProvider;
@@ -988,6 +990,107 @@
     }
 
 
+    @DataProvider(name = "unparseableVersions")
+    public Object[][] unparseableVersions() {
+        return new Object[][]{
+
+                { null,  "A1" },    // no version < unparseable
+                { "A1",  "A2" },    // unparseable < unparseable
+                { "A1",  "1.0" },   // unparseable < parseable
+
+        };
+    }
+
+    /**
+     * Basic test for unparseable module versions
+     */
+    @Test(dataProvider = "unparseableVersions")
+    public void testUnparseableModuleVersion(String vs1, String vs2) {
+        ModuleDescriptor descriptor1 = newModule("m", vs1);
+        ModuleDescriptor descriptor2 = newModule("m", vs2);
+
+        if (vs1 != null && !isParsableVersion(vs1)) {
+            assertFalse(descriptor1.version().isPresent());
+            assertTrue(descriptor1.rawVersion().isPresent());
+            assertEquals(descriptor1.rawVersion().get(), vs1);
+        }
+
+        if (vs2 != null && !isParsableVersion(vs2)) {
+            assertFalse(descriptor2.version().isPresent());
+            assertTrue(descriptor2.rawVersion().isPresent());
+            assertEquals(descriptor2.rawVersion().get(), vs2);
+        }
+
+        assertFalse(descriptor1.equals(descriptor2));
+        assertFalse(descriptor2.equals(descriptor1));
+        assertTrue(descriptor1.compareTo(descriptor2) == -1);
+        assertTrue(descriptor2.compareTo(descriptor1) == 1);
+    }
+
+    /**
+     * Basic test for requiring a module with an unparseable version recorded
+     * at compile version.
+     */
+    @Test(dataProvider = "unparseableVersions")
+    public void testUnparseableCompiledVersion(String vs1, String vs2) {
+        Requires r1 = newRequires("m", vs1);
+        Requires r2 = newRequires("m", vs2);
+
+        if (vs1 != null && !isParsableVersion(vs1)) {
+            assertFalse(r1.compiledVersion().isPresent());
+            assertTrue(r1.rawCompiledVersion().isPresent());
+            assertEquals(r1.rawCompiledVersion().get(), vs1);
+        }
+
+        if (vs2 != null && !isParsableVersion(vs2)) {
+            assertFalse(r2.compiledVersion().isPresent());
+            assertTrue(r2.rawCompiledVersion().isPresent());
+            assertEquals(r2.rawCompiledVersion().get(), vs2);
+        }
+
+        assertFalse(r1.equals(r2));
+        assertFalse(r2.equals(r1));
+        assertTrue(r1.compareTo(r2) == -1);
+        assertTrue(r2.compareTo(r1) == 1);
+    }
+
+    private ModuleDescriptor newModule(String name, String vs) {
+        JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess();
+        Builder builder = JLMA.newModuleBuilder(name, false, Set.of());
+        if (vs != null)
+            builder.version(vs);
+        builder.requires("java.base");
+        ByteBuffer bb = ModuleInfoWriter.toByteBuffer(builder.build());
+        return ModuleDescriptor.read(bb);
+    }
+
+    private Requires newRequires(String name, String vs) {
+        JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess();
+        Builder builder = JLMA.newModuleBuilder("foo", false, Set.of());
+        if (vs == null) {
+            builder.requires(name);
+        } else {
+            JLMA.requires(builder, Set.of(), name, vs);
+        }
+        Set<ModuleDescriptor.Requires> requires = builder.build().requires();
+        Iterator<ModuleDescriptor.Requires> iterator = requires.iterator();
+        ModuleDescriptor.Requires r = iterator.next();
+        if (r.name().equals("java.base")) {
+            r = iterator.next();
+        }