Merge
authorddehaven
Tue, 17 Jan 2017 11:35:28 -0800
changeset 43231 4885b2a3898b
parent 43230 f139e452dd55 (current diff)
parent 43109 fe275140c3f1 (diff)
child 43232 8e39ad39979f
Merge
jdk/test/java/rmi/registry/readTest/readTest.java
jdk/test/java/rmi/registry/readTest/readTest.sh
jdk/test/lib/security/SecurityTools.java
jdk/test/tools/jar/mmrjar/ConcealedPackage.java
jdk/test/tools/jmod/hashes/src/m1/module-info.java
jdk/test/tools/jmod/hashes/src/m1/org/m1/Main.java
jdk/test/tools/jmod/hashes/src/m2/module-info.java
jdk/test/tools/jmod/hashes/src/m2/org/m2/Util.java
jdk/test/tools/jmod/hashes/src/m3/module-info.java
jdk/test/tools/jmod/hashes/src/m3/org/m3/Name.java
jdk/test/tools/jmod/hashes/src/org.bar/module-info.java
jdk/test/tools/jmod/hashes/src/org.foo/module-info.java
--- a/jdk/.hgtags	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/.hgtags	Tue Jan 17 11:35:28 2017 -0800
@@ -394,3 +394,4 @@
 5a846396a24c7aff01d6a8feaa7afc0a6369f04d jdk-9+149
 71e198ef3839045e829a879af1d709be16ab0f88 jdk-9+150
 d27bab22ff62823902d93d1d35ca397cfd50d059 jdk-9+151
+a20f2cf90762673e1bc4980fd6597e70a2578045 jdk-9+152
--- a/jdk/src/java.base/share/classes/java/io/File.java	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/java.base/share/classes/java/io/File.java	Tue Jan 17 11:35:28 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 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
@@ -1962,6 +1962,9 @@
                 name = sb.toString();
             }
 
+            // Normalize the path component
+            name = fs.normalize(name);
+
             File f = new File(dir, name);
             if (!name.equals(f.getName()) || f.isInvalid()) {
                 if (System.getSecurityManager() != null)
--- a/jdk/src/java.base/share/classes/java/util/Date.java	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/java.base/share/classes/java/util/Date.java	Tue Jan 17 11:35:28 2017 -0800
@@ -82,17 +82,19 @@
  * well; for example, the time scale used by the satellite-based
  * global positioning system (GPS) is synchronized to UTC but is
  * <i>not</i> adjusted for leap seconds. An interesting source of
- * further information is the U.S. Naval Observatory, particularly
- * the Directorate of Time at:
+ * further information is the United States Naval Observatory (USNO):
  * <blockquote><pre>
- *     <a href="http://www.usno.navy.mil">http://www.usno.navy.mil</a>
+ *     <a href="http://www.usno.navy.mil/USNO">http://www.usno.navy.mil/USNO</a>
  * </pre></blockquote>
  * <p>
- * and their definitions of "Systems of Time" at:
+ * and the material regarding "Systems of Time" at:
  * <blockquote><pre>
  *     <a href="http://www.usno.navy.mil/USNO/time/master-clock/systems-of-time">http://www.usno.navy.mil/USNO/time/master-clock/systems-of-time</a>
  * </pre></blockquote>
  * <p>
+ * which has descriptions of various different time systems including
+ * UT, UT1, and UTC.
+ * <p>
  * In all methods of class {@code Date} that accept or return
  * year, month, date, hours, minutes, and seconds values, the
  * following representations are used:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashesBuilder.java	Tue Jan 17 11:35:28 2017 -0800
@@ -0,0 +1,312 @@
+/*
+ * 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.io.PrintStream;
+import java.lang.module.Configuration;
+import java.lang.module.ResolvedModule;
+import java.net.URI;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayDeque;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.stream.Stream;
+import static java.util.stream.Collectors.*;
+
+/**
+ * A Builder to compute ModuleHashes from a given configuration
+ */
+public class ModuleHashesBuilder {
+    private final Configuration configuration;
+    private final Set<String> hashModuleCandidates;
+
+    /**
+     * Constructs a ModuleHashesBuilder that finds the packaged modules
+     * from the location of ModuleReference found from the given Configuration.
+     *
+     * @param config Configuration for building module hashes
+     * @param modules the candidate modules to be hashed
+     */
+    public ModuleHashesBuilder(Configuration config, Set<String> modules) {
+        this.configuration = config;
+        this.hashModuleCandidates = modules;
+    }
+
+    /**
+     * Returns a map of a module M to ModuleHashes for the modules
+     * that depend upon M directly or indirectly.
+     *
+     * The key for each entry in the returned map is a module M that has
+     * no outgoing edges to any of the candidate modules to be hashed
+     * i.e. M is a leaf node in a connected subgraph containing M and
+     * other candidate modules from the module graph filtering
+     * the outgoing edges from M to non-candidate modules.
+     */
+    public Map<String, ModuleHashes> computeHashes(Set<String> roots) {
+        // build a graph containing the the packaged modules and
+        // its transitive dependences matching --hash-modules
+        Graph.Builder<String> builder = new Graph.Builder<>();
+        Deque<ResolvedModule> deque = new ArrayDeque<>(configuration.modules());
+        Set<ResolvedModule> visited = new HashSet<>();
+        while (!deque.isEmpty()) {
+            ResolvedModule rm = deque.pop();
+            if (!visited.contains(rm)) {
+                visited.add(rm);
+                builder.addNode(rm.name());
+                for (ResolvedModule dm : rm.reads()) {
+                    if (!visited.contains(dm)) {
+                        deque.push(dm);
+                    }
+                    builder.addEdge(rm.name(), dm.name());
+                }
+            }
+        }
+
+        // each node in a transposed graph is a matching packaged module
+        // in which the hash of the modules that depend upon it is recorded
+        Graph<String> transposedGraph = builder.build().transpose();
+
+        // traverse the modules in topological order that will identify
+        // the modules to record the hashes - it is the first matching
+        // module and has not been hashed during the traversal.
+        Set<String> mods = new HashSet<>();
+        Map<String, ModuleHashes> hashes = new HashMap<>();
+        builder.build()
+               .orderedNodes()
+               .filter(mn -> roots.contains(mn) && !mods.contains(mn))
+               .forEach(mn -> {
+                   // Compute hashes of the modules that depend on mn directly and
+                   // indirectly excluding itself.
+                   Set<String> ns = transposedGraph.dfs(mn)
+                       .stream()
+                       .filter(n -> !n.equals(mn) && hashModuleCandidates.contains(n))
+                       .collect(toSet());
+                   mods.add(mn);
+                   mods.addAll(ns);
+
+                   if (!ns.isEmpty()) {
+                       Map<String, Path> moduleToPath = ns.stream()
+                           .collect(toMap(Function.identity(), this::moduleToPath));
+                       hashes.put(mn, ModuleHashes.generate(moduleToPath, "SHA-256"));
+                   }
+               });
+        return hashes;
+    }
+
+    private Path moduleToPath(String name) {
+        ResolvedModule rm = configuration.findModule(name).orElseThrow(
+            () -> new InternalError("Selected module " + name + " not on module path"));
+
+        URI uri = rm.reference().location().get();
+        Path path = Paths.get(uri);
+        String fn = path.getFileName().toString();
+        if (!fn.endsWith(".jar") && !fn.endsWith(".jmod")) {
+            throw new UnsupportedOperationException(path + " is not a modular JAR or jmod file");
+        }
+        return path;
+    }
+
+    /*
+     * Utilty class
+     */
+    static class Graph<T> {
+        private final Set<T> nodes;
+        private final Map<T, Set<T>> edges;
+
+        public Graph(Set<T> nodes, Map<T, Set<T>> edges) {
+            this.nodes = Collections.unmodifiableSet(nodes);
+            this.edges = Collections.unmodifiableMap(edges);
+        }
+
+        public Set<T> nodes() {
+            return nodes;
+        }
+
+        public Map<T, Set<T>> edges() {
+            return edges;
+        }
+
+        public Set<T> adjacentNodes(T u) {
+            return edges.get(u);
+        }
+
+        public boolean contains(T u) {
+            return nodes.contains(u);
+        }
+
+        /**
+         * Returns nodes sorted in topological order.
+         */
+        public Stream<T> orderedNodes() {
+            TopoSorter<T> sorter = new TopoSorter<>(this);
+            return sorter.result.stream();
+        }
+
+        /**
+         * Traverse this graph and performs the given action in topological order
+         */
+        public void ordered(Consumer<T> action) {
+            TopoSorter<T> sorter = new TopoSorter<>(this);
+            sorter.ordered(action);
+        }
+
+        /**
+         * Traverses this graph and performs the given action in reverse topological order
+         */
+        public void reverse(Consumer<T> action) {
+            TopoSorter<T> sorter = new TopoSorter<>(this);
+            sorter.reverse(action);
+        }
+
+        /**
+         * Returns a transposed graph from this graph
+         */
+        public Graph<T> transpose() {
+            Builder<T> builder = new Builder<>();
+            nodes.stream().forEach(builder::addNode);
+            // reverse edges
+            edges.keySet().forEach(u -> {
+                edges.get(u).stream()
+                    .forEach(v -> builder.addEdge(v, u));
+            });
+            return builder.build();
+        }
+
+        /**
+         * Returns all nodes reachable from the given root.
+         */
+        public Set<T> dfs(T root) {
+            return dfs(Set.of(root));
+        }
+
+        /**
+         * Returns all nodes reachable from the given set of roots.
+         */
+        public Set<T> dfs(Set<T> roots) {
+            Deque<T> deque = new LinkedList<>(roots);
+            Set<T> visited = new HashSet<>();
+            while (!deque.isEmpty()) {
+                T u = deque.pop();
+                if (!visited.contains(u)) {
+                    visited.add(u);
+                    if (contains(u)) {
+                        adjacentNodes(u).stream()
+                            .filter(v -> !visited.contains(v))
+                            .forEach(deque::push);
+                    }
+                }
+            }
+            return visited;
+        }
+
+        public void printGraph(PrintStream out) {
+            out.println("graph for " + nodes);
+            nodes.stream()
+                .forEach(u -> adjacentNodes(u).stream()
+                    .forEach(v -> out.format("  %s -> %s%n", u, v)));
+        }
+
+        static class Builder<T> {
+            final Set<T> nodes = new HashSet<>();
+            final Map<T, Set<T>> edges = new HashMap<>();
+
+            public void addNode(T node) {
+                if (nodes.contains(node)) {
+                    return;
+                }
+                nodes.add(node);
+                edges.computeIfAbsent(node, _e -> new HashSet<>());
+            }
+
+            public void addEdge(T u, T v) {
+                addNode(u);
+                addNode(v);
+                edges.get(u).add(v);
+            }
+
+            public Graph<T> build() {
+                return new Graph<T>(nodes, edges);
+            }
+        }
+    }
+
+    /**
+     * Topological sort
+     */
+    private static class TopoSorter<T> {
+        final Deque<T> result = new LinkedList<>();
+        final Deque<T> nodes;
+        final Graph<T> graph;
+
+        TopoSorter(Graph<T> graph) {
+            this.graph = graph;
+            this.nodes = new LinkedList<>(graph.nodes);
+            sort();
+        }
+
+        public void ordered(Consumer<T> action) {
+            result.iterator().forEachRemaining(action);
+        }
+
+        public void reverse(Consumer<T> action) {
+            result.descendingIterator().forEachRemaining(action);
+        }
+
+        private void sort() {
+            Deque<T> visited = new LinkedList<>();
+            Deque<T> done = new LinkedList<>();
+            T node;
+            while ((node = nodes.poll()) != null) {
+                if (!visited.contains(node)) {
+                    visit(node, visited, done);
+                }
+            }
+        }
+
+        private void visit(T node, Deque<T> visited, Deque<T> done) {
+            if (visited.contains(node)) {
+                if (!done.contains(node)) {
+                    throw new IllegalArgumentException("Cyclic detected: " +
+                        node + " " + graph.edges().get(node));
+                }
+                return;
+            }
+            visited.add(node);
+            graph.edges().get(node).stream()
+                .forEach(x -> visit(x, visited, done));
+            done.add(node);
+            result.addLast(node);
+        }
+    }
+}
--- a/jdk/src/java.base/share/native/libnet/net_util.c	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/java.base/share/native/libnet/net_util.c	Tue Jan 17 11:35:28 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -64,10 +64,10 @@
     preferIPv4Stack = (*env)->CallStaticBooleanMethod(env, iCls, mid, s);
 
     /*
-       Since we have initialized and loaded the Socket library we will
-       check now to whether we have IPv6 on this platform and if the
-       supporting socket APIs are available
-    */
+     * Since we have initialized and loaded the socket library we will
+     * check now whether we have IPv6 on this platform and if the
+     * supporting socket APIs are available
+     */
     IPv6_available = IPv6_supported() & (!preferIPv4Stack);
 
     /* check if SO_REUSEPORT is supported on this platform */
@@ -120,16 +120,16 @@
     return JNI_TRUE;
 }
 
-int getInet6Address_scopeid_set(JNIEnv *env, jobject iaObj) {
+jboolean getInet6Address_scopeid_set(JNIEnv *env, jobject iaObj) {
     jobject holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID);
-    CHECK_NULL_RETURN(holder, -1);
+    CHECK_NULL_RETURN(holder, JNI_FALSE);
     return (*env)->GetBooleanField(env, holder, ia6_scopeidsetID);
 }
 
-int getInet6Address_scopeid(JNIEnv *env, jobject iaObj) {
+unsigned int getInet6Address_scopeid(JNIEnv *env, jobject iaObj) {
     jobject holder = (*env)->GetObjectField(env, iaObj, ia6_holder6ID);
-    CHECK_NULL_RETURN(holder, -1);
-    return (*env)->GetIntField(env, holder, ia6_scopeidID);
+    CHECK_NULL_RETURN(holder, 0);
+    return (unsigned int)(*env)->GetIntField(env, holder, ia6_scopeidID);
 }
 
 jboolean setInet6Address_scopeid(JNIEnv *env, jobject iaObj, int scopeid) {
@@ -201,11 +201,10 @@
 }
 
 JNIEXPORT jobject JNICALL
-NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) {
+NET_SockaddrToInetAddress(JNIEnv *env, SOCKETADDRESS *sa, int *port) {
     jobject iaObj;
-    if (him->sa_family == AF_INET6) {
-        struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
-        jbyte *caddr = (jbyte *)&(him6->sin6_addr);
+    if (sa->sa.sa_family == AF_INET6) {
+        jbyte *caddr = (jbyte *)&sa->sa6.sin6_addr;
         if (NET_IsIPv4Mapped(caddr)) {
             int address;
             iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
@@ -214,42 +213,35 @@
             setInetAddress_addr(env, iaObj, address);
             setInetAddress_family(env, iaObj, java_net_InetAddress_IPv4);
         } else {
-            jint scope;
             jboolean ret;
             iaObj = (*env)->NewObject(env, ia6_class, ia6_ctrID);
             CHECK_NULL_RETURN(iaObj, NULL);
-            ret = setInet6Address_ipaddress(env, iaObj, (char *)&(him6->sin6_addr));
+            ret = setInet6Address_ipaddress(env, iaObj, (char *)&sa->sa6.sin6_addr);
             if (ret == JNI_FALSE)
                 return NULL;
             setInetAddress_family(env, iaObj, java_net_InetAddress_IPv6);
-            scope = getScopeID(him);
-            setInet6Address_scopeid(env, iaObj, scope);
+            setInet6Address_scopeid(env, iaObj, sa->sa6.sin6_scope_id);
         }
-        *port = ntohs(him6->sin6_port);
+        *port = ntohs(sa->sa6.sin6_port);
     } else {
-        struct sockaddr_in *him4 = (struct sockaddr_in *)him;
         iaObj = (*env)->NewObject(env, ia4_class, ia4_ctrID);
         CHECK_NULL_RETURN(iaObj, NULL);
         setInetAddress_family(env, iaObj, java_net_InetAddress_IPv4);
-        setInetAddress_addr(env, iaObj, ntohl(him4->sin_addr.s_addr));
-        *port = ntohs(him4->sin_port);
+        setInetAddress_addr(env, iaObj, ntohl(sa->sa4.sin_addr.s_addr));
+        *port = ntohs(sa->sa4.sin_port);
     }
     return iaObj;
 }
 
-JNIEXPORT jint JNICALL
-NET_SockaddrEqualsInetAddress(JNIEnv *env, struct sockaddr *him, jobject iaObj)
+JNIEXPORT jboolean JNICALL
+NET_SockaddrEqualsInetAddress(JNIEnv *env, SOCKETADDRESS *sa, jobject iaObj)
 {
-    jint family = AF_INET;
-
-    family = getInetAddress_family(env, iaObj) == java_net_InetAddress_IPv4 ?
-        AF_INET : AF_INET6;
-    if (him->sa_family == AF_INET6) {
-        struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
-        jbyte *caddrNew = (jbyte *)&(him6->sin6_addr);
+    jint family = getInetAddress_family(env, iaObj) ==
+        java_net_InetAddress_IPv4 ? AF_INET : AF_INET6;
+    if (sa->sa.sa_family == AF_INET6) {
+        jbyte *caddrNew = (jbyte *)&sa->sa6.sin6_addr;
         if (NET_IsIPv4Mapped(caddrNew)) {
-            int addrNew;
-            int addrCur;
+            int addrNew, addrCur;
             if (family == AF_INET6) {
                 return JNI_FALSE;
             }
@@ -262,26 +254,24 @@
             }
         } else {
             jbyte caddrCur[16];
-            int scope;
-
             if (family == AF_INET) {
                 return JNI_FALSE;
             }
-            scope = getInet6Address_scopeid(env, iaObj);
             getInet6Address_ipaddress(env, iaObj, (char *)caddrCur);
-            if (NET_IsEqual(caddrNew, caddrCur) && cmpScopeID(scope, him)) {
+            if (NET_IsEqual(caddrNew, caddrCur) &&
+                sa->sa6.sin6_scope_id == getInet6Address_scopeid(env, iaObj))
+            {
                 return JNI_TRUE;
             } else {
                 return JNI_FALSE;
             }
         }
     } else {
-        struct sockaddr_in *him4 = (struct sockaddr_in *)him;
         int addrNew, addrCur;
         if (family != AF_INET) {
             return JNI_FALSE;
         }
-        addrNew = ntohl(him4->sin_addr.s_addr);
+        addrNew = ntohl(sa->sa4.sin_addr.s_addr);
         addrCur = getInetAddress_addr(env, iaObj);
         if (addrNew == addrCur) {
             return JNI_TRUE;
@@ -291,6 +281,15 @@
     }
 }
 
+JNIEXPORT jint JNICALL
+NET_GetPortFromSockaddr(SOCKETADDRESS *sa) {
+    if (sa->sa.sa_family == AF_INET6) {
+        return ntohs(sa->sa6.sin6_port);
+    } else {
+        return ntohs(sa->sa4.sin_port);
+    }
+}
+
 unsigned short
 in_cksum(unsigned short *addr, int len) {
     int nleft = len;
--- a/jdk/src/java.base/share/native/libnet/net_util.h	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/java.base/share/native/libnet/net_util.h	Tue Jan 17 11:35:28 2017 -0800
@@ -63,8 +63,8 @@
  */
 extern jobject getInet6Address_scopeifname(JNIEnv *env, jobject ia6Obj);
 extern jboolean setInet6Address_scopeifname(JNIEnv *env, jobject ia6Obj, jobject scopeifname);
-extern int getInet6Address_scopeid_set(JNIEnv *env, jobject ia6Obj);
-extern int getInet6Address_scopeid(JNIEnv *env, jobject ia6Obj);
+extern jboolean getInet6Address_scopeid_set(JNIEnv *env, jobject ia6Obj);
+extern unsigned int getInet6Address_scopeid(JNIEnv *env, jobject ia6Obj);
 extern jboolean setInet6Address_scopeid(JNIEnv *env, jobject ia6Obj, int scopeid);
 extern jboolean getInet6Address_ipaddress(JNIEnv *env, jobject ia6Obj, char *dest);
 extern jboolean setInet6Address_ipaddress(JNIEnv *env, jobject ia6Obj, char *address);
@@ -132,24 +132,41 @@
 
 JNIEXPORT jint JNICALL reuseport_available();
 
+/**
+ * This function will fill a SOCKETADDRESS structure from an InetAddress
+ * object.
+ *
+ * The parameter 'sa' must point to valid storage of size
+ * 'sizeof(SOCKETADDRESS)'.
+ *
+ * The parameter 'len' is a pointer to an int and is used for returning
+ * the actual sockaddr length, e.g. 'sizeof(struct sockaddr_in)' or
+ * 'sizeof(struct sockaddr_in6)'.
+ *
+ * If the type of the InetAddress object is IPv6, the function will fill a
+ * sockaddr_in6 structure. IPv6 must be available in that case, otherwise an
+ * exception is thrown.
+ * In the case of an IPv4 InetAddress, when IPv6 is available and
+ * v4MappedAddress is TRUE, this method will fill a sockaddr_in6 structure
+ * containing an IPv4 mapped IPv6 address. Otherwise a sockaddr_in
+ * structure will be filled.
+ */
 JNIEXPORT int JNICALL
 NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port,
-                          struct sockaddr *him, int *len,
+                          SOCKETADDRESS *sa, int *len,
                           jboolean v4MappedAddress);
 
 JNIEXPORT jobject JNICALL
-NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port);
+NET_SockaddrToInetAddress(JNIEnv *env, SOCKETADDRESS *sa, int *port);
 
 void platformInit();
 
 void parseExclusiveBindProperty(JNIEnv *env);
 
-void NET_SetTrafficClass(struct sockaddr *him, int trafficClass);
+JNIEXPORT jint JNICALL NET_GetPortFromSockaddr(SOCKETADDRESS *sa);
 
-JNIEXPORT jint JNICALL NET_GetPortFromSockaddr(struct sockaddr *him);
-
-JNIEXPORT jint JNICALL
-NET_SockaddrEqualsInetAddress(JNIEnv *env,struct sockaddr *him, jobject iaObj);
+JNIEXPORT jboolean JNICALL
+NET_SockaddrEqualsInetAddress(JNIEnv *env, SOCKETADDRESS *sa, jobject iaObj);
 
 int NET_IsIPv4Mapped(jbyte* caddr);
 
@@ -172,7 +189,7 @@
 NET_SetSockOpt(int fd, int level, int opt, const void *arg, int len);
 
 JNIEXPORT int JNICALL
-NET_Bind(int fd, struct sockaddr *him, int len);
+NET_Bind(int fd, SOCKETADDRESS *sa, int len);
 
 JNIEXPORT int JNICALL
 NET_MapSocketOption(jint cmd, int *level, int *optname);
@@ -183,10 +200,6 @@
 JNIEXPORT jint JNICALL
 NET_EnableFastTcpLoopback(int fd);
 
-int getScopeID(struct sockaddr *);
-
-int cmpScopeID(unsigned int, struct sockaddr *);
-
 unsigned short in_cksum(unsigned short *addr, int len);
 
 jint NET_Wait(JNIEnv *env, jint fd, jint flags, jint timeout);
--- a/jdk/src/java.base/unix/native/libnet/Inet6AddressImpl.c	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/java.base/unix/native/libnet/Inet6AddressImpl.c	Tue Jan 17 11:35:28 2017 -0800
@@ -211,7 +211,8 @@
         {
             int port;
             int index = (family == AF_INET) ? i++ : j++;
-            jobject o = NET_SockaddrToInetAddress(env, iter->ifa_addr, &port);
+            jobject o = NET_SockaddrToInetAddress(env,
+                            (SOCKETADDRESS *)iter->ifa_addr, &port);
             if (!o) {
                 freeifaddrs(ifa);
                 if (!(*env)->ExceptionCheck(env))
--- a/jdk/src/java.base/unix/native/libnet/NetworkInterface.c	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/java.base/unix/native/libnet/NetworkInterface.c	Tue Jan 17 11:35:28 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -791,7 +791,7 @@
     int sock;
 
     sock = openSocket(env, AF_INET);
-    if (sock < 0 && (*env)->ExceptionOccurred(env)) {
+    if (sock < 0) {
         return NULL;
     }
 
@@ -809,7 +809,7 @@
     // so we have to call ipv6_available()
     if (ipv6_available()) {
         sock = openSocket(env, AF_INET6);
-        if (sock < 0 && (*env)->ExceptionOccurred(env)) {
+        if (sock < 0) {
             freeif(ifs);
             return NULL;
         }
--- a/jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c	Tue Jan 17 11:35:28 2017 -0800
@@ -99,7 +99,7 @@
         CHECK_NULL_RETURN(i_class, NULL);
     }
 
-    return ( (*env)->NewObject(env, i_class, i_ctrID, i) );
+    return (*env)->NewObject(env, i_class, i_ctrID, i);
 }
 
 /*
@@ -118,10 +118,9 @@
         CHECK_NULL_RETURN(b_class, NULL);
     }
 
-    return( (*env)->NewObject(env, b_class, b_ctrID, (jboolean)(b!=0)) );
+    return (*env)->NewObject(env, b_class, b_ctrID, (jboolean)(b != 0));
 }
 
-
 /*
  * Returns the fd for a PlainDatagramSocketImpl or -1
  * if closed.
@@ -134,7 +133,6 @@
     return (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 }
 
-
 /*
  * Class:     java_net_PlainDatagramSocketImpl
  * Method:    init
@@ -166,7 +164,6 @@
     initInetAddressIDs(env);
     JNU_CHECK_EXCEPTION(env);
     Java_java_net_NetworkInterface_init(env, 0);
-
 }
 
 /*
@@ -176,13 +173,13 @@
  */
 JNIEXPORT void JNICALL
 Java_java_net_PlainDatagramSocketImpl_bind0(JNIEnv *env, jobject this,
-                                           jint localport, jobject iaObj) {
+                                            jint localport, jobject iaObj) {
     /* fdObj is the FileDescriptor field on this */
     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
     /* fd is an int field on fdObj */
     int fd;
     int len = 0;
-    SOCKETADDRESS him;
+    SOCKETADDRESS sa;
     socklen_t slen = sizeof(SOCKETADDRESS);
 
     if (IS_NULL(fdObj)) {
@@ -199,12 +196,13 @@
     }
 
     /* bind */
-    if (NET_InetAddressToSockaddr(env, iaObj, localport, &him.sa, &len, JNI_TRUE) != 0) {
+    if (NET_InetAddressToSockaddr(env, iaObj, localport, &sa, &len,
+                                  JNI_TRUE) != 0) {
       return;
     }
-    setDefaultScopeID(env, &him.sa);
+    setDefaultScopeID(env, &sa.sa);
 
-    if (NET_Bind(fd, &him.sa, len) < 0)  {
+    if (NET_Bind(fd, &sa, len) < 0)  {
         if (errno == EADDRINUSE || errno == EADDRNOTAVAIL ||
             errno == EPERM || errno == EACCES) {
             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "BindException",
@@ -221,13 +219,13 @@
         /* Now that we're a connected socket, let's extract the port number
          * that the system chose for us and store it in the Socket object.
          */
-        if (getsockname(fd, &him.sa, &slen) == -1) {
+        if (getsockname(fd, &sa.sa, &slen) == -1) {
             JNU_ThrowByNameWithMessageAndLastError
                 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name");
             return;
         }
 
-        localport = NET_GetPortFromSockaddr(&him.sa);
+        localport = NET_GetPortFromSockaddr(&sa);
 
         (*env)->SetIntField(env, this, pdsi_localPortID, localport);
     } else {
@@ -263,7 +261,8 @@
         return;
     }
 
-    if (NET_InetAddressToSockaddr(env, address, port, &rmtaddr.sa, &len, JNI_TRUE) != 0) {
+    if (NET_InetAddressToSockaddr(env, address, port, &rmtaddr, &len,
+                                  JNI_TRUE) != 0) {
       return;
     }
 
@@ -290,6 +289,9 @@
 #if defined(__linux__) || defined(_ALLBSD_SOURCE)
     SOCKETADDRESS addr;
     socklen_t len;
+#if defined(__linux__)
+    int localPort = 0;
+#endif
 #endif
 
     if (IS_NULL(fdObj)) {
@@ -298,32 +300,31 @@
     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
 
 #if defined(__linux__) || defined(_ALLBSD_SOURCE)
-        memset(&addr, 0, sizeof(addr));
-        if (ipv6_available()) {
-            addr.sa6.sin6_family = AF_UNSPEC;
-            len = sizeof(struct sockaddr_in6);
-        } else {
-            addr.sa4.sin_family = AF_UNSPEC;
-            len = sizeof(struct sockaddr_in);
-        }
-        NET_Connect(fd, &addr.sa, len);
+    memset(&addr, 0, sizeof(addr));
+    if (ipv6_available()) {
+        addr.sa6.sin6_family = AF_UNSPEC;
+        len = sizeof(struct sockaddr_in6);
+    } else {
+        addr.sa4.sin_family = AF_UNSPEC;
+        len = sizeof(struct sockaddr_in);
+    }
+    NET_Connect(fd, &addr.sa, len);
 
-#ifdef __linux__
-        int localPort = 0;
-        if (getsockname(fd, &addr.sa, &len) == -1)
-            return;
+#if defined(__linux__)
+    if (getsockname(fd, &addr.sa, &len) == -1)
+        return;
 
-        localPort = NET_GetPortFromSockaddr(&addr.sa);
-        if (localPort == 0) {
-            localPort = (*env)->GetIntField(env, this, pdsi_localPortID);
-            if (addr.sa.sa_family == AF_INET6) {
-                addr.sa6.sin6_port = htons(localPort);
-            } else {
-                addr.sa4.sin_port = htons(localPort);
-            }
+    localPort = NET_GetPortFromSockaddr(&addr);
+    if (localPort == 0) {
+        localPort = (*env)->GetIntField(env, this, pdsi_localPortID);
+        if (addr.sa.sa_family == AF_INET6) {
+            addr.sa6.sin6_port = htons(localPort);
+        } else {
+            addr.sa4.sin_port = htons(localPort);
+        }
 
-            NET_Bind(fd, &addr.sa, len);
-        }
+        NET_Bind(fd, &addr, len);
+    }
 
 #endif
 #else
@@ -355,8 +356,9 @@
     /* The fdObj'fd */
     jint fd;
 
-    SOCKETADDRESS rmtaddr, *rmtaddrP = &rmtaddr;
-    int len;
+    SOCKETADDRESS rmtaddr;
+    struct sockaddr *rmtaddrP = 0;
+    int len = 0;
 
     if (IS_NULL(fdObj)) {
         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
@@ -382,15 +384,14 @@
     packetBufferOffset = (*env)->GetIntField(env, packet, dp_offsetID);
     packetBufferLen = (*env)->GetIntField(env, packet, dp_lengthID);
 
-    if (connected) {
-        /* arg to NET_Sendto () null in this case */
-        len = 0;
-        rmtaddrP = 0;
-    } else {
+    // arg to NET_Sendto() null, if connected
+    if (!connected) {
         packetPort = (*env)->GetIntField(env, packet, dp_portID);
-        if (NET_InetAddressToSockaddr(env, packetAddress, packetPort, &rmtaddr.sa, &len, JNI_TRUE) != 0) {
+        if (NET_InetAddressToSockaddr(env, packetAddress, packetPort, &rmtaddr,
+                                      &len, JNI_TRUE) != 0) {
             return;
         }
+        rmtaddrP = &rmtaddr.sa;
     }
     setDefaultScopeID(env, &rmtaddr.sa);
 
@@ -427,7 +428,7 @@
     (*env)->GetByteArrayRegion(env, packetBuffer, packetBufferOffset, packetBufferLen,
                                (jbyte *)fullPacket);
     if (trafficClass != 0 && ipv6_available()) {
-        NET_SetTrafficClass(&rmtaddr.sa, trafficClass);
+        NET_SetTrafficClass(&rmtaddr, trafficClass);
     }
 
     /*
@@ -437,8 +438,7 @@
      * ECONNREFUSED indicating that an ICMP port unreachable has
      * received.
      */
-    ret = NET_SendTo(fd, fullPacket, packetBufferLen, 0,
-                     (struct sockaddr *)rmtaddrP, len);
+    ret = NET_SendTo(fd, fullPacket, packetBufferLen, 0, rmtaddrP, len);
 
     if (ret < 0) {
         if (errno == ECONNREFUSED) {
@@ -510,7 +510,7 @@
 #ifdef __solaris__
         if (errno == ECONNREFUSED) {
             int orig_errno = errno;
-            (void) recv(fd, buf, 1, 0);
+            recv(fd, buf, 1, 0);
             errno = orig_errno;
         }
 #endif
@@ -528,7 +528,7 @@
         return 0;
     }
 
-    iaObj = NET_SockaddrToInetAddress(env, &rmtaddr.sa, &port);
+    iaObj = NET_SockaddrToInetAddress(env, &rmtaddr, &port);
     family = getInetAddress_family(env, iaObj) == java_net_InetAddress_IPv4 ?
         AF_INET : AF_INET6;
     if (family == AF_INET) { /* this API can't handle IPV6 addresses */
@@ -676,18 +676,18 @@
          */
         packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
         if (packetAddress != NULL) {
-            if (!NET_SockaddrEqualsInetAddress(env, &rmtaddr.sa, packetAddress)) {
+            if (!NET_SockaddrEqualsInetAddress(env, &rmtaddr, packetAddress)) {
                 /* force a new InetAddress to be created */
                 packetAddress = NULL;
             }
         }
         if (packetAddress == NULL) {
-            packetAddress = NET_SockaddrToInetAddress(env, &rmtaddr.sa, &port);
+            packetAddress = NET_SockaddrToInetAddress(env, &rmtaddr, &port);
             /* stuff the new Inetaddress in the packet */
             (*env)->SetObjectField(env, packet, dp_addressID, packetAddress);
         } else {
             /* only get the new port number */
-            port = NET_GetPortFromSockaddr(&rmtaddr.sa);
+            port = NET_GetPortFromSockaddr(&rmtaddr);
         }
         /* and fill in the data, remote address/port and such */
         (*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, n,
@@ -857,18 +857,19 @@
              */
             packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
             if (packetAddress != NULL) {
-                if (!NET_SockaddrEqualsInetAddress(env, &rmtaddr.sa, packetAddress)) {
+                if (!NET_SockaddrEqualsInetAddress(env, &rmtaddr,
+                                                   packetAddress)) {
                     /* force a new InetAddress to be created */
                     packetAddress = NULL;
                 }
             }
             if (packetAddress == NULL) {
-                packetAddress = NET_SockaddrToInetAddress(env, &rmtaddr.sa, &port);
+                packetAddress = NET_SockaddrToInetAddress(env, &rmtaddr, &port);
                 /* stuff the new Inetaddress in the packet */
                 (*env)->SetObjectField(env, packet, dp_addressID, packetAddress);
             } else {
                 /* only get the new port number */
-                port = NET_GetPortFromSockaddr(&rmtaddr.sa);
+                port = NET_GetPortFromSockaddr(&rmtaddr);
             }
             /* and fill in the data, remote address/port and such */
             (*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, n,
@@ -1040,6 +1041,7 @@
     /*
      * We need an ipv4 address here
      */
+    in.s_addr = 0;
     for (i = 0; i < len; i++) {
         addr = (*env)->GetObjectArrayElement(env, addrArray, i);
         if (getInetAddress_family(env, addr) == java_net_InetAddress_IPv4) {
@@ -1049,7 +1051,7 @@
     }
 
     if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
-                   (const char*)&in, sizeof(in)) < 0) {
+                   (const char *)&in, sizeof(in)) < 0) {
         JNU_ThrowByNameWithMessageAndLastError
             (env, JNU_JAVANETPKG "SocketException", "Error setting socket option");
     }
@@ -1670,17 +1672,17 @@
      */
     if (opt == java_net_SocketOptions_SO_BINDADDR) {
         /* find out local IP address */
-        SOCKETADDRESS him;
+        SOCKETADDRESS sa;
         socklen_t len = sizeof(SOCKETADDRESS);
         int port;
         jobject iaObj;
 
-        if (getsockname(fd, &him.sa, &len) == -1) {
+        if (getsockname(fd, &sa.sa, &len) == -1) {
             JNU_ThrowByNameWithMessageAndLastError
                 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name");
             return NULL;
         }
-        iaObj = NET_SockaddrToInetAddress(env, &him.sa, &port);
+        iaObj = NET_SockaddrToInetAddress(env, &sa, &port);
 
         return iaObj;
     }
@@ -1969,6 +1971,7 @@
                 mname.imr_multiaddr.s_addr = htonl(getInetAddress_addr(env, iaObj));
 #ifdef __linux__
                 mname.imr_address.s_addr = htonl(getInetAddress_addr(env, addr));
+                mname.imr_ifindex = 0;
 #else
                 mname.imr_interface.s_addr = htonl(getInetAddress_addr(env, addr));
 #endif
@@ -2023,7 +2026,7 @@
 
 #ifdef __linux__
                 mname.imr_address.s_addr = in.s_addr;
-
+                mname.imr_ifindex = 0;
 #else
                 mname.imr_interface.s_addr = in.s_addr;
 #endif
--- a/jdk/src/java.base/unix/native/libnet/PlainSocketImpl.c	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/java.base/unix/native/libnet/PlainSocketImpl.c	Tue Jan 17 11:35:28 2017 -0800
@@ -244,7 +244,7 @@
     /* fd is an int field on iaObj */
     jint fd;
 
-    SOCKETADDRESS him;
+    SOCKETADDRESS sa;
     /* The result of the connection */
     int connect_rv = -1;
 
@@ -260,17 +260,18 @@
     }
 
     /* connect */
-    if (NET_InetAddressToSockaddr(env, iaObj, port, &him.sa, &len, JNI_TRUE) != 0) {
+    if (NET_InetAddressToSockaddr(env, iaObj, port, &sa, &len,
+                                  JNI_TRUE) != 0) {
         return;
     }
-    setDefaultScopeID(env, &him.sa);
+    setDefaultScopeID(env, &sa.sa);
 
     if (trafficClass != 0 && ipv6_available()) {
-        NET_SetTrafficClass(&him.sa, trafficClass);
+        NET_SetTrafficClass(&sa, trafficClass);
     }
 
     if (timeout <= 0) {
-        connect_rv = NET_Connect(fd, &him.sa, len);
+        connect_rv = NET_Connect(fd, &sa.sa, len);
 #ifdef __solaris__
         if (connect_rv == -1 && errno == EINPROGRESS ) {
 
@@ -319,7 +320,7 @@
         SET_NONBLOCKING(fd);
 
         /* no need to use NET_Connect as non-blocking */
-        connect_rv = connect(fd, &him.sa, len);
+        connect_rv = connect(fd, &sa.sa, len);
 
         /* connection not established immediately */
         if (connect_rv != 0) {
@@ -467,11 +468,11 @@
          * that the system chose for us and store it in the Socket object.
          */
         socklen_t slen = sizeof(SOCKETADDRESS);
-        if (getsockname(fd, &him.sa, &slen) == -1) {
+        if (getsockname(fd, &sa.sa, &slen) == -1) {
             JNU_ThrowByNameWithMessageAndLastError
                 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name");
         } else {
-            localport = NET_GetPortFromSockaddr(&him.sa);
+            localport = NET_GetPortFromSockaddr(&sa);
             (*env)->SetIntField(env, this, psi_localportID, localport);
         }
     }
@@ -490,8 +491,8 @@
     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
     /* fd is an int field on fdObj */
     int fd;
-    int len;
-    SOCKETADDRESS him;
+    int len = 0;
+    SOCKETADDRESS sa;
 
     if (IS_NULL(fdObj)) {
         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
@@ -506,13 +507,13 @@
     }
 
     /* bind */
-    if (NET_InetAddressToSockaddr(env, iaObj, localport, &him.sa,
+    if (NET_InetAddressToSockaddr(env, iaObj, localport, &sa,
                                   &len, JNI_TRUE) != 0) {
         return;
     }
-    setDefaultScopeID(env, &him.sa);
+    setDefaultScopeID(env, &sa.sa);
 
-    if (NET_Bind(fd, &him.sa, len) < 0) {
+    if (NET_Bind(fd, &sa, len) < 0) {
         if (errno == EADDRINUSE || errno == EADDRNOTAVAIL ||
             errno == EPERM || errno == EACCES) {
             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "BindException",
@@ -533,12 +534,12 @@
         /* Now that we're a connected socket, let's extract the port number
          * that the system chose for us and store it in the Socket object.
          */
-        if (getsockname(fd, &him.sa, &slen) == -1) {
+        if (getsockname(fd, &sa.sa, &slen) == -1) {
             JNU_ThrowByNameWithMessageAndLastError
                 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name");
             return;
         }
-        localport = NET_GetPortFromSockaddr(&him.sa);
+        localport = NET_GetPortFromSockaddr(&sa);
         (*env)->SetIntField(env, this, psi_localportID, localport);
     } else {
         (*env)->SetIntField(env, this, psi_localportID, localport);
@@ -606,7 +607,7 @@
     /* accepted fd */
     jint newfd;
 
-    SOCKETADDRESS him;
+    SOCKETADDRESS sa;
     socklen_t slen = sizeof(SOCKETADDRESS);
 
     if (IS_NULL(fdObj)) {
@@ -661,7 +662,7 @@
             return;
         }
 
-        newfd = NET_Accept(fd, &him.sa, &slen);
+        newfd = NET_Accept(fd, &sa.sa, &slen);
 
         /* connection accepted */
         if (newfd >= 0) {
@@ -709,7 +710,7 @@
     /*
      * fill up the remote peer port and address in the new socket structure.
      */
-    socketAddressObj = NET_SockaddrToInetAddress(env, &him.sa, &port);
+    socketAddressObj = NET_SockaddrToInetAddress(env, &sa, &port);
     if (socketAddressObj == NULL) {
         /* should be pending exception */
         close(newfd);
@@ -944,19 +945,19 @@
      * SO_BINDADDR isn't a socket option
      */
     if (cmd == java_net_SocketOptions_SO_BINDADDR) {
-        SOCKETADDRESS him;
+        SOCKETADDRESS sa;
         socklen_t len = sizeof(SOCKETADDRESS);
         int port;
         jobject iaObj;
         jclass iaCntrClass;
         jfieldID iaFieldID;
 
-        if (getsockname(fd, &him.sa, &len) < 0) {
+        if (getsockname(fd, &sa.sa, &len) < 0) {
             JNU_ThrowByNameWithMessageAndLastError
                 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name");
             return -1;
         }
-        iaObj = NET_SockaddrToInetAddress(env, &him.sa, &port);
+        iaObj = NET_SockaddrToInetAddress(env, &sa, &port);
         CHECK_NULL_RETURN(iaObj, -1);
 
         iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj);
--- a/jdk/src/java.base/unix/native/libnet/net_util_md.c	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/java.base/unix/native/libnet/net_util_md.c	Tue Jan 17 11:35:28 2017 -0800
@@ -234,29 +234,6 @@
     }
     return kernelV24;
 }
-
-int getScopeID (struct sockaddr *him) {
-    struct sockaddr_in6 *hext = (struct sockaddr_in6 *)him;
-    return hext->sin6_scope_id;
-}
-
-int cmpScopeID (unsigned int scope, struct sockaddr *him) {
-    struct sockaddr_in6 *hext = (struct sockaddr_in6 *)him;
-    return hext->sin6_scope_id == scope;
-}
-
-#else
-
-int getScopeID (struct sockaddr *him) {
-    struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
-    return him6->sin6_scope_id;
-}
-
-int cmpScopeID (unsigned int scope, struct sockaddr *him) {
-    struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
-    return him6->sin6_scope_id == scope;
-}
-
 #endif
 
 void
@@ -775,30 +752,32 @@
     return 0;
 }
 
-/* In the case of an IPv4 Inetaddress this method will return an
- * IPv4 mapped address where IPv6 is available and v4MappedAddress is TRUE.
- * Otherwise it will return a sockaddr_in structure for an IPv4 InetAddress.
-*/
+/**
+ * See net_util.h for documentation
+ */
 JNIEXPORT int JNICALL
-NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr *him,
-                          int *len, jboolean v4MappedAddress) {
-    jint family;
-    family = getInetAddress_family(env, iaObj);
-    /* needs work. 1. family 2. clean up him6 etc deallocate memory */
-    if (ipv6_available() && !(family == java_net_InetAddress_IPv4 &&
-                              v4MappedAddress == JNI_FALSE)) {
-        struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
+NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port,
+                          SOCKETADDRESS *sa, int *len,
+                          jboolean v4MappedAddress)
+{
+    jint family = getInetAddress_family(env, iaObj);
+    memset((char *)sa, 0, sizeof(SOCKETADDRESS));
+
+    if (ipv6_available() &&
+        !(family == java_net_InetAddress_IPv4 &&
+          v4MappedAddress == JNI_FALSE))
+    {
         jbyte caddr[16];
         jint address;
 
         if (family == java_net_InetAddress_IPv4) {
             // convert to IPv4-mapped address
-            memset((char *) caddr, 0, 16);
+            memset((char *)caddr, 0, 16);
             address = getInetAddress_addr(env, iaObj);
             if (address == INADDR_ANY) {
                 /* we would always prefer IPv6 wildcard address
-                   caddr[10] = 0xff;
-                   caddr[11] = 0xff; */
+                 * caddr[10] = 0xff;
+                 * caddr[11] = 0xff; */
             } else {
                 caddr[10] = 0xff;
                 caddr[11] = 0xff;
@@ -810,22 +789,19 @@
         } else {
             getInet6Address_ipaddress(env, iaObj, (char *)caddr);
         }
-        memset((char *)him6, 0, sizeof(struct sockaddr_in6));
-        him6->sin6_port = htons(port);
-        memcpy((void *)&(him6->sin6_addr), caddr, sizeof(struct in6_addr) );
-        him6->sin6_family = AF_INET6;
-        *len = sizeof(struct sockaddr_in6);
+        sa->sa6.sin6_port = htons(port);
+        memcpy((void *)&sa->sa6.sin6_addr, caddr, sizeof(struct in6_addr));
+        sa->sa6.sin6_family = AF_INET6;
+        if (len != NULL) {
+            *len = sizeof(struct sockaddr_in6);
+        }
 
-#if defined(_ALLBSD_SOURCE)
-// XXXBSD: should we do something with scope id here ? see below linux comment
-/* MMM: Come back to this! */
-#endif
-
+#ifdef __linux__
         /*
          * On Linux if we are connecting to a link-local address
          * we need to specify the interface in the scope_id (2.4 kernel only)
          *
-         * If the scope was cached the we use the cached value. If not cached but
+         * If the scope was cached then we use the cached value. If not cached but
          * specified in the Inet6Address we use that, but we first check if the
          * address needs to be routed via the loopback interface. In this case,
          * we override the specified value with that of the loopback interface.
@@ -833,9 +809,8 @@
          * we try to determine a value from the routing table. In all these
          * cases the used value is cached for further use.
          */
-#ifdef __linux__
-        if (IN6_IS_ADDR_LINKLOCAL(&(him6->sin6_addr))) {
-            int cached_scope_id = 0, scope_id = 0;
+        if (IN6_IS_ADDR_LINKLOCAL(&sa->sa6.sin6_addr)) {
+            unsigned int cached_scope_id = 0, scope_id = 0;
 
             if (ia6_cachedscopeidID) {
                 cached_scope_id = (int)(*env)->GetIntField(env, iaObj, ia6_cachedscopeidID);
@@ -850,7 +825,7 @@
                         /* check user-specified value for loopback case
                          * that needs to be overridden
                          */
-                        if (kernelIsV24() && needsLoopbackRoute (&him6->sin6_addr)) {
+                        if (kernelIsV24() && needsLoopbackRoute(&sa->sa6.sin6_addr)) {
                             cached_scope_id = lo_scope_id;
                             (*env)->SetIntField(env, iaObj, ia6_cachedscopeidID, cached_scope_id);
                         }
@@ -860,11 +835,11 @@
                          * try determine the appropriate interface.
                          */
                         if (kernelIsV24()) {
-                            cached_scope_id = getDefaultIPv6Interface(&(him6->sin6_addr));
+                            cached_scope_id = getDefaultIPv6Interface(&sa->sa6.sin6_addr);
                         } else {
-                            cached_scope_id = getLocalScopeID((char *)&(him6->sin6_addr));
+                            cached_scope_id = getLocalScopeID((char *)&(sa->sa6.sin6_addr));
                             if (cached_scope_id == 0) {
-                                cached_scope_id = getDefaultIPv6Interface(&(him6->sin6_addr));
+                                cached_scope_id = getDefaultIPv6Interface(&sa->sa6.sin6_addr);
                             }
                         }
                         (*env)->SetIntField(env, iaObj, ia6_cachedscopeidID, cached_scope_id);
@@ -876,53 +851,37 @@
              * If we have a scope_id use the extended form
              * of sockaddr_in6.
              */
-
-            struct sockaddr_in6 *him6 =
-                    (struct sockaddr_in6 *)him;
-            him6->sin6_scope_id = cached_scope_id != 0 ?
-                                        cached_scope_id    : scope_id;
-            *len = sizeof(struct sockaddr_in6);
+            sa->sa6.sin6_scope_id = cached_scope_id == 0 ? scope_id : cached_scope_id;
         }
 #else
-        /* handle scope_id for solaris */
-
+        /* handle scope_id */
         if (family != java_net_InetAddress_IPv4) {
             if (ia6_scopeidID) {
-                him6->sin6_scope_id = getInet6Address_scopeid(env, iaObj);
+                sa->sa6.sin6_scope_id = getInet6Address_scopeid(env, iaObj);
             }
         }
 #endif
     } else {
-        struct sockaddr_in *him4 = (struct sockaddr_in *)him;
         jint address;
-        if (family == java_net_InetAddress_IPv6) {
+        if (family != java_net_InetAddress_IPv4) {
             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Protocol family unavailable");
             return -1;
         }
-        memset((char *)him4, 0, sizeof(struct sockaddr_in));
         address = getInetAddress_addr(env, iaObj);
-        him4->sin_port = htons((short) port);
-        him4->sin_addr.s_addr = htonl(address);
-        him4->sin_family = AF_INET;
-        *len = sizeof(struct sockaddr_in);
+        sa->sa4.sin_port = htons(port);
+        sa->sa4.sin_addr.s_addr = htonl(address);
+        sa->sa4.sin_family = AF_INET;
+        if (len != NULL) {
+            *len = sizeof(struct sockaddr_in);
+        }
     }
     return 0;
 }
 
 void
-NET_SetTrafficClass(struct sockaddr *him, int trafficClass) {
-    if (him->sa_family == AF_INET6) {
-        struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
-        him6->sin6_flowinfo = htonl((trafficClass & 0xff) << 20);
-    }
-}
-
-JNIEXPORT jint JNICALL
-NET_GetPortFromSockaddr(struct sockaddr *him) {
-    if (him->sa_family == AF_INET6) {
-        return ntohs(((struct sockaddr_in6*)him)->sin6_port);
-    } else {
-        return ntohs(((struct sockaddr_in*)him)->sin_port);
+NET_SetTrafficClass(SOCKETADDRESS *sa, int trafficClass) {
+    if (sa->sa.sa_family == AF_INET6) {
+        sa->sa6.sin6_flowinfo = htonl((trafficClass & 0xff) << 20);
     }
 }
 
@@ -1488,7 +1447,7 @@
  *
  */
 int
-NET_Bind(int fd, struct sockaddr *him, int len)
+NET_Bind(int fd, SOCKETADDRESS *sa, int len)
 {
 #if defined(__solaris__)
     int level = -1;
@@ -1503,9 +1462,8 @@
      * ## When IPv6 is enabled this will be an IPv4-mapped
      * ## with family set to AF_INET6
      */
-    if (him->sa_family == AF_INET) {
-        struct sockaddr_in *sa = (struct sockaddr_in *)him;
-        if ((ntohl(sa->sin_addr.s_addr) & 0x7f0000ff) == 0x7f0000ff) {
+    if (sa->sa.sa_family == AF_INET) {
+        if ((ntohl(sa->sa4.sin_addr.s_addr) & 0x7f0000ff) == 0x7f0000ff) {
             errno = EADDRNOTAVAIL;
             return -1;
         }
@@ -1524,8 +1482,9 @@
      */
     alen = sizeof(arg);
 
-    if (useExclBind || getsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
-                   (char *)&arg, &alen) == 0) {
+    if (useExclBind ||
+        getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&arg, &alen) == 0)
+    {
         if (useExclBind || arg == 0) {
             /*
              * SO_REUSEADDR is disabled or sun.net.useExclusiveBind
@@ -1533,8 +1492,8 @@
              * UDP_EXCLBIND
              */
             alen = sizeof(arg);
-            if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&arg,
-                           &alen) == 0) {
+            if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&arg, &alen) == 0)
+            {
                 if (arg == SOCK_STREAM) {
                     level = IPPROTO_TCP;
                     exclbind = TCP_EXCLBIND;
@@ -1545,14 +1504,13 @@
             }
 
             arg = 1;
-            setsockopt(fd, level, exclbind, (char *)&arg,
-                       sizeof(arg));
+            setsockopt(fd, level, exclbind, (char *)&arg, sizeof(arg));
         }
     }
 
 #endif
 
-    rv = bind(fd, him, len);
+    rv = bind(fd, &sa->sa, len);
 
 #if defined(__solaris__)
     if (rv < 0) {
--- a/jdk/src/java.base/unix/native/libnet/net_util_md.h	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/java.base/unix/native/libnet/net_util_md.h	Tue Jan 17 11:35:28 2017 -0800
@@ -30,32 +30,6 @@
 #include <sys/poll.h>
 #include <sys/socket.h>
 
-int NET_Timeout(int s, long timeout);
-int NET_Timeout0(int s, long timeout, long currentTime);
-int NET_Read(int s, void* buf, size_t len);
-int NET_NonBlockingRead(int s, void* buf, size_t len);
-int NET_TimeoutWithCurrentTime(int s, long timeout, long currentTime);
-long NET_GetCurrentTime();
-int NET_RecvFrom(int s, void *buf, int len, unsigned int flags,
-                 struct sockaddr *from, socklen_t *fromlen);
-int NET_ReadV(int s, const struct iovec * vector, int count);
-int NET_Send(int s, void *msg, int len, unsigned int flags);
-int NET_SendTo(int s, const void *msg, int len,  unsigned  int
-               flags, const struct sockaddr *to, int tolen);
-int NET_Writev(int s, const struct iovec * vector, int count);
-int NET_Connect(int s, struct sockaddr *addr, int addrlen);
-int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen);
-int NET_SocketClose(int s);
-int NET_Dup2(int oldfd, int newfd);
-int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout);
-int NET_SocketAvailable(int s, jint *pbytes);
-
-void NET_ThrowUnknownHostExceptionWithGaiError(JNIEnv *env,
-                                               const char* hostname,
-                                               int gai_error);
-void NET_ThrowByNameWithLastError(JNIEnv *env, const char *name,
-                                  const char *defaultDetail);
-
 /************************************************************************
  * Macros and constants
  */
@@ -91,9 +65,36 @@
 } SOCKETADDRESS;
 
 /************************************************************************
- *  Utilities
+ * Functions
  */
 
+int NET_Timeout(int s, long timeout);
+int NET_Timeout0(int s, long timeout, long currentTime);
+int NET_Read(int s, void* buf, size_t len);
+int NET_NonBlockingRead(int s, void* buf, size_t len);
+int NET_TimeoutWithCurrentTime(int s, long timeout, long currentTime);
+long NET_GetCurrentTime();
+int NET_RecvFrom(int s, void *buf, int len, unsigned int flags,
+                 struct sockaddr *from, socklen_t *fromlen);
+int NET_ReadV(int s, const struct iovec * vector, int count);
+int NET_Send(int s, void *msg, int len, unsigned int flags);
+int NET_SendTo(int s, const void *msg, int len,  unsigned  int
+               flags, const struct sockaddr *to, int tolen);
+int NET_Writev(int s, const struct iovec * vector, int count);
+int NET_Connect(int s, struct sockaddr *addr, int addrlen);
+int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen);
+int NET_SocketClose(int s);
+int NET_Dup2(int oldfd, int newfd);
+int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout);
+int NET_SocketAvailable(int s, jint *pbytes);
+
+void NET_ThrowUnknownHostExceptionWithGaiError(JNIEnv *env,
+                                               const char* hostname,
+                                               int gai_error);
+void NET_ThrowByNameWithLastError(JNIEnv *env, const char *name,
+                                  const char *defaultDetail);
+void NET_SetTrafficClass(SOCKETADDRESS *sa, int trafficClass);
+
 #ifdef __linux__
 int kernelIsV24();
 int getDefaultIPv6Interface(struct in6_addr *target_addr);
--- a/jdk/src/java.base/unix/native/libnio/ch/DatagramChannelImpl.c	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/java.base/unix/native/libnio/ch/DatagramChannelImpl.c	Tue Jan 17 11:35:28 2017 -0800
@@ -181,11 +181,11 @@
      */
     senderAddr = (*env)->GetObjectField(env, this, dci_senderAddrID);
     if (senderAddr != NULL) {
-        if (!NET_SockaddrEqualsInetAddress(env, &sa.sa, senderAddr)) {
+        if (!NET_SockaddrEqualsInetAddress(env, &sa, senderAddr)) {
             senderAddr = NULL;
         } else {
             jint port = (*env)->GetIntField(env, this, dci_senderPortID);
-            if (port != NET_GetPortFromSockaddr(&sa.sa)) {
+            if (port != NET_GetPortFromSockaddr(&sa)) {
                 senderAddr = NULL;
             }
         }
@@ -193,7 +193,7 @@
     if (senderAddr == NULL) {
         jobject isa = NULL;
         int port = 0;
-        jobject ia = NET_SockaddrToInetAddress(env, &sa.sa, &port);
+        jobject ia = NET_SockaddrToInetAddress(env, &sa, &port);
         if (ia != NULL) {
             isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
         }
@@ -201,7 +201,7 @@
 
         (*env)->SetObjectField(env, this, dci_senderAddrID, ia);
         (*env)->SetIntField(env, this, dci_senderPortID,
-                            NET_GetPortFromSockaddr(&sa.sa));
+                            NET_GetPortFromSockaddr(&sa));
         (*env)->SetObjectField(env, this, dci_senderID, isa);
     }
     return n;
@@ -215,14 +215,14 @@
     jint fd = fdval(env, fdo);
     void *buf = (void *)jlong_to_ptr(address);
     SOCKETADDRESS sa;
-    int sa_len = sizeof(SOCKETADDRESS);
+    int sa_len = 0;
     jint n = 0;
 
     if (len > MAX_PACKET_LEN) {
         len = MAX_PACKET_LEN;
     }
 
-    if (NET_InetAddressToSockaddr(env, destAddress, destPort, &sa.sa,
+    if (NET_InetAddressToSockaddr(env, destAddress, destPort, &sa,
                                   &sa_len, preferIPv6) != 0) {
       return IOS_THROWN;
     }
--- a/jdk/src/java.base/unix/native/libnio/ch/InheritedChannel.c	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/java.base/unix/native/libnio/ch/InheritedChannel.c	Tue Jan 17 11:35:28 2017 -0800
@@ -64,7 +64,7 @@
 
     if (getpeername(fd, &sa.sa, &len) == 0) {
         if (matchFamily(&sa.sa)) {
-            remote_ia = NET_SockaddrToInetAddress(env, &sa.sa, (int *)&remote_port);
+            remote_ia = NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port);
         }
     }
 
@@ -81,7 +81,7 @@
 
     if (getpeername(fd, &sa.sa, &len) == 0) {
         if (matchFamily(&sa.sa)) {
-            NET_SockaddrToInetAddress(env, &sa.sa, (int *)&remote_port);
+            NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port);
         }
     }
 
--- a/jdk/src/java.base/unix/native/libnio/ch/Net.c	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/java.base/unix/native/libnio/ch/Net.c	Tue Jan 17 11:35:28 2017 -0800
@@ -274,15 +274,15 @@
                           jboolean useExclBind, jobject iao, int port)
 {
     SOCKETADDRESS sa;
-    int sa_len = sizeof(SOCKETADDRESS);
+    int sa_len = 0;
     int rv = 0;
 
-    if (NET_InetAddressToSockaddr(env, iao, port, &sa.sa, &sa_len,
+    if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len,
                                   preferIPv6) != 0) {
         return;
     }
 
-    rv = NET_Bind(fdval(env, fdo), &sa.sa, sa_len);
+    rv = NET_Bind(fdval(env, fdo), &sa, sa_len);
     if (rv != 0) {
         handleSocketError(env, errno);
     }
@@ -300,10 +300,10 @@
                              jobject fdo, jobject iao, jint port)
 {
     SOCKETADDRESS sa;
-    int sa_len = sizeof(SOCKETADDRESS);
+    int sa_len = 0;
     int rv;
 
-    if (NET_InetAddressToSockaddr(env, iao, port, &sa.sa, &sa_len,
+    if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len,
                                   preferIPv6) != 0) {
         return IOS_THROWN;
     }
@@ -349,7 +349,7 @@
         return -1;
 #endif /* _ALLBSD_SOURCE */
     }
-    return NET_GetPortFromSockaddr(&sa.sa);
+    return NET_GetPortFromSockaddr(&sa);
 }
 
 JNIEXPORT jobject JNICALL
@@ -382,7 +382,7 @@
         return NULL;
 #endif /* _ALLBSD_SOURCE */
     }
-    return NET_SockaddrToInetAddress(env, &sa.sa, &port);
+    return NET_SockaddrToInetAddress(env, &sa, &port);
 }
 
 JNIEXPORT jint JNICALL
--- a/jdk/src/java.base/unix/native/libnio/ch/ServerSocketChannelImpl.c	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/java.base/unix/native/libnio/ch/ServerSocketChannelImpl.c	Tue Jan 17 11:35:28 2017 -0800
@@ -112,7 +112,7 @@
     }
 
     (*env)->SetIntField(env, newfdo, fd_fdID, newfd);
-    remote_ia = NET_SockaddrToInetAddress(env, &sa.sa, (int *)&remote_port);
+    remote_ia = NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port);
     CHECK_NULL_RETURN(remote_ia, IOS_THROWN);
     isa = (*env)->NewObject(env, isa_class, isa_ctorID, remote_ia, remote_port);
     CHECK_NULL_RETURN(isa, IOS_THROWN);
--- a/jdk/src/java.base/windows/classes/java/io/WinNTFileSystem.java	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/java.base/windows/classes/java/io/WinNTFileSystem.java	Tue Jan 17 11:35:28 2017 -0800
@@ -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
@@ -233,11 +233,14 @@
         int childStart = 0;
         int parentEnd = pn;
 
+        boolean isDirectoryRelative =
+            pn == 2 && isLetter(parent.charAt(0)) && parent.charAt(1) == ':';
+
         if ((cn > 1) && (c.charAt(0) == slash)) {
             if (c.charAt(1) == slash) {
                 /* Drop prefix when child is a UNC pathname */
                 childStart = 2;
-            } else {
+            } else if (!isDirectoryRelative) {
                 /* Drop prefix when child is drive-relative */
                 childStart = 1;
 
@@ -254,7 +257,7 @@
 
         int strlen = parentEnd + cn - childStart;
         char[] theChars = null;
-        if (child.charAt(childStart) == slash) {
+        if (child.charAt(childStart) == slash || isDirectoryRelative) {
             theChars = new char[strlen];
             parent.getChars(0, parentEnd, theChars, 0);
             child.getChars(childStart, cn, theChars, parentEnd);
--- a/jdk/src/java.base/windows/native/libnet/DualStackPlainDatagramSocketImpl.c	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/java.base/windows/native/libnet/DualStackPlainDatagramSocketImpl.c	Tue Jan 17 11:35:28 2017 -0800
@@ -53,7 +53,7 @@
             break;
         }
         if (recvfrom(fd, buf, 1, MSG_PEEK,
-                         (struct sockaddr *)&rmtaddr, &addrlen) != SOCKET_ERROR) {
+                     &rmtaddr.sa, &addrlen) != SOCKET_ERROR) {
             break;
         }
         if (WSAGetLastError() != WSAECONNRESET) {
@@ -61,7 +61,7 @@
             break;
         }
 
-        recvfrom(fd, buf, 1, 0,  (struct sockaddr *)&rmtaddr, &addrlen);
+        recvfrom(fd, buf, 1, 0, &rmtaddr.sa, &addrlen);
         got_icmp = JNI_TRUE;
     }
 
@@ -134,14 +134,13 @@
 JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketBind
   (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port, jboolean exclBind) {
     SOCKETADDRESS sa;
-    int rv;
-    int sa_len = sizeof(sa);
+    int rv, sa_len = 0;
 
-    if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&sa,
+    if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
                                  &sa_len, JNI_TRUE) != 0) {
         return;
     }
-    rv = NET_WinBind(fd, (struct sockaddr *)&sa, sa_len, exclBind);
+    rv = NET_WinBind(fd, &sa, sa_len, exclBind);
 
     if (rv == SOCKET_ERROR) {
         if (WSAGetLastError() == WSAEACCES) {
@@ -159,17 +158,15 @@
 JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketConnect
   (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) {
     SOCKETADDRESS sa;
-    int rv;
-    int sa_len = sizeof(sa);
+    int rv, sa_len = 0, t = TRUE;
     DWORD x1, x2; /* ignored result codes */
-    int t = TRUE;
 
-    if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&sa,
+    if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
                                    &sa_len, JNI_TRUE) != 0) {
         return;
     }
 
-    rv = connect(fd, (struct sockaddr *)&sa, sa_len);
+    rv = connect(fd, &sa.sa, sa_len);
     if (rv == SOCKET_ERROR) {
         NET_ThrowNew(env, WSAGetLastError(), "connect");
         return;
@@ -192,7 +189,7 @@
     int t = FALSE;
 
     memset(&sa, 0, sa_len);
-    connect(fd, (struct sockaddr *)&sa, sa_len);
+    connect(fd, &sa.sa, sa_len);
 
     /* see comment in socketCreate */
     WSAIoctl(fd, SIO_UDP_CONNRESET, &t, sizeof(t), &x1, sizeof(x1), &x2, 0, 0);
@@ -219,7 +216,7 @@
     SOCKETADDRESS sa;
     int len = sizeof(sa);
 
-    if (getsockname(fd, (struct sockaddr *)&sa, &len) == SOCKET_ERROR) {
+    if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) {
         NET_ThrowNew(env, WSAGetLastError(), "getsockname");
         return -1;
     }
@@ -238,12 +235,12 @@
     jobject iaObj;
     int port;
 
-    if (getsockname(fd, (struct sockaddr *)&sa, &len) == SOCKET_ERROR) {
+    if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) {
         NET_ThrowNew(env, WSAGetLastError(), "Error getting socket name");
         return NULL;
     }
 
-    iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);
+    iaObj = NET_SockaddrToInetAddress(env, &sa, &port);
     return iaObj;
 }
 
@@ -316,7 +313,7 @@
 
         /* receive the packet */
         rv = recvfrom(fd, fullPacket, packetBufferLen, flags,
-                    (struct sockaddr *)&sa, &sa_len);
+                      &sa.sa, &sa_len);
 
         if (rv == SOCKET_ERROR && (WSAGetLastError() == WSAECONNRESET)) {
             /* An icmp port unreachable - we must receive this as Windows
@@ -383,15 +380,13 @@
          */
         packetAddress = (*env)->GetObjectField(env, dpObj, dp_addressID);
         if (packetAddress != NULL) {
-            if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&sa,
-                                               packetAddress)) {
+            if (!NET_SockaddrEqualsInetAddress(env, &sa, packetAddress)) {
                 /* force a new InetAddress to be created */
                 packetAddress = NULL;
             }
         }
         if (packetAddress == NULL) {
-            packetAddress = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa,
-                                                      &port);
+            packetAddress = NET_SockaddrToInetAddress(env, &sa, &port);
             if (packetAddress != NULL) {
                 /* stuff the new Inetaddress into the packet */
                 (*env)->SetObjectField(env, dpObj, dp_addressID, packetAddress);
@@ -422,20 +417,18 @@
   (JNIEnv *env, jclass clazz, jint fd, jbyteArray data, jint offset, jint length,
      jobject iaObj, jint port, jboolean connected) {
     SOCKETADDRESS sa;
-    int sa_len = sizeof(sa);
-    SOCKETADDRESS *sap = &sa;
+    int rv, sa_len = 0;
+    struct sockaddr *sap = 0;
     char BUF[MAX_BUFFER_LEN];
     char *fullPacket;
-    int rv;
 
-    if (connected) {
-        sap = 0; /* arg to sendto () null in this case */
-        sa_len = 0;
-    } else {
-        if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&sa,
-                                       &sa_len, JNI_TRUE) != 0) {
+    // if already connected, sap arg to sendto() is null
+    if (!connected) {
+        if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
+                                      &sa_len, JNI_TRUE) != 0) {
             return;
         }
+        sap = &sa.sa;
     }
 
     if (length > MAX_BUFFER_LEN) {
@@ -456,7 +449,7 @@
 
     (*env)->GetByteArrayRegion(env, data, offset, length,
                                (jbyte *)fullPacket);
-    rv = sendto(fd, fullPacket, length, 0, (struct sockaddr *)sap, sa_len);
+    rv = sendto(fd, fullPacket, length, 0, sap, sa_len);
     if (rv == SOCKET_ERROR) {
         if (rv == -1) {
             NET_ThrowNew(env, WSAGetLastError(), "Datagram send failed");
--- a/jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c	Tue Jan 17 11:35:28 2017 -0800
@@ -89,15 +89,14 @@
    jboolean exclBind)
 {
     SOCKETADDRESS sa;
-    int rv;
-    int sa_len = sizeof(sa);
+    int rv, sa_len = 0;
 
-    if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&sa,
-                                 &sa_len, JNI_TRUE) != 0) {
+    if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
+                                  &sa_len, JNI_TRUE) != 0) {
       return;
     }
 
-    rv = NET_WinBind(fd, (struct sockaddr *)&sa, sa_len, exclBind);
+    rv = NET_WinBind(fd, &sa, sa_len, exclBind);
 
     if (rv == SOCKET_ERROR)
         NET_ThrowNew(env, WSAGetLastError(), "NET_Bind");
@@ -111,15 +110,14 @@
 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_connect0
   (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) {
     SOCKETADDRESS sa;
-    int rv;
-    int sa_len = sizeof(sa);
+    int rv, sa_len = 0;
 
-    if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&sa,
-                                 &sa_len, JNI_TRUE) != 0) {
+    if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
+                                  &sa_len, JNI_TRUE) != 0) {
       return -1;
     }
 
-    rv = connect(fd, (struct sockaddr *)&sa, sa_len);
+    rv = connect(fd, &sa.sa, sa_len);
     if (rv == SOCKET_ERROR) {
         int err = WSAGetLastError();
         if (err == WSAEWOULDBLOCK) {
@@ -217,7 +215,7 @@
     SOCKETADDRESS sa;
     int len = sizeof(sa);
 
-    if (getsockname(fd, (struct sockaddr *)&sa, &len) == SOCKET_ERROR) {
+    if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) {
         if (WSAGetLastError() == WSAENOTSOCK) {
             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
                     "Socket closed");
@@ -243,11 +241,11 @@
     jclass iaContainerClass;
     jfieldID iaFieldID;
 
-    if (getsockname(fd, (struct sockaddr *)&sa, &len) == SOCKET_ERROR) {
+    if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) {
         NET_ThrowNew(env, WSAGetLastError(), "Error getting socket name");
         return;
     }
-    iaObj = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);
+    iaObj = NET_SockaddrToInetAddress(env, &sa, &port);
     CHECK_NULL(iaObj);
 
     iaContainerClass = (*env)->GetObjectClass(env, iaContainerObj);
@@ -283,7 +281,7 @@
     int len = sizeof(sa);
 
     memset((char *)&sa, 0, len);
-    newfd = accept(fd, (struct sockaddr *)&sa, &len);
+    newfd = accept(fd, &sa.sa, &len);
 
     if (newfd == INVALID_SOCKET) {
         if (WSAGetLastError() == -2) {
@@ -298,7 +296,7 @@
 
     SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0);
 
-    ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);
+    ia = NET_SockaddrToInetAddress(env, &sa, &port);
     isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
     (*env)->SetObjectArrayElement(env, isaa, 0, isa);
 
--- a/jdk/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c	Tue Jan 17 11:35:28 2017 -0800
@@ -420,18 +420,13 @@
                                            jboolean exclBind) {
     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
-
-    int fd, fd1 = -1, family;
     int ipv6_supported = ipv6_available();
-
+    int fd, fd1 = -1, lcladdrlen = 0;
     SOCKETADDRESS lcladdr;
-    int lcladdrlen = sizeof(SOCKETADDRESS);
-    int address;
 
-    memset((char *)&lcladdr, 0, sizeof(lcladdr));
-
-    family = getInetAddress_family(env, addressObj);
-    if (family == java_net_InetAddress_IPv6 && !ipv6_supported) {
+    if (getInetAddress_family(env, addressObj) == java_net_InetAddress_IPv6 &&
+        !ipv6_supported)
+    {
         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
                         "Protocol family not supported");
         return;
@@ -446,14 +441,13 @@
             fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
         }
     }
+
     if (IS_NULL(addressObj)) {
         JNU_ThrowNullPointerException(env, "argument address");
         return;
-    } else {
-        address = getInetAddress_addr(env, addressObj);
     }
 
-    if (NET_InetAddressToSockaddr(env, addressObj, port, &lcladdr.sa,
+    if (NET_InetAddressToSockaddr(env, addressObj, port, &lcladdr,
                                   &lcladdrlen, JNI_FALSE) != 0) {
         return;
     }
@@ -493,7 +487,7 @@
             return;
         }
     } else {
-        if (NET_WinBind(fd, &lcladdr.sa, lcladdrlen, exclBind) == -1) {
+        if (NET_WinBind(fd, &lcladdr, lcladdrlen, exclBind) == -1) {
             if (WSAGetLastError() == WSAEACCES) {
                 WSASetLastError(WSAEADDRINUSE);
             }
@@ -507,7 +501,7 @@
             NET_ThrowCurrent(env, "getsockname");
             return;
         }
-        port = ntohs((u_short) GET_PORT (&lcladdr));
+        port = ntohs((u_short)GET_PORT(&lcladdr));
     }
     (*env)->SetIntField(env, this, pdsi_localPortID, port);
 }
@@ -520,27 +514,25 @@
  */
 
 JNIEXPORT void JNICALL
-Java_java_net_TwoStacksPlainDatagramSocketImpl_connect0(JNIEnv *env, jobject this,
-                                               jobject address, jint port) {
-    /* The object's field */
+Java_java_net_TwoStacksPlainDatagramSocketImpl_connect0
+  (JNIEnv *env, jobject this, jobject address, jint port)
+{
     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
-    /* The fdObj'fd */
-    jint fd=-1, fd1=-1, fdc;
-    /* The packetAddress address, family and port */
-    jint addr, family;
+    jint fd = -1, fd1 = -1, fdc, family;
     SOCKETADDRESS rmtaddr;
-    int rmtaddrlen;
-    int ipv6_supported = ipv6_available();
+    int rmtaddrlen = 0;
 
     if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
                         "Socket closed");
         return;
     }
+
     if (!IS_NULL(fdObj)) {
         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
     }
+
     if (!IS_NULL(fd1Obj)) {
         fd1 = (*env)->GetIntField(env, fd1Obj, IO_fd_fdID);
     }
@@ -550,10 +542,8 @@
         return;
     }
 
-    addr = getInetAddress_addr(env, address);
-
     family = getInetAddress_family(env, address);
-    if (family == java_net_InetAddress_IPv6 && !ipv6_supported) {
+    if (family == java_net_InetAddress_IPv6 && !ipv6_available()) {
         JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
                         "Protocol family not supported");
         return;
@@ -572,12 +562,12 @@
         res = WSAIoctl(fdc,SIO_UDP_CONNRESET,&t,sizeof(t),&x1,sizeof(x1),&x2,0,0);
     }
 
-    if (NET_InetAddressToSockaddr(env, address, port, &rmtaddr.sa,
+    if (NET_InetAddressToSockaddr(env, address, port, &rmtaddr,
                                   &rmtaddrlen, JNI_FALSE) != 0) {
         return;
     }
 
-    if (connect(fdc, &rmtaddr.sa, sizeof(rmtaddr)) == -1) {
+    if (connect(fdc, &rmtaddr.sa, rmtaddrlen) == -1) {
         NET_ThrowCurrent(env, "connect");
         return;
     }
@@ -631,9 +621,9 @@
  * Signature: (Ljava/net/DatagramPacket;)V
  */
 JNIEXPORT void JNICALL
-Java_java_net_TwoStacksPlainDatagramSocketImpl_send(JNIEnv *env, jobject this,
-                                           jobject packet) {
-
+Java_java_net_TwoStacksPlainDatagramSocketImpl_send
+  (JNIEnv *env, jobject this, jobject packet)
+{
     char BUF[MAX_BUFFER_LEN];
     char *fullPacket;
     jobject fdObj;
@@ -647,11 +637,10 @@
     jbyteArray packetBuffer;
     jboolean connected;
 
-    SOCKETADDRESS rmtaddr, *addrp = &rmtaddr;
+    SOCKETADDRESS rmtaddr;
+    struct sockaddr *addrp = 0;
     int addrlen = 0;
 
-    memset((char *)&rmtaddr, 0, sizeof(rmtaddr));
-
     if (IS_NULL(packet)) {
         JNU_ThrowNullPointerException(env, "null packet");
         return;
@@ -696,14 +685,13 @@
         packetBufferLen = MAX_PACKET_LEN;
     }
 
-    if (connected) {
-        addrp = 0; /* arg to sendto () null in this case */
-        addrlen = 0;
-    } else {
-        if (NET_InetAddressToSockaddr(env, iaObj, packetPort, &rmtaddr.sa,
+    // sockaddr arg to sendto() is null if already connected
+    if (!connected) {
+        if (NET_InetAddressToSockaddr(env, iaObj, packetPort, &rmtaddr,
                                       &addrlen, JNI_FALSE) != 0) {
             return;
         }
+        addrp = &rmtaddr.sa;
     }
 
     if (packetBufferLen > MAX_BUFFER_LEN) {
@@ -753,11 +741,12 @@
         fullPacket = &(BUF[0]);
     }
 
-    (*env)->GetByteArrayRegion(env, packetBuffer, packetBufferOffset, packetBufferLen,
-                               (jbyte *)fullPacket);
-    if (sendto(fd, fullPacket, packetBufferLen, 0,
-               (struct sockaddr *)addrp, addrlen) == SOCKET_ERROR) {
-         NET_ThrowCurrent(env, "Datagram send failed");
+    (*env)->GetByteArrayRegion(env, packetBuffer, packetBufferOffset,
+                               packetBufferLen, (jbyte *)fullPacket);
+    if (sendto(fd, fullPacket, packetBufferLen, 0, addrp,
+               addrlen) == SOCKET_ERROR)
+    {
+        NET_ThrowCurrent(env, "Datagram send failed");
     }
 
     if (packetBufferLen > MAX_BUFFER_LEN) {
@@ -1147,14 +1136,14 @@
          */
         packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
         if (packetAddress != NULL) {
-            if (!NET_SockaddrEqualsInetAddress(env, &remote_addr.sa,
+            if (!NET_SockaddrEqualsInetAddress(env, &remote_addr,
                                                packetAddress)) {
                 /* force a new InetAddress to be created */
                 packetAddress = NULL;
             }
         }
         if (packetAddress == NULL) {
-            packetAddress = NET_SockaddrToInetAddress(env, &remote_addr.sa,
+            packetAddress = NET_SockaddrToInetAddress(env, &remote_addr,
                                                       &port);
             /* stuff the new Inetaddress in the packet */
             (*env)->SetObjectField(env, packet, dp_addressID, packetAddress);
@@ -1431,20 +1420,21 @@
          * can't update any existing InetAddress because it is immutable
          */
         packetAddress = (*env)->GetObjectField(env, packet, dp_addressID);
-
         if (packetAddress != NULL) {
-            if (!NET_SockaddrEqualsInetAddress(env, &remote_addr.sa, packetAddress)) {
+            if (!NET_SockaddrEqualsInetAddress(env, &remote_addr,
+                                               packetAddress)) {
                 /* force a new InetAddress to be created */
                 packetAddress = NULL;
             }
         }
         if (packetAddress == NULL) {
-            packetAddress = NET_SockaddrToInetAddress(env, &remote_addr.sa, &port);
+            packetAddress = NET_SockaddrToInetAddress(env, &remote_addr,
+                                                      &port);
             /* stuff the new Inetaddress in the packet */
             (*env)->SetObjectField(env, packet, dp_addressID, packetAddress);
         } else {
             /* only get the new port number */
-            port = NET_GetPortFromSockaddr(&remote_addr.sa);
+            port = NET_GetPortFromSockaddr(&remote_addr);
         }
         /* populate the packet */
         (*env)->SetByteArrayRegion(env, packetBuffer, packetBufferOffset, n,
@@ -1528,7 +1518,7 @@
     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
     jobject fd1Obj = (*env)->GetObjectField(env, this, pdsi_fd1ID);
     int ipv6_supported = ipv6_available();
-    int fd=-1, fd1=-1;
+    int fd = -1, fd1 = -1;
 
     if (IS_NULL(fdObj) && (!ipv6_supported || IS_NULL(fd1Obj))) {
         return;
@@ -1799,7 +1789,7 @@
 Java_java_net_TwoStacksPlainDatagramSocketImpl_socketNativeSetOption
   (JNIEnv *env,jobject this, jint opt,jobject value)
 {
-    int fd=-1, fd1=-1;
+    int fd = -1, fd1 = -1;
     int levelv4 = 0, levelv6 = 0, optnamev4 = 0, optnamev6 = 0, optlen = 0;
     union {
         int i;
@@ -2167,7 +2157,7 @@
 Java_java_net_TwoStacksPlainDatagramSocketImpl_socketGetOption
   (JNIEnv *env, jobject this, jint opt)
 {
-    int fd=-1, fd1=-1;
+    int fd = -1, fd1 = -1;
     int level, optname, optlen;
     union {
         int i;
@@ -2255,7 +2245,7 @@
   (JNIEnv *env, jobject this, jint family)
 {
     int fd = -1, fd1 = -1;
-    SOCKETADDRESS him;
+    SOCKETADDRESS sa;
     int len = 0;
     int port;
     jobject iaObj;
@@ -2288,12 +2278,12 @@
         return NULL;
     }
 
-    if (getsockname(fd, &him.sa, &len) == -1) {
+    if (getsockname(fd, &sa.sa, &len) == -1) {
         JNU_ThrowByNameWithMessageAndLastError
             (env, JNU_JAVANETPKG "SocketException", "Error getting socket name");
         return NULL;
     }
-    iaObj = NET_SockaddrToInetAddress(env, &him.sa, &port);
+    iaObj = NET_SockaddrToInetAddress(env, &sa, &port);
 
     return iaObj;
 }
@@ -2430,7 +2420,7 @@
 
     int len, family;
     int ipv6_supported = ipv6_available();
-    int cmd ;
+    int cmd;
 
     memset((char *)&in, 0, sizeof(in));
     memset((char *)&name, 0, sizeof(name));
@@ -2452,7 +2442,7 @@
         return;
     }
 
-    if (NET_InetAddressToSockaddr(env, iaObj, 0, &name.sa, &len, JNI_FALSE) != 0) {
+    if (NET_InetAddressToSockaddr(env, iaObj, 0, &name, &len, JNI_FALSE) != 0) {
       return;
     }
 
@@ -2473,7 +2463,7 @@
           return;
         }
         if (IS_NULL(niObj)) {
-            len = sizeof (in);
+            len = sizeof(in);
             if (NET_GetSockOpt(fd, IPPROTO_IP, IP_MULTICAST_IF,
                            (char *)&in, &len) < 0) {
                 NET_ThrowCurrent(env, "get IP_MULTICAST_IF failed");
--- a/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c	Tue Jan 17 11:35:28 2017 -0800
@@ -175,8 +175,8 @@
  */
 JNIEXPORT void JNICALL
 Java_java_net_TwoStacksPlainSocketImpl_socketConnect(JNIEnv *env, jobject this,
-                                            jobject iaObj, jint port,
-                                            jint timeout)
+                                                     jobject iaObj, jint port,
+                                                     jint timeout)
 {
     jint localport = (*env)->GetIntField(env, this, psi_localportID);
 
@@ -193,11 +193,11 @@
     jobject fdObj = (*env)->GetObjectField(env, this, psi_fdID);
     jobject fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID);
 
-    SOCKETADDRESS him;
+    SOCKETADDRESS sa;
 
     /* The result of the connection */
     int connect_res;
-    memset((char *)&him, 0, sizeof(him));
+    memset((char *)&sa, 0, sizeof(sa));
 
     if (!IS_NULL(fdObj)) {
         fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
@@ -212,11 +212,12 @@
         return;
     }
 
-    if (NET_InetAddressToSockaddr(env, iaObj, port, &him.sa, &len, JNI_FALSE) != 0) {
-      return;
+    if (NET_InetAddressToSockaddr(env, iaObj, port, &sa, &len,
+                                  JNI_FALSE) != 0) {
+        return;
     }
 
-    family = him.sa.sa_family;
+    family = sa.sa.sa_family;
     if (family == AF_INET6) {
         if (!ipv6_supported) {
             JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
@@ -248,7 +249,7 @@
     (*env)->SetObjectField(env, this, psi_fd1ID, NULL);
 
     if (timeout <= 0) {
-        connect_res = connect(fd, &him.sa, sizeof(SOCKETADDRESS));
+        connect_res = connect(fd, &sa.sa, sizeof(SOCKETADDRESS));
         if (connect_res == SOCKET_ERROR) {
             connect_res = WSAGetLastError();
         }
@@ -261,7 +262,7 @@
         ioctlsocket(fd, FIONBIO, &optval);
 
         /* initiate the connect */
-        connect_res = connect(fd, &him.sa, sizeof(SOCKETADDRESS));
+        connect_res = connect(fd, &sa.sa, sizeof(SOCKETADDRESS));
         if (connect_res == SOCKET_ERROR) {
             if (WSAGetLastError() != WSAEWOULDBLOCK) {
                 connect_res = WSAGetLastError();
@@ -362,7 +363,7 @@
          */
         u_short port;
         int len = sizeof(SOCKETADDRESS);
-        if (getsockname(fd, &him.sa, &len) == -1) {
+        if (getsockname(fd, &sa.sa, &len) == -1) {
             if (WSAGetLastError() == WSAENOTSOCK) {
                 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
                                 "Socket closed");
@@ -371,7 +372,7 @@
             }
             return;
         }
-        port = ntohs((u_short)GET_PORT(&him));
+        port = ntohs((u_short)GET_PORT(&sa));
         (*env)->SetIntField(env, this, psi_localportID, (int) port);
     }
 }
@@ -396,7 +397,7 @@
     int family;
     int rv;
 
-    SOCKETADDRESS him;
+    SOCKETADDRESS sa;
 
     fdObj = (*env)->GetObjectField(env, this, psi_fdID);
     fd1Obj = (*env)->GetObjectField(env, this, psi_fd1ID);
@@ -424,13 +425,13 @@
         return;
     }
 
-    if (NET_InetAddressToSockaddr(env, iaObj, localport, &him.sa, &len,
+    if (NET_InetAddressToSockaddr(env, iaObj, localport, &sa, &len,
                                   JNI_FALSE) != 0) {
         return;
     }
     if (ipv6_supported) {
         struct ipv6bind v6bind;
-        v6bind.addr = &him;
+        v6bind.addr = &sa.sa;
         v6bind.ipv4_fd = fd;
         v6bind.ipv6_fd = fd1;
         rv = NET_BindV6(&v6bind, exclBind);
@@ -462,7 +463,7 @@
             (*env)->SetObjectField(env, this, psi_fd1ID, NULL);
         }
     } else {
-        rv = NET_WinBind(fd, &him.sa, len, exclBind);
+        rv = NET_WinBind(fd, &sa, len, exclBind);
     }
 
     if (rv == -1) {
@@ -481,11 +482,11 @@
         int len = sizeof(SOCKETADDRESS);
         u_short port;
 
-        if (getsockname(him.sa.sa_family == AF_INET ? fd: fd1, &him.sa, &len) == -1) {
+        if (getsockname(sa.sa.sa_family == AF_INET ? fd : fd1, &sa.sa, &len) == -1) {
             NET_ThrowCurrent(env, "getsockname in plain socketBind");
             return;
         }
-        port = ntohs((u_short) GET_PORT (&him));
+        port = ntohs((u_short) GET_PORT (&sa));
 
         (*env)->SetIntField(env, this, psi_localportID, (int)port);
     } else {
@@ -529,7 +530,7 @@
         JNU_ThrowNullPointerException(env, "socket address");
         return;
     }
-    if (NET_InetAddressToSockaddr(env, address, 0, &addr.sa, &addrlen,
+    if (NET_InetAddressToSockaddr(env, address, 0, &addr, &addrlen,
                                   JNI_FALSE) != 0) {
         return;
     }
@@ -585,7 +586,7 @@
     /* the fd int field on fdObj */
     jint fd=-1, fd1=-1;
 
-    SOCKETADDRESS him;
+    SOCKETADDRESS sa;
     jint len;
 
     if (IS_NULL(fdObj) && IS_NULL(fd1Obj)) {
@@ -676,7 +677,7 @@
             }
         }
     }
-    fd = accept(fd, &him.sa, &len);
+    fd = accept(fd, &sa.sa, &len);
     if (fd < 0) {
         /* REMIND: SOCKET CLOSED PROBLEM */
         if (fd == -2) {
@@ -691,7 +692,7 @@
     SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, 0);
     (*env)->SetIntField(env, socketFdObj, IO_fd_fdID, fd);
 
-    if (him.sa.sa_family == AF_INET) {
+    if (sa.sa.sa_family == AF_INET) {
         if (inet4Cls == NULL) {
             jclass c = (*env)->FindClass(env, "java/net/Inet4Address");
             if (c != NULL) {
@@ -717,7 +718,7 @@
             return;
         }
 
-        setInetAddress_addr(env, socketAddressObj, ntohl(him.sa4.sin_addr.s_addr));
+        setInetAddress_addr(env, socketAddressObj, ntohl(sa.sa4.sin_addr.s_addr));
         setInetAddress_family(env, socketAddressObj, java_net_InetAddress_IPv4);
         (*env)->SetObjectField(env, socket, psi_addressID, socketAddressObj);
     } else {
@@ -743,14 +744,14 @@
             NET_SocketClose(fd);
             return;
         }
-        setInet6Address_ipaddress(env, socketAddressObj, (char *)&him.sa6.sin6_addr);
+        setInet6Address_ipaddress(env, socketAddressObj, (char *)&sa.sa6.sin6_addr);
         setInetAddress_family(env, socketAddressObj, java_net_InetAddress_IPv6);
-        setInet6Address_scopeid(env, socketAddressObj, him.sa6.sin6_scope_id);
+        setInet6Address_scopeid(env, socketAddressObj, sa.sa6.sin6_scope_id);
 
     }
     /* fields common to AF_INET and AF_INET6 */
 
-    port = ntohs ((u_short) GET_PORT (&him));
+    port = ntohs ((u_short)GET_PORT(&sa));
     (*env)->SetIntField(env, socket, psi_portID, (int)port);
     port = (*env)->GetIntField(env, this, psi_localportID);
     (*env)->SetIntField(env, socket, psi_localportID, port);
@@ -1025,14 +1026,14 @@
      * SO_BINDADDR isn't a socket option
      */
     if (opt == java_net_SocketOptions_SO_BINDADDR) {
-        SOCKETADDRESS him;
+        SOCKETADDRESS sa;
         int len = sizeof(SOCKETADDRESS);
         int port;
         jobject iaObj;
         jclass iaCntrClass;
         jfieldID iaFieldID;
 
-        memset((char *)&him, 0, len);
+        memset((char *)&sa, 0, len);
 
         if (fd == -1) {
             /* must be an IPV6 only socket. Case where both sockets are != -1
@@ -1041,12 +1042,12 @@
             fd = getFD1 (env, this);
         }
 
-        if (getsockname(fd, &him.sa, &len) < 0) {
+        if (getsockname(fd, &sa.sa, &len) < 0) {
             JNU_ThrowByNameWithMessageAndLastError
                 (env, JNU_JAVANETPKG "SocketException", "Error getting socket name");
             return -1;
         }
-        iaObj = NET_SockaddrToInetAddress(env, &him.sa, &port);
+        iaObj = NET_SockaddrToInetAddress(env, &sa, &port);
         CHECK_NULL_RETURN(iaObj, -1);
 
         iaCntrClass = (*env)->GetObjectClass(env, iaContainerObj);
--- a/jdk/src/java.base/windows/native/libnet/net_util_md.c	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/java.base/windows/native/libnet/net_util_md.c	Tue Jan 17 11:35:28 2017 -0800
@@ -488,10 +488,10 @@
  * Should be only called by the wrapper method NET_WinBind
  */
 JNIEXPORT int JNICALL
-NET_Bind(int s, struct sockaddr *him, int len)
+NET_Bind(int s, SOCKETADDRESS *sa, int len)
 {
     int rv = 0;
-    rv = bind(s, him, len);
+    rv = bind(s, &sa->sa, len);
 
     if (rv == SOCKET_ERROR) {
         /*
@@ -511,11 +511,11 @@
  * if required, and then calls NET_BIND
  */
 JNIEXPORT int JNICALL
-NET_WinBind(int s, struct sockaddr *him, int len, jboolean exclBind)
+NET_WinBind(int s, SOCKETADDRESS *sa, int len, jboolean exclBind)
 {
     if (exclBind == JNI_TRUE)
         setExclusiveBind(s);
-    return NET_Bind(s, him, len);
+    return NET_Bind(s, sa, len);
 }
 
 JNIEXPORT int JNICALL
@@ -677,8 +677,8 @@
     if (family == AF_INET && (b->addr->sa4.sin_addr.s_addr != INADDR_ANY)) {
         /* bind to v4 only */
         int ret;
-        ret = NET_WinBind((int)b->ipv4_fd, (struct sockaddr *)b->addr,
-                                sizeof(SOCKETADDRESS), exclBind);
+        ret = NET_WinBind((int)b->ipv4_fd, b->addr,
+                          sizeof(SOCKETADDRESS), exclBind);
         if (ret == SOCKET_ERROR) {
             CLOSE_SOCKETS_AND_RETURN;
         }
@@ -689,7 +689,7 @@
     if (family == AF_INET6 && (!IN6_IS_ADDR_ANY(&b->addr->sa6.sin6_addr))) {
         /* bind to v6 only */
         int ret;
-        ret = NET_WinBind((int)b->ipv6_fd, (struct sockaddr *)b->addr,
+        ret = NET_WinBind((int)b->ipv6_fd, b->addr,
                           sizeof(SOCKETADDRESS), exclBind);
         if (ret == SOCKET_ERROR) {
             CLOSE_SOCKETS_AND_RETURN;
@@ -719,7 +719,7 @@
         oaddr.sa4.sin_addr.s_addr = INADDR_ANY;
     }
 
-    rv = NET_WinBind(fd, (struct sockaddr *)b->addr, sizeof(SOCKETADDRESS), exclBind);
+    rv = NET_WinBind(fd, b->addr, sizeof(SOCKETADDRESS), exclBind);
     if (rv == SOCKET_ERROR) {
         CLOSE_SOCKETS_AND_RETURN;
     }
@@ -731,7 +731,7 @@
     }
     bound_port = GET_PORT (b->addr);
     SET_PORT (&oaddr, bound_port);
-    if ((rv = NET_WinBind(ofd, &oaddr.sa,
+    if ((rv = NET_WinBind(ofd, &oaddr,
                           sizeof(SOCKETADDRESS), exclBind)) == SOCKET_ERROR) {
         int retries;
         int sotype, arglen=sizeof(sotype);
@@ -768,7 +768,7 @@
 
             /* bind random port on first socket */
             SET_PORT (&oaddr, 0);
-            rv = NET_WinBind(ofd, &oaddr.sa, sizeof(SOCKETADDRESS), exclBind);
+            rv = NET_WinBind(ofd, &oaddr, sizeof(SOCKETADDRESS), exclBind);
             if (rv == SOCKET_ERROR) {
                 CLOSE_SOCKETS_AND_RETURN;
             }
@@ -784,8 +784,7 @@
             }
             bound_port = GET_PORT (&oaddr);
             SET_PORT (b->addr, bound_port);
-            rv = NET_WinBind(fd, (struct sockaddr *)b->addr,
-                             sizeof(SOCKETADDRESS), exclBind);
+            rv = NET_WinBind(fd, b->addr, sizeof(SOCKETADDRESS), exclBind);
 
             if (rv != SOCKET_ERROR) {
                 if (family == AF_INET) {
@@ -853,31 +852,33 @@
     return result == SOCKET_ERROR ? WSAGetLastError() : 0;
 }
 
-/* If address types is IPv6, then IPv6 must be available. Otherwise
- * no address can be generated. In the case of an IPv4 Inetaddress this
- * method will return an IPv4 mapped address where IPv6 is available and
- * v4MappedAddress is TRUE. Otherwise it will return a sockaddr_in
- * structure for an IPv4 InetAddress.
-*/
+/**
+ * See net_util.h for documentation
+ */
 JNIEXPORT int JNICALL
-NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port, struct sockaddr *him,
-                          int *len, jboolean v4MappedAddress) {
-    jint family, iafam;
-    iafam = getInetAddress_family(env, iaObj);
-    family = (iafam == java_net_InetAddress_IPv4)? AF_INET : AF_INET6;
-    if (ipv6_available() && !(family == AF_INET && v4MappedAddress == JNI_FALSE)) {
-        struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
+NET_InetAddressToSockaddr(JNIEnv *env, jobject iaObj, int port,
+                          SOCKETADDRESS *sa, int *len,
+                          jboolean v4MappedAddress)
+{
+    jint family = getInetAddress_family(env, iaObj);
+    memset((char *)sa, 0, sizeof(SOCKETADDRESS));
+
+    if (ipv6_available() &&
+        !(family == java_net_InetAddress_IPv4 &&
+          v4MappedAddress == JNI_FALSE))
+    {
         jbyte caddr[16];
-        jint address, scopeid = 0;
-        jint cached_scope_id = 0;
+        jint address;
+        unsigned int scopeid = 0, cached_scope_id = 0;
 
-        if (family == AF_INET) { /* will convert to IPv4-mapped address */
-            memset((char *) caddr, 0, 16);
+        if (family == java_net_InetAddress_IPv4) {
+            // convert to IPv4-mapped address
+            memset((char *)caddr, 0, 16);
             address = getInetAddress_addr(env, iaObj);
             if (address == INADDR_ANY) {
                 /* we would always prefer IPv6 wildcard address
-                caddr[10] = 0xff;
-                caddr[11] = 0xff; */
+                 * caddr[10] = 0xff;
+                 * caddr[11] = 0xff; */
             } else {
                 caddr[10] = 0xff;
                 caddr[11] = 0xff;
@@ -889,46 +890,39 @@
         } else {
             getInet6Address_ipaddress(env, iaObj, (char *)caddr);
             scopeid = getInet6Address_scopeid(env, iaObj);
-            cached_scope_id = (jint)(*env)->GetIntField(env, iaObj, ia6_cachedscopeidID);
+            cached_scope_id = (unsigned int)(*env)->GetIntField(env, iaObj, ia6_cachedscopeidID);
         }
-
-        memset((char *)him6, 0, sizeof(struct sockaddr_in6));
-        him6->sin6_port = (u_short) htons((u_short)port);
-        memcpy((void *)&(him6->sin6_addr), caddr, sizeof(struct in6_addr) );
-        him6->sin6_family = AF_INET6;
-        if ((family == AF_INET6) && IN6_IS_ADDR_LINKLOCAL( &(him6->sin6_addr) )
-            && (!scopeid && !cached_scope_id)) {
-            cached_scope_id = getDefaultIPv6Interface(env, him6);
+        sa->sa6.sin6_port = (u_short)htons((u_short)port);
+        memcpy((void *)&sa->sa6.sin6_addr, caddr, sizeof(struct in6_addr));
+        sa->sa6.sin6_family = AF_INET6;
+        if ((family == java_net_InetAddress_IPv6) &&
+            IN6_IS_ADDR_LINKLOCAL(&sa->sa6.sin6_addr) &&
+            (!scopeid && !cached_scope_id))
+        {
+            cached_scope_id = getDefaultIPv6Interface(env, &sa->sa6);
             (*env)->SetIntField(env, iaObj, ia6_cachedscopeidID, cached_scope_id);
         }
-        him6->sin6_scope_id = scopeid != 0 ? scopeid : cached_scope_id;
-        *len = sizeof(struct sockaddr_in6) ;
+        sa->sa6.sin6_scope_id = scopeid == 0 ? cached_scope_id : scopeid;
+        if (len != NULL) {
+            *len = sizeof(struct sockaddr_in6);
+        }
     } else {
-        struct sockaddr_in *him4 = (struct sockaddr_in *)him;
         jint address;
-        if (family != AF_INET) {
-          JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Protocol family unavailable");
-          return -1;
+        if (family != java_net_InetAddress_IPv4) {
+            JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Protocol family unavailable");
+            return -1;
         }
-        memset((char *)him4, 0, sizeof(struct sockaddr_in));
         address = getInetAddress_addr(env, iaObj);
-        him4->sin_port = htons((short) port);
-        him4->sin_addr.s_addr = (u_long) htonl(address);
-        him4->sin_family = AF_INET;
-        *len = sizeof(struct sockaddr_in);
+        sa->sa4.sin_port = htons((short)port);
+        sa->sa4.sin_addr.s_addr = (u_long)htonl(address);
+        sa->sa4.sin_family = AF_INET;
+        if (len != NULL) {
+            *len = sizeof(struct sockaddr_in);
+        }
     }
     return 0;
 }
 
-JNIEXPORT jint JNICALL
-NET_GetPortFromSockaddr(struct sockaddr *him) {
-    if (him->sa_family == AF_INET6) {
-        return ntohs(((struct sockaddr_in6 *)him)->sin6_port);
-    } else {
-        return ntohs(((struct sockaddr_in *)him)->sin_port);
-    }
-}
-
 int
 NET_IsIPv4Mapped(jbyte* caddr) {
     int i;
@@ -961,16 +955,6 @@
     return 1;
 }
 
-int getScopeID(struct sockaddr *him) {
-    struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
-    return him6->sin6_scope_id;
-}
-
-int cmpScopeID(unsigned int scope, struct sockaddr *him) {
-    struct sockaddr_in6 *him6 = (struct sockaddr_in6 *)him;
-    return him6->sin6_scope_id == scope;
-}
-
 /**
  * Wrapper for select/poll with timeout on a single file descriptor.
  *
--- a/jdk/src/java.base/windows/native/libnet/net_util_md.h	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/java.base/windows/native/libnet/net_util_md.h	Tue Jan 17 11:35:28 2017 -0800
@@ -121,7 +121,7 @@
 
 JNIEXPORT int JNICALL NET_BindV6(struct ipv6bind *b, jboolean exclBind);
 
-JNIEXPORT int JNICALL NET_WinBind(int s, struct sockaddr *him, int len,
+JNIEXPORT int JNICALL NET_WinBind(int s, SOCKETADDRESS *sa, int len,
                                   jboolean exclBind);
 
 /* XP versions of the native routines */
--- a/jdk/src/java.base/windows/native/libnio/ch/DatagramChannelImpl.c	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/java.base/windows/native/libnio/ch/DatagramChannelImpl.c	Tue Jan 17 11:35:28 2017 -0800
@@ -96,7 +96,7 @@
             break;
         }
         if (recvfrom(fd, buf, 1, MSG_PEEK,
-                     (struct sockaddr *)&sa, &addrlen) != SOCKET_ERROR) {
+                     &sa.sa, &addrlen) != SOCKET_ERROR) {
             break;
         }
         if (WSAGetLastError() != WSAECONNRESET) {
@@ -104,7 +104,7 @@
             break;
         }
 
-        recvfrom(fd, buf, 1, 0,  (struct sockaddr *)&sa, &addrlen);
+        recvfrom(fd, buf, 1, 0, &sa.sa, &addrlen);
         got_icmp = JNI_TRUE;
     }
 
@@ -122,7 +122,7 @@
 
     memset(&sa, 0, sa_len);
 
-    rv = connect((SOCKET)fd, (struct sockaddr *)&sa, sa_len);
+    rv = connect((SOCKET)fd, &sa.sa, sa_len);
     if (rv == SOCKET_ERROR) {
         handleSocketError(env, WSAGetLastError());
     } else {
@@ -153,7 +153,7 @@
                      (char *)buf,
                      len,
                      0,
-                     (struct sockaddr *)&sa,
+                     &sa.sa,
                      &sa_len);
 
         if (n == SOCKET_ERROR) {
@@ -182,12 +182,11 @@
      */
     senderAddr = (*env)->GetObjectField(env, this, dci_senderAddrID);
     if (senderAddr != NULL) {
-        if (!NET_SockaddrEqualsInetAddress(env, (struct sockaddr *)&sa,
-                                           senderAddr)) {
+        if (!NET_SockaddrEqualsInetAddress(env, &sa, senderAddr)) {
             senderAddr = NULL;
         } else {
             jint port = (*env)->GetIntField(env, this, dci_senderPortID);
-            if (port != NET_GetPortFromSockaddr((struct sockaddr *)&sa)) {
+            if (port != NET_GetPortFromSockaddr(&sa)) {
                 senderAddr = NULL;
             }
         }
@@ -195,7 +194,7 @@
     if (senderAddr == NULL) {
         jobject isa = NULL;
         int port;
-        jobject ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);
+        jobject ia = NET_SockaddrToInetAddress(env, &sa, &port);
         if (ia != NULL) {
             isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
         }
@@ -204,7 +203,7 @@
         // update cachedSenderInetAddress/cachedSenderPort
         (*env)->SetObjectField(env, this, dci_senderAddrID, ia);
         (*env)->SetIntField(env, this, dci_senderPortID,
-                            NET_GetPortFromSockaddr((struct sockaddr *)&sa));
+                            NET_GetPortFromSockaddr(&sa));
         (*env)->SetObjectField(env, this, dci_senderID, isa);
     }
     return n;
@@ -219,21 +218,15 @@
     jint fd = fdval(env, fdo);
     void *buf = (void *)jlong_to_ptr(address);
     SOCKETADDRESS sa;
-    int sa_len;
+    int sa_len = 0;
     jint rv = 0;
 
-    if (NET_InetAddressToSockaddr(env, destAddress, destPort,
-                                  (struct sockaddr *)&sa,
-                                   &sa_len, preferIPv6) != 0) {
+    if (NET_InetAddressToSockaddr(env, destAddress, destPort, &sa,
+                                  &sa_len, preferIPv6) != 0) {
       return IOS_THROWN;
     }
 
-    rv = sendto((SOCKET)fd,
-               buf,
-               len,
-               0,
-               (struct sockaddr *)&sa,
-               sa_len);
+    rv = sendto((SOCKET)fd, buf, len, 0, &sa.sa, sa_len);
     if (rv == SOCKET_ERROR) {
         int theErr = (jint)WSAGetLastError();
         if (theErr == WSAEWOULDBLOCK) {
--- a/jdk/src/java.base/windows/native/libnio/ch/Net.c	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/java.base/windows/native/libnio/ch/Net.c	Tue Jan 17 11:35:28 2017 -0800
@@ -168,13 +168,13 @@
 {
     SOCKETADDRESS sa;
     int rv;
-    int sa_len;
+    int sa_len = 0;
 
-    if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) {
-      return;
+    if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, preferIPv6) != 0) {
+        return;
     }
 
-    rv = NET_WinBind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len, isExclBind);
+    rv = NET_WinBind(fdval(env, fdo), &sa, sa_len, isExclBind);
     if (rv == SOCKET_ERROR)
         NET_ThrowNew(env, WSAGetLastError(), "bind");
 }
@@ -194,14 +194,14 @@
 {
     SOCKETADDRESS sa;
     int rv;
-    int sa_len;
+    int sa_len = 0;
     SOCKET s = (SOCKET)fdval(env, fdo);
 
-    if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) {
+    if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len, preferIPv6) != 0) {
         return IOS_THROWN;
     }
 
-    rv = connect(s, (struct sockaddr *)&sa, sa_len);
+    rv = connect(s, &sa.sa, sa_len);
     if (rv != 0) {
         int err = WSAGetLastError();
         if (err == WSAEINPROGRESS || err == WSAEWOULDBLOCK) {
@@ -226,7 +226,7 @@
     SOCKETADDRESS sa;
     int sa_len = sizeof(sa);
 
-    if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) {
+    if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) < 0) {
         int error = WSAGetLastError();
         if (error == WSAEINVAL) {
             return 0;
@@ -234,7 +234,7 @@
         NET_ThrowNew(env, error, "getsockname");
         return IOS_THROWN;
     }
-    return NET_GetPortFromSockaddr((struct sockaddr *)&sa);
+    return NET_GetPortFromSockaddr(&sa);
 }
 
 JNIEXPORT jobject JNICALL
@@ -244,11 +244,11 @@
     int sa_len = sizeof(sa);
     int port;
 
-    if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) {
+    if (getsockname(fdval(env, fdo), &sa.sa, &sa_len) < 0) {
         NET_ThrowNew(env, WSAGetLastError(), "getsockname");
         return NULL;
     }
-    return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);
+    return NET_SockaddrToInetAddress(env, &sa, &port);
 }
 
 JNIEXPORT jint JNICALL
@@ -257,7 +257,7 @@
     SOCKETADDRESS sa;
     int sa_len = sizeof(sa);
 
-    if (getpeername(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) {
+    if (getpeername(fdval(env, fdo), &sa.sa, &sa_len) < 0) {
         int error = WSAGetLastError();
         if (error == WSAEINVAL) {
             return 0;
@@ -265,7 +265,7 @@
         NET_ThrowNew(env, error, "getsockname");
         return IOS_THROWN;
     }
-    return NET_GetPortFromSockaddr((struct sockaddr *)&sa);
+    return NET_GetPortFromSockaddr(&sa);
 }
 
 JNIEXPORT jobject JNICALL
@@ -275,11 +275,11 @@
     int sa_len = sizeof(sa);
     int port;
 
-    if (getpeername(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) {
+    if (getpeername(fdval(env, fdo), &sa.sa, &sa_len) < 0) {
         NET_ThrowNew(env, WSAGetLastError(), "getsockname");
         return NULL;
     }
-    return NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);
+    return NET_SockaddrToInetAddress(env, &sa, &port);
 }
 
 JNIEXPORT jint JNICALL
--- a/jdk/src/java.base/windows/native/libnio/ch/ServerSocketChannelImpl.c	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/java.base/windows/native/libnio/ch/ServerSocketChannelImpl.c	Tue Jan 17 11:35:28 2017 -0800
@@ -95,7 +95,7 @@
     int addrlen = sizeof(sa);
 
     memset((char *)&sa, 0, sizeof(sa));
-    newfd = (jint)accept(ssfd, (struct sockaddr *)&sa, &addrlen);
+    newfd = (jint)accept(ssfd, &sa.sa, &addrlen);
     if (newfd == INVALID_SOCKET) {
         int theErr = (jint)WSAGetLastError();
         if (theErr == WSAEWOULDBLOCK) {
@@ -107,7 +107,7 @@
 
     SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0);
     (*env)->SetIntField(env, newfdo, fd_fdID, newfd);
-    remote_ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, (int *)&remote_port);
+    remote_ia = NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port);
     CHECK_NULL_RETURN(remote_ia, IOS_THROWN);
 
     isa = (*env)->NewObject(env, isa_class, isa_ctorID, remote_ia, remote_port);
--- a/jdk/src/java.base/windows/native/libnio/ch/WindowsAsynchronousSocketChannelImpl.c	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/java.base/windows/native/libnio/ch/WindowsAsynchronousSocketChannelImpl.c	Tue Jan 17 11:35:28 2017 -0800
@@ -88,26 +88,21 @@
 Java_sun_nio_ch_WindowsAsynchronousSocketChannelImpl_connect0(JNIEnv* env, jclass this,
     jlong socket, jboolean preferIPv6, jobject iao, jint port, jlong ov)
 {
-    SOCKET s = (SOCKET) jlong_to_ptr(socket);
-    OVERLAPPED* lpOverlapped = (OVERLAPPED*) jlong_to_ptr(ov);
+    SOCKET s = (SOCKET)jlong_to_ptr(socket);
+    OVERLAPPED *lpOverlapped = (OVERLAPPED *)jlong_to_ptr(ov);
 
     SOCKETADDRESS sa;
-    int sa_len;
+    int sa_len = 0;
     BOOL res;
 
-    if (NET_InetAddressToSockaddr(env, iao, port, (struct sockaddr *)&sa, &sa_len, preferIPv6) != 0) {
+    if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len,
+                                  preferIPv6) != 0) {
         return IOS_THROWN;
     }
 
     ZeroMemory((PVOID)lpOverlapped, sizeof(OVERLAPPED));
 
-    res = (*ConnectEx_func)(s,
-                            (struct sockaddr *)&sa,
-                            sa_len,
-                            NULL,
-                            0,
-                            NULL,
-                            lpOverlapped);
+    res = (*ConnectEx_func)(s, &sa.sa, sa_len, NULL, 0, NULL, lpOverlapped);
     if (res == 0) {
         int error = GetLastError();
         if (error == ERROR_IO_PENDING) {
--- a/jdk/src/jdk.internal.le/windows/native/lible/WindowsTerminal.cpp	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/jdk.internal.le/windows/native/lible/WindowsTerminal.cpp	Tue Jan 17 11:35:28 2017 -0800
@@ -102,26 +102,26 @@
 
 JNIEXPORT jint JNICALL Java_jdk_internal_jline_WindowsTerminal_getWindowsTerminalWidth
   (JNIEnv *, jobject) {
-    HANDLE hStdIn;
-    if ((hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
+    HANDLE hStdOut;
+    if ((hStdOut = GetStdHandle(STD_OUTPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
         return -1;
     }
     CONSOLE_SCREEN_BUFFER_INFO info;
-    if (! GetConsoleScreenBufferInfo(hStdIn, &info)) {
+    if (! GetConsoleScreenBufferInfo(hStdOut, &info)) {
         return -1;
     }
-    return info.dwSize.X;
+    return info.srWindow.Right - info.srWindow.Left;
 }
 
 JNIEXPORT jint JNICALL Java_jdk_internal_jline_WindowsTerminal_getWindowsTerminalHeight
   (JNIEnv *, jobject) {
-    HANDLE hStdIn;
-    if ((hStdIn = GetStdHandle(STD_INPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
+    HANDLE hStdOut;
+    if ((hStdOut = GetStdHandle(STD_OUTPUT_HANDLE)) == INVALID_HANDLE_VALUE) {
         return -1;
     }
     CONSOLE_SCREEN_BUFFER_INFO info;
-    if (! GetConsoleScreenBufferInfo(hStdIn, &info)) {
+    if (! GetConsoleScreenBufferInfo(hStdOut, &info)) {
         return -1;
     }
-    return info.dwSize.Y;
+    return info.srWindow.Bottom - info.srWindow.Top + 1;
 }
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java	Tue Jan 17 11:35:28 2017 -0800
@@ -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
@@ -34,6 +34,8 @@
 import java.nio.file.Paths;
 import java.util.regex.Pattern;
 import java.util.regex.PatternSyntaxException;
+
+import jdk.internal.module.ModulePath;
 import jdk.internal.module.ModuleResolution;
 
 /**
@@ -155,8 +157,8 @@
                     for (String dir : dirs) {
                         paths[i++] = Paths.get(dir);
                     }
-                    jartool.moduleFinder = ModuleFinder.compose(jartool.moduleFinder,
-                                                                ModuleFinder.of(paths));
+                    jartool.moduleFinder =
+                        new ModulePath(Runtime.version(), true, paths);
                 }
             },
             new Option(false, OptionType.CREATE_UPDATE, "--do-not-resolve-by-default") {
@@ -169,9 +171,9 @@
             new Option(true, OptionType.CREATE_UPDATE, "--warn-if-resolved") {
                 void process(Main jartool, String opt, String arg) throws BadArgs {
                     ModuleResolution mres = ModuleResolution.empty();
-                    if (jartool.moduleResolution.doNotResolveByDefault())
+                    if (jartool.moduleResolution.doNotResolveByDefault()) {
                         mres.withDoNotResolveByDefault();
-
+                    }
                     if (arg.equals("deprecated")) {
                         jartool.moduleResolution = mres.withDeprecated();
                     } else if (arg.equals("deprecated-for-removal")) {
@@ -201,26 +203,27 @@
             // Other options
             new Option(true, true, OptionType.OTHER, "--help", "-h") {
                 void process(Main jartool, String opt, String arg) throws BadArgs {
-                    if (arg == null) {
-                        jartool.info = Main.Info.HELP;
-                        return;
+                    if (jartool.info == null) {
+                        if (arg == null) {
+                            jartool.info = GNUStyleOptions::printHelp;  //  Main.Info.HELP;
+                            return;
+                        }
+                        if (!arg.equals("compat"))
+                            throw new BadArgs("error.illegal.option", arg).showUsage(true);
+                        // jartool.info = Main.Info.COMPAT_HELP;
+                        jartool.info = GNUStyleOptions::printCompatHelp;
                     }
-
-                    if (!arg.equals("compat"))
-                        throw new BadArgs("error.illegal.option", arg).showUsage(true);
-
-                    jartool.info = Main.Info.COMPAT_HELP;
                 }
             },
             new Option(false, OptionType.OTHER, "--help-extra") {
                 void process(Main jartool, String opt, String arg) throws BadArgs {
-                    jartool.info = Main.Info.HELP_EXTRA;
+                    jartool.info = GNUStyleOptions::printHelpExtra;
                 }
             },
             new Option(false, OptionType.OTHER, "--version") {
                 void process(Main jartool, String opt, String arg) {
                     if (jartool.info == null)
-                        jartool.info = Main.Info.VERSION;
+                        jartool.info = GNUStyleOptions::printVersion;
                 }
             }
     };
@@ -279,14 +282,14 @@
     static int parseOptions(Main jartool, String[] args) throws BadArgs {
         int count = 0;
         if (args.length == 0) {
-            jartool.info = Main.Info.USAGE_TRYHELP;
+            jartool.info = GNUStyleOptions::printUsageTryHelp;  //  never be here
             return 0;
         }
 
         // process options
         for (; count < args.length; count++) {
-            if (args[count].charAt(0) != '-' || args[count].equals("-C")
-                || args[count].equals("--release"))
+            if (args[count].charAt(0) != '-' || args[count].equals("-C") ||
+                args[count].equals("--release"))
                 break;
 
             String name = args[count];
@@ -322,15 +325,15 @@
         throw new BadArgs("error.unrecognized.option", name).showUsage(true);
     }
 
-    static void printHelp(PrintWriter out) {
-        printHelp(out, false);
+    static void printHelpExtra(PrintWriter out) {
+        printHelp0(out, true);
     }
 
-    static void printHelpExtra(PrintWriter out) {
-        printHelp(out, true);
+    static void printHelp(PrintWriter out) {
+        printHelp0(out, false);
     }
 
-    private static void printHelp(PrintWriter out, boolean printExtra) {
+    private static void printHelp0(PrintWriter out, boolean printExtra) {
         out.format("%s%n", Main.getMsg("main.help.preopt"));
         for (OptionType type : OptionType.values()) {
             boolean typeHeadingWritten = false;
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java	Tue Jan 17 11:35:28 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,7 @@
 
 import java.io.*;
 import java.lang.module.Configuration;
+import java.lang.module.InvalidModuleDescriptorException;
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Exports;
 import java.lang.module.ModuleDescriptor.Provides;
@@ -46,7 +47,7 @@
 import java.nio.file.StandardCopyOption;
 import java.util.*;
 import java.util.function.Consumer;
-import java.util.function.Function;
+import java.util.function.Supplier;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -58,6 +59,7 @@
 
 import jdk.internal.module.Checks;
 import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModuleHashesBuilder;
 import jdk.internal.module.ModuleInfo;
 import jdk.internal.module.ModuleInfoExtender;
 import jdk.internal.module.ModuleResolution;
@@ -66,7 +68,6 @@
 import static jdk.internal.util.jar.JarIndex.INDEX_NAME;
 import static java.util.jar.JarFile.MANIFEST_NAME;
 import static java.util.stream.Collectors.joining;
-import static java.util.stream.Collectors.toSet;
 import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
 
 /**
@@ -74,58 +75,24 @@
  * (Java Archive) file format. The JAR format is based on the ZIP file
  * format, with optional meta-information stored in a MANIFEST entry.
  */
-public
-class Main {
+public class Main {
     String program;
     PrintWriter out, err;
     String fname, mname, ename;
     String zname = "";
     String rootjar = null;
-    Set<String> concealedPackages = new HashSet<>(); // used by Validator
 
     private static final int BASE_VERSION = 0;
 
-    class Entry {
-        final String basename;
-        final String entryname;
+    private static class Entry {
+        final String name;
         final File file;
         final boolean isDir;
 
-        Entry(File file, String basename, String entryname) {
-            this.file = file;
-            this.isDir = file.isDirectory();
-            this.basename = basename;
-            this.entryname = entryname;
-        }
-
-        Entry(int version, File file) {
+        Entry(File file, String name, boolean isDir) {
             this.file = file;
-            String path = file.getPath();
-            if (file.isDirectory()) {
-                isDir = true;
-                path = path.endsWith(File.separator) ? path :
-                            path + File.separator;
-            } else {
-                isDir = false;
-            }
-            EntryName en = new EntryName(path, version);
-            basename = en.baseName;
-            entryname = en.entryName;
-        }
-
-        /**
-         * Returns a new Entry that trims the versions directory.
-         *
-         * This entry should be a valid entry matching the given version.
-         */
-        Entry toVersionedEntry(int version) {
-            assert isValidVersionedEntry(this, version);
-
-            if (version == BASE_VERSION)
-                return this;
-
-            EntryName en = new EntryName(trimVersionsDir(basename, version), version);
-            return new Entry(this.file, en.baseName, en.entryName);
+            this.isDir = isDir;
+            this.name = name;
         }
 
         @Override
@@ -141,32 +108,6 @@
         }
     }
 
-    class EntryName {
-        final String baseName;
-        final String entryName;
-
-        EntryName(String name, int version) {
-            name = name.replace(File.separatorChar, '/');
-            String matchPath = "";
-            for (String path : pathsMap.get(version)) {
-                if (name.startsWith(path)
-                        && (path.length() > matchPath.length())) {
-                    matchPath = path;
-                }
-            }
-            name = safeName(name.substring(matchPath.length()));
-            // the old implementaton doesn't remove
-            // "./" if it was led by "/" (?)
-            if (name.startsWith("./")) {
-                name = name.substring(2);
-            }
-            baseName = name;
-            entryName = (version > BASE_VERSION)
-                    ? VERSIONS_DIR + version + "/" + baseName
-                    : baseName;
-        }
-    }
-
     // An entryName(path)->Entry map generated during "expand", it helps to
     // decide whether or not an existing entry in a jar file needs to be
     // replaced, during the "update" operation.
@@ -175,11 +116,8 @@
     // All entries need to be added/updated.
     Set<Entry> entries = new LinkedHashSet<>();
 
-    // All packages.
-    Set<String> packages = new HashSet<>();
-    // All actual entries added, or existing, in the jar file ( excl manifest
-    // and module-info.class ). Populated during create or update.
-    Set<String> jarEntries = new HashSet<>();
+    // module-info.class entries need to be added/updated.
+    Map<String,byte[]> moduleInfos = new HashMap<>();
 
     // A paths Set for each version, where each Set contains directories
     // specified by the "-C" operation.
@@ -208,19 +146,7 @@
     boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag, nflag, pflag, dflag;
 
     /* To support additional GNU Style informational options */
-    enum Info {
-        HELP(GNUStyleOptions::printHelp),
-        HELP_EXTRA(GNUStyleOptions::printHelpExtra),
-        COMPAT_HELP(GNUStyleOptions::printCompatHelp),
-        USAGE_TRYHELP(GNUStyleOptions::printUsageTryHelp),
-        VERSION(GNUStyleOptions::printVersion);
-
-        private Consumer<PrintWriter> printFunction;
-        Info(Consumer<PrintWriter> f) { this.printFunction = f; }
-        void print(PrintWriter out) { printFunction.accept(out); }
-    };
-    Info info;
-
+    Consumer<PrintWriter> info;
 
     /* Modular jar related options */
     Version moduleVersion;
@@ -228,8 +154,7 @@
     ModuleResolution moduleResolution = ModuleResolution.empty();
     ModuleFinder moduleFinder = ModuleFinder.of();
 
-    private static final String MODULE_INFO = "module-info.class";
-
+    static final String MODULE_INFO = "module-info.class";
     static final String MANIFEST_DIR = "META-INF/";
     static final String VERSIONS_DIR = MANIFEST_DIR + "versions/";
     static final String VERSION = "1.0";
@@ -324,7 +249,6 @@
                     }
                 }
             }
-
             if (cflag) {
                 Manifest manifest = null;
                 if (!Mflag) {
@@ -347,72 +271,60 @@
                         addMultiRelease(manifest);
                     }
                 }
-
-                Map<String,Path> moduleInfoPaths = new HashMap<>();
-                for (int version : filesMap.keySet()) {
-                    String[] files = filesMap.get(version);
-                    expand(null, files, false, moduleInfoPaths, version);
-                }
-
-                Map<String,byte[]> moduleInfos = new LinkedHashMap<>();
-                if (!moduleInfoPaths.isEmpty()) {
-                    if (!checkModuleInfos(moduleInfoPaths))
-                        return false;
-
-                    // root module-info first
-                    byte[] b = readModuleInfo(moduleInfoPaths.get(MODULE_INFO));
-                    moduleInfos.put(MODULE_INFO, b);
-                    for (Map.Entry<String,Path> e : moduleInfoPaths.entrySet())
-                        moduleInfos.putIfAbsent(e.getKey(), readModuleInfo(e.getValue()));
-
-                    if (!addExtendedModuleAttributes(moduleInfos))
-                        return false;
+                expand();
+                if (!moduleInfos.isEmpty()) {
+                    // All actual file entries (excl manifest and module-info.class)
+                    Set<String> jentries = new HashSet<>();
+                    // all packages if it's a class or resource
+                    Set<String> packages = new HashSet<>();
+                    entries.stream()
+                           .filter(e -> !e.isDir)
+                           .forEach( e -> {
+                               addPackageIfNamed(packages, e.name);
+                               jentries.add(e.name);
+                    });
+                    addExtendedModuleAttributes(moduleInfos, packages);
 
                     // Basic consistency checks for modular jars.
-                    if (!checkServices(moduleInfos.get(MODULE_INFO)))
+                    if (!checkModuleInfo(moduleInfos.get(MODULE_INFO), jentries))
                         return false;
 
                 } else if (moduleVersion != null || modulesToHash != null) {
                     error(getMsg("error.module.options.without.info"));
                     return false;
                 }
-
                 if (vflag && fname == null) {
                     // Disable verbose output so that it does not appear
                     // on stdout along with file data
                     // error("Warning: -v option ignored");
                     vflag = false;
                 }
-
                 final String tmpbase = (fname == null)
                         ? "tmpjar"
                         : fname.substring(fname.indexOf(File.separatorChar) + 1);
+
                 File tmpfile = createTemporaryFile(tmpbase, ".jar");
-
                 try (OutputStream out = new FileOutputStream(tmpfile)) {
-                    create(new BufferedOutputStream(out, 4096), manifest, moduleInfos);
+                    create(new BufferedOutputStream(out, 4096), manifest);
                 }
-
                 if (nflag) {
                     File packFile = createTemporaryFile(tmpbase, ".pack");
                     try {
                         Packer packer = Pack200.newPacker();
                         Map<String, String> p = packer.properties();
                         p.put(Packer.EFFORT, "1"); // Minimal effort to conserve CPU
-                        try (
-                                JarFile jarFile = new JarFile(tmpfile.getCanonicalPath());
-                                OutputStream pack = new FileOutputStream(packFile)
-                        ) {
+                        try (JarFile jarFile = new JarFile(tmpfile.getCanonicalPath());
+                             OutputStream pack = new FileOutputStream(packFile))
+                        {
                             packer.pack(jarFile, pack);
                         }
                         if (tmpfile.exists()) {
                             tmpfile.delete();
                         }
                         tmpfile = createTemporaryFile(tmpbase, ".jar");
-                        try (
-                                OutputStream out = new FileOutputStream(tmpfile);
-                                JarOutputStream jos = new JarOutputStream(out)
-                        ) {
+                        try (OutputStream out = new FileOutputStream(tmpfile);
+                             JarOutputStream jos = new JarOutputStream(out))
+                        {
                             Unpacker unpacker = Pack200.newUnpacker();
                             unpacker.unpack(packFile, jos);
                         }
@@ -420,9 +332,7 @@
                         Files.deleteIfExists(packFile.toPath());
                     }
                 }
-
                 validateAndClose(tmpfile);
-
             } else if (uflag) {
                 File inputFile = null, tmpFile = null;
                 if (fname != null) {
@@ -432,39 +342,20 @@
                     vflag = false;
                     tmpFile = createTemporaryFile("tmpjar", ".jar");
                 }
-
-                Map<String,Path> moduleInfoPaths = new HashMap<>();
-                for (int version : filesMap.keySet()) {
-                    String[] files = filesMap.get(version);
-                    expand(null, files, true, moduleInfoPaths, version);
+                expand();
+                try (FileInputStream in = (fname != null) ? new FileInputStream(inputFile)
+                        : new FileInputStream(FileDescriptor.in);
+                     FileOutputStream out = new FileOutputStream(tmpFile);
+                     InputStream manifest = (!Mflag && (mname != null)) ?
+                            (new FileInputStream(mname)) : null;
+                ) {
+                    boolean updateOk = update(in, new BufferedOutputStream(out),
+                        manifest, moduleInfos, null);
+                    if (ok) {
+                        ok = updateOk;
+                    }
                 }
-
-                Map<String,byte[]> moduleInfos = new HashMap<>();
-                for (Map.Entry<String,Path> e : moduleInfoPaths.entrySet())
-                    moduleInfos.put(e.getKey(), readModuleInfo(e.getValue()));
-
-                try (
-                        FileInputStream in = (fname != null) ? new FileInputStream(inputFile)
-                                : new FileInputStream(FileDescriptor.in);
-                        FileOutputStream out = new FileOutputStream(tmpFile);
-                        InputStream manifest = (!Mflag && (mname != null)) ?
-                                (new FileInputStream(mname)) : null;
-                ) {
-                        boolean updateOk = update(in, new BufferedOutputStream(out),
-                                manifest, moduleInfos, null);
-                        if (ok) {
-                            ok = updateOk;
-                        }
-                }
-
-                // Consistency checks for modular jars.
-                if (!moduleInfos.isEmpty()) {
-                    if(!checkServices(moduleInfos.get(MODULE_INFO)))
-                        return false;
-                }
-
                 validateAndClose(tmpFile);
-
             } else if (tflag) {
                 replaceFSC(filesMap);
                 // For the "list table contents" action, access using the
@@ -542,12 +433,15 @@
 
     private void validateAndClose(File tmpfile) throws IOException {
         if (ok && isMultiRelease) {
-            ok = validate(tmpfile.getCanonicalPath());
-            if (!ok) {
-                error(formatMsg("error.validator.jarfile.invalid", fname));
+            try (JarFile jf = new JarFile(tmpfile)) {
+                ok = Validator.validate(this, jf);
+                if (!ok) {
+                    error(formatMsg("error.validator.jarfile.invalid", fname));
+                }
+            } catch (IOException e) {
+                error(formatMsg2("error.validator.jarfile.exception", fname, e.getMessage()));
             }
         }
-
         Path path = tmpfile.toPath();
         try {
             if (ok) {
@@ -572,78 +466,9 @@
 
     Stream<String> filesToEntryNames(Map.Entry<Integer,String[]> fileEntries) {
         int version = fileEntries.getKey();
+        Set<String> cpaths = pathsMap.get(version);
         return Stream.of(fileEntries.getValue())
-                .map(f -> (new EntryName(f, version)).entryName);
-    }
-
-    // sort base entries before versioned entries, and sort entry classes with
-    // nested classes so that the top level class appears before the associated
-    // nested class
-    private Comparator<JarEntry> entryComparator = (je1, je2) ->  {
-        String s1 = je1.getName();
-        String s2 = je2.getName();
-        if (s1.equals(s2)) return 0;
-        boolean b1 = s1.startsWith(VERSIONS_DIR);
-        boolean b2 = s2.startsWith(VERSIONS_DIR);
-        if (b1 && !b2) return 1;
-        if (!b1 && b2) return -1;
-        int n = 0; // starting char for String compare
-        if (b1 && b2) {
-            // normally strings would be sorted so "10" goes before "9", but
-            // version number strings need to be sorted numerically
-            n = VERSIONS_DIR.length();   // skip the common prefix
-            int i1 = s1.indexOf('/', n);
-            int i2 = s1.indexOf('/', n);
-            if (i1 == -1) throw new InvalidJarException(s1);
-            if (i2 == -1) throw new InvalidJarException(s2);
-            // shorter version numbers go first
-            if (i1 != i2) return i1 - i2;
-            // otherwise, handle equal length numbers below
-        }
-        int l1 = s1.length();
-        int l2 = s2.length();
-        int lim = Math.min(l1, l2);
-        for (int k = n; k < lim; k++) {
-            char c1 = s1.charAt(k);
-            char c2 = s2.charAt(k);
-            if (c1 != c2) {
-                // change natural ordering so '.' comes before '$'
-                // i.e. top level classes come before nested classes
-                if (c1 == '$' && c2 == '.') return 1;
-                if (c1 == '.' && c2 == '$') return -1;
-                return c1 - c2;
-            }
-        }
-        return l1 - l2;
-    };
-
-    private boolean validate(String fname) {
-        boolean valid;
-
-        try (JarFile jf = new JarFile(fname)) {
-            Validator validator = new Validator(this, jf);
-            jf.stream()
-                    .filter(e -> !e.isDirectory())
-                    .filter(e -> !e.getName().equals(MANIFEST_NAME))
-                    .filter(e -> !e.getName().endsWith(MODULE_INFO))
-                    .sorted(entryComparator)
-                    .forEachOrdered(validator);
-             valid = validator.isValid();
-        } catch (IOException e) {
-            error(formatMsg2("error.validator.jarfile.exception", fname, e.getMessage()));
-            valid = false;
-        } catch (InvalidJarException e) {
-            error(formatMsg("error.validator.bad.entry.name", e.getMessage()));
-            valid = false;
-        }
-        return valid;
-    }
-
-    private static class InvalidJarException extends RuntimeException {
-        private static final long serialVersionUID = -3642329147299217726L;
-        InvalidJarException(String msg) {
-            super(msg);
-        }
+            .map(f -> toVersionedName(toEntryName(f, cpaths, false), version));
     }
 
     /**
@@ -668,20 +493,22 @@
             // Note: flags.length == 2 can be treated as the short version of
             // the GNU option since the there cannot be any other options,
             // excluding -C, as per the old way.
-            if (flags.startsWith("--")
-                || (flags.startsWith("-") && flags.length() == 2)) {
+            if (flags.startsWith("--") ||
+                (flags.startsWith("-") && flags.length() == 2)) {
                 try {
                     count = GNUStyleOptions.parseOptions(this, args);
                 } catch (GNUStyleOptions.BadArgs x) {
                     if (info == null) {
-                        error(x.getMessage());
-                        if (x.showUsage)
-                            Info.USAGE_TRYHELP.print(err);
+                        if (x.showUsage) {
+                            usageError(x.getMessage());
+                        } else {
+                            error(x.getMessage());
+                        }
                         return false;
                     }
                 }
                 if (info != null) {
-                    info.print(out);
+                    info.accept(out);
                     return true;
                 }
             } else {
@@ -851,19 +678,55 @@
      * Add the package of the given resource name if it's a .class
      * or a resource in a named package.
      */
-    boolean addPackageIfNamed(String name) {
+    void addPackageIfNamed(Set<String> packages, String name) {
         if (name.startsWith(VERSIONS_DIR)) {
-            throw new InternalError(name);
+            // trim the version dir prefix
+            int i0 = VERSIONS_DIR.length();
+            int i = name.indexOf('/', i0);
+            if (i <= 0) {
+                warn(formatMsg("warn.release.unexpected.versioned.entry", name));
+                return;
+            }
+            while (i0 < i) {
+                char c = name.charAt(i0);
+                if (c < '0' || c > '9') {
+                    warn(formatMsg("warn.release.unexpected.versioned.entry", name));
+                    return;
+                }
+                i0++;
+            }
+            name = name.substring(i + 1, name.length());
         }
-
         String pn = toPackageName(name);
         // add if this is a class or resource in a package
         if (Checks.isJavaIdentifier(pn)) {
             packages.add(pn);
-            return true;
+        }
+    }
+
+    private String toEntryName(String name, Set<String> cpaths, boolean isDir) {
+        name = name.replace(File.separatorChar, '/');
+        if (isDir) {
+            name = name.endsWith("/") ? name : name + "/";
         }
+        String matchPath = "";
+        for (String path : cpaths) {
+            if (name.startsWith(path) && path.length() > matchPath.length()) {
+                matchPath = path;
+            }
+        }
+        name = safeName(name.substring(matchPath.length()));
+        // the old implementaton doesn't remove
+        // "./" if it was led by "/" (?)
+        if (name.startsWith("./")) {
+            name = name.substring(2);
+        }
+        return name;
+    }
 
-        return false;
+    private static String toVersionedName(String name, int version) {
+        return version > BASE_VERSION
+                ? VERSIONS_DIR + version + "/" + name : name;
     }
 
     private static String toPackageName(String path) {
@@ -875,57 +738,23 @@
         }
     }
 
-    /*
-     * Returns true if the given entry is a valid entry of the given version.
-     */
-    private boolean isValidVersionedEntry(Entry entry, int version) {
-        String name = entry.basename;
-        if (name.startsWith(VERSIONS_DIR) && version != BASE_VERSION) {
-            int i = name.indexOf('/', VERSIONS_DIR.length());
-            // name == -1 -> not a versioned directory, something else
-            if (i == -1)
-                return false;
-            try {
-                String v = name.substring(VERSIONS_DIR.length(), i);
-                return Integer.valueOf(v) == version;
-            } catch (NumberFormatException x) {
-                return false;
-            }
+    private void expand() throws IOException {
+        for (int version : filesMap.keySet()) {
+            String[] files = filesMap.get(version);
+            expand(null, files, pathsMap.get(version), version);
         }
-        return true;
-    }
-
-    /*
-     * Trim META-INF/versions/$version/ from the given name if the
-     * given name is a versioned entry of the given version; or
-     * of any version if the given version is BASE_VERSION
-     */
-    private String trimVersionsDir(String name, int version) {
-        if (name.startsWith(VERSIONS_DIR)) {
-            int i = name.indexOf('/', VERSIONS_DIR.length());
-            if (i >= 0) {
-                try {
-                    String v = name.substring(VERSIONS_DIR.length(), i);
-                    if (version == BASE_VERSION || Integer.valueOf(v) == version) {
-                        return name.substring(i + 1, name.length());
-                    }
-                } catch (NumberFormatException x) {}
-            }
-            throw new InternalError("unexpected versioned entry: " +
-                    name + " version " + version);
-        }
-        return name;
     }
 
     /**
      * Expands list of files to process into full list of all files that
      * can be found by recursively descending directories.
+     *
+     * @param dir    parent directory
+     * @param file s list of files to expand
+     * @param cpaths set of directories specified by -C option for the files
+     * @throws IOException if an I/O error occurs
      */
-    void expand(File dir,
-                String[] files,
-                boolean isUpdate,
-                Map<String,Path> moduleInfoPaths,
-                int version)
+    private void expand(File dir, String[] files, Set<String> cpaths, int version)
         throws IOException
     {
         if (files == null)
@@ -938,47 +767,48 @@
             else
                 f = new File(dir, files[i]);
 
-            Entry e = new Entry(version, f);
-            String entryName = e.entryname;
-            Entry entry = e;
-            if (e.basename.startsWith(VERSIONS_DIR) && isValidVersionedEntry(e, version)) {
-                entry = e.toVersionedEntry(version);
-            }
-            if (f.isFile()) {
-                if (entryName.endsWith(MODULE_INFO)) {
-                    moduleInfoPaths.put(entryName, f.toPath());
-                    if (isUpdate)
-                        entryMap.put(entryName, entry);
-                } else if (isValidVersionedEntry(entry, version)) {
-                    if (entries.add(entry)) {
-                        jarEntries.add(entryName);
-                        // add the package if it's a class or resource
-                        addPackageIfNamed(trimVersionsDir(entry.basename, version));
-                        if (isUpdate)
-                            entryMap.put(entryName, entry);
-                    }
-                } else {
+            boolean isDir = f.isDirectory();
+            String name = toEntryName(f.getPath(), cpaths, isDir);
+
+            if (version != BASE_VERSION) {
+                if (name.startsWith(VERSIONS_DIR)) {
+                    // the entry starts with VERSIONS_DIR and version != BASE_VERSION,
+                    // which means the "[dirs|files]" in --release v [dirs|files]
+                    // includes VERSIONS_DIR-ed entries --> warning and skip (?)
                     error(formatMsg2("error.release.unexpected.versioned.entry",
-                                      entry.basename, String.valueOf(version)));
+                                     name, String.valueOf(version)));
                     ok = false;
+                    return;
                 }
-            } else if (f.isDirectory()) {
-                if (isValidVersionedEntry(entry, version)) {
-                    if (entries.add(entry)) {
-                        if (isUpdate) {
-                            entryMap.put(entryName, entry);
-                        }
+                name = toVersionedName(name, version);
+            }
+
+            if (f.isFile()) {
+                Entry e = new Entry(f, name, false);
+                if (isModuleInfoEntry(name)) {
+                    moduleInfos.putIfAbsent(name, Files.readAllBytes(f.toPath()));
+                    if (uflag)
+                        entryMap.put(name, e);
+                } else if (entries.add(e)) {
+                    if (uflag)
+                        entryMap.put(name, e);
+                }
+            } else if (isDir) {
+                Entry e = new Entry(f, name, true);
+                if (entries.add(e)) {
+                    // utilize entryMap for the duplicate dir check even in
+                    // case of cflag == true.
+                    // dir name confilict/duplicate could happen with -C option.
+                    // just remove the last "e" from the "entries" (zos will fail
+                    // with "duplicated" entries), but continue expanding the
+                    // sub tree
+                    if (entryMap.containsKey(name)) {
+                        entries.remove(e);
+                    } else {
+                        entryMap.put(name, e);
                     }
-                } else if (entry.basename.equals(VERSIONS_DIR)) {
-                    if (vflag) {
-                        output(formatMsg("out.ignore.entry", entry.basename));
-                    }
-                } else {
-                    error(formatMsg2("error.release.unexpected.versioned.entry",
-                                      entry.basename, String.valueOf(version)));
-                    ok = false;
+                    expand(f, f.list(), cpaths, version);
                 }
-                expand(f, f.list(), isUpdate, moduleInfoPaths, version);
             } else {
                 error(formatMsg("error.nosuch.fileordir", String.valueOf(f)));
                 ok = false;
@@ -989,52 +819,36 @@
     /**
      * Creates a new JAR file.
      */
-    void create(OutputStream out, Manifest manifest, Map<String,byte[]> moduleInfos)
-        throws IOException
+    void create(OutputStream out, Manifest manifest) throws IOException
     {
-        ZipOutputStream zos = new JarOutputStream(out);
-        if (flag0) {
-            zos.setMethod(ZipOutputStream.STORED);
-        }
-        // TODO: check module-info attributes against manifest ??
-        if (manifest != null) {
-            if (vflag) {
-                output(getMsg("out.added.manifest"));
-            }
-            ZipEntry e = new ZipEntry(MANIFEST_DIR);
-            e.setTime(System.currentTimeMillis());
-            e.setSize(0);
-            e.setCrc(0);
-            zos.putNextEntry(e);
-            e = new ZipEntry(MANIFEST_NAME);
-            e.setTime(System.currentTimeMillis());
+        try (ZipOutputStream zos = new JarOutputStream(out)) {
             if (flag0) {
-                crc32Manifest(e, manifest);
+                zos.setMethod(ZipOutputStream.STORED);
             }
-            zos.putNextEntry(e);
-            manifest.write(zos);
-            zos.closeEntry();
-        }
-        for (Map.Entry<String,byte[]> mi : moduleInfos.entrySet()) {
-            String entryName = mi.getKey();
-            byte[] miBytes = mi.getValue();
-            if (vflag) {
-                output(formatMsg("out.added.module-info", entryName));
+            // TODO: check module-info attributes against manifest ??
+            if (manifest != null) {
+                if (vflag) {
+                    output(getMsg("out.added.manifest"));
+                }
+                ZipEntry e = new ZipEntry(MANIFEST_DIR);
+                e.setTime(System.currentTimeMillis());
+                e.setSize(0);
+                e.setCrc(0);
+                zos.putNextEntry(e);
+                e = new ZipEntry(MANIFEST_NAME);
+                e.setTime(System.currentTimeMillis());
+                if (flag0) {
+                    crc32Manifest(e, manifest);
+                }
+                zos.putNextEntry(e);
+                manifest.write(zos);
+                zos.closeEntry();
             }
-            ZipEntry e = new ZipEntry(mi.getKey());
-            e.setTime(System.currentTimeMillis());
-            if (flag0) {
-                crc32ModuleInfo(e, miBytes);
+            updateModuleInfo(moduleInfos, zos);
+            for (Entry entry : entries) {
+                addFile(zos, entry);
             }
-            zos.putNextEntry(e);
-            ByteArrayInputStream in = new ByteArrayInputStream(miBytes);
-            in.transferTo(zos);
-            zos.closeEntry();
         }
-        for (Entry entry : entries) {
-            addFile(zos, entry);
-        }
-        zos.close();
     }
 
     private char toUpperCaseASCII(char c) {
@@ -1062,30 +876,6 @@
     }
 
     /**
-     * Returns true of the given module-info's are located in acceptable
-     * locations.  Otherwise, outputs an appropriate message and returns false.
-     */
-    private boolean checkModuleInfos(Map<String,?> moduleInfos) {
-        // there must always be, at least, a root module-info
-        if (!moduleInfos.containsKey(MODULE_INFO)) {
-            error(getMsg("error.versioned.info.without.root"));
-            return false;
-        }
-
-        // module-info can only appear in the root, or a versioned section
-        Optional<String> other = moduleInfos.keySet().stream()
-                .filter(x -> !x.equals(MODULE_INFO))
-                .filter(x -> !x.startsWith(VERSIONS_DIR))
-                .findFirst();
-
-        if (other.isPresent()) {
-            error(formatMsg("error.unexpected.module-info", other.get()));
-            return false;
-        }
-        return true;
-    }
-
-    /**
      * Updates an existing jar file.
      */
     boolean update(InputStream in, OutputStream out,
@@ -1099,6 +889,10 @@
         boolean foundManifest = false;
         boolean updateOk = true;
 
+        // All actual entries added/updated/existing, in the jar file (excl manifest
+        // and module-info.class ).
+        Set<String> jentries = new HashSet<>();
+
         if (jarIndex != null) {
             addIndex(jarIndex, zos);
         }
@@ -1108,7 +902,7 @@
             String name = e.getName();
 
             boolean isManifestEntry = equalsIgnoreCase(name, MANIFEST_NAME);
-            boolean isModuleInfoEntry = name.endsWith(MODULE_INFO);
+            boolean isModuleInfoEntry = isModuleInfoEntry(name);
 
             if ((jarIndex != null && equalsIgnoreCase(name, INDEX_NAME))
                 || (Mflag && isManifestEntry)) {
@@ -1127,7 +921,6 @@
                         return false;
                     }
                 }
-
                 // Update the manifest.
                 Manifest old = new Manifest(zis);
                 if (newManifest != null) {
@@ -1137,7 +930,7 @@
                     return false;
                 }
             } else if (moduleInfos != null && isModuleInfoEntry) {
-                moduleInfos.putIfAbsent(name, readModuleInfo(zis));
+                moduleInfos.putIfAbsent(name, zis.readAllBytes());
             } else {
                 boolean isDir = e.isDirectory();
                 if (!entryMap.containsKey(name)) { // copy the old stuff
@@ -1160,11 +953,8 @@
                     entries.remove(ent);
                     isDir = ent.isDir;
                 }
-
-                jarEntries.add(name);
                 if (!isDir) {
-                    // add the package if it's a class or resource
-                    addPackageIfNamed(trimVersionsDir(name, BASE_VERSION));
+                    jentries.add(name);
                 }
             }
         }
@@ -1172,6 +962,9 @@
         // add the remaining new files
         for (Entry entry : entries) {
             addFile(zos, entry);
+            if (!entry.isDir) {
+                jentries.add(entry.name);
+            }
         }
         if (!foundManifest) {
             if (newManifest != null) {
@@ -1188,35 +981,24 @@
                 }
             }
         }
-
-        if (moduleInfos != null && !moduleInfos.isEmpty()) {
-            if (!checkModuleInfos(moduleInfos))
+        if (updateOk) {
+            if (moduleInfos != null && !moduleInfos.isEmpty()) {
+                Set<String> pkgs = new HashSet<>();
+                jentries.forEach( je -> addPackageIfNamed(pkgs, je));
+                addExtendedModuleAttributes(moduleInfos, pkgs);
+                updateOk = checkModuleInfo(moduleInfos.get(MODULE_INFO), jentries);
+                updateModuleInfo(moduleInfos, zos);
+                // TODO: check manifest main classes, etc
+            } else if (moduleVersion != null || modulesToHash != null) {
+                error(getMsg("error.module.options.without.info"));
                 updateOk = false;
-
-            if (updateOk) {
-                if (!addExtendedModuleAttributes(moduleInfos))
-                    updateOk = false;
             }
-
-            // TODO: check manifest main classes, etc
-
-            if (updateOk) {
-                for (Map.Entry<String,byte[]> mi : moduleInfos.entrySet()) {
-                    if (!updateModuleInfo(mi.getValue(), zos, mi.getKey()))
-                        updateOk = false;
-                }
-            }
-        } else if (moduleVersion != null || modulesToHash != null) {
-            error(getMsg("error.module.options.without.info"));
-            updateOk = false;
         }
-
         zis.close();
         zos.close();
         return updateOk;
     }
 
-
     private void addIndex(JarIndex index, ZipOutputStream zos)
         throws IOException
     {
@@ -1232,20 +1014,25 @@
         zos.closeEntry();
     }
 
-    private boolean updateModuleInfo(byte[] moduleInfoBytes, ZipOutputStream zos, String entryName)
+    private void updateModuleInfo(Map<String,byte[]> moduleInfos, ZipOutputStream zos)
         throws IOException
     {
-        ZipEntry e = new ZipEntry(entryName);
-        e.setTime(System.currentTimeMillis());
-        if (flag0) {
-            crc32ModuleInfo(e, moduleInfoBytes);
+        String fmt = uflag ? "out.update.module-info": "out.added.module-info";
+        for (Map.Entry<String,byte[]> mi : moduleInfos.entrySet()) {
+            String name = mi.getKey();
+            byte[] bytes = mi.getValue();
+            ZipEntry e = new ZipEntry(name);
+            e.setTime(System.currentTimeMillis());
+            if (flag0) {
+                crc32ModuleInfo(e, bytes);
+            }
+            zos.putNextEntry(e);
+            zos.write(bytes);
+            zos.closeEntry();
+            if (vflag) {
+                output(formatMsg(fmt, name));
+            }
         }
-        zos.putNextEntry(e);
-        zos.write(moduleInfoBytes);
-        if (vflag) {
-            output(formatMsg("out.update.module-info", entryName));
-        }
-        return true;
     }
 
     private boolean updateManifest(Manifest m, ZipOutputStream zos)
@@ -1358,11 +1145,9 @@
      * Adds a new file entry to the ZIP output stream.
      */
     void addFile(ZipOutputStream zos, Entry entry) throws IOException {
-        // skip the generation of directory entries for META-INF/versions/*/
-        if (entry.basename.isEmpty()) return;
 
         File file = entry.file;
-        String name = entry.entryname;
+        String name = entry.name;
         boolean isDir = entry.isDir;
 
         if (name.equals("") || name.equals(".") || name.equals(zname)) {
@@ -1444,11 +1229,8 @@
      * @throws IOException if an I/O error occurs
      */
     private void copy(File from, OutputStream to) throws IOException {
-        InputStream in = new FileInputStream(from);
-        try {
+        try (InputStream in = new FileInputStream(from)) {
             copy(in, to);
-        } finally {
-            in.close();
         }
     }
 
@@ -1461,11 +1243,8 @@
      * @throws IOException if an I/O error occurs
      */
     private void copy(InputStream from, File to) throws IOException {
-        OutputStream out = new FileOutputStream(to);
-        try {
+        try (OutputStream out = new FileOutputStream(to)) {
             copy(from, out);
-        } finally {
-            out.close();
         }
     }
 
@@ -1825,7 +1604,7 @@
      */
     void usageError(String s) {
         err.println(s);
-        Info.USAGE_TRYHELP.print(err);
+        err.println(getMsg("main.usage.summary.try"));
     }
 
     /**
@@ -1934,16 +1713,6 @@
         return tmpfile;
     }
 
-    private static byte[] readModuleInfo(InputStream zis) throws IOException {
-        return zis.readAllBytes();
-    }
-
-    private static byte[] readModuleInfo(Path path) throws IOException {
-        try (InputStream is = Files.newInputStream(path)) {
-            return is.readAllBytes();
-        }
-    }
-
     // Modular jar support
 
     static <T> String toString(Collection<T> c,
@@ -1951,7 +1720,6 @@
                                CharSequence suffix ) {
         if (c.isEmpty())
             return "";
-
         return c.stream().map(e -> e.toString())
                            .collect(joining(", ", prefix, suffix));
     }
@@ -2045,136 +1813,84 @@
 
         md.osVersion().ifPresent(v -> sb.append("\n  operating-system-version " + v));
 
-        if (hashes != null) {
-            hashes.names().stream().sorted().forEach(
-                    mod -> sb.append("\n  hashes ").append(mod).append(" ")
-                             .append(hashes.algorithm()).append(" ")
-                             .append(toHex(hashes.hashFor(mod))));
+       if (hashes != null) {
+           hashes.names().stream().sorted().forEach(
+                   mod -> sb.append("\n  hashes ").append(mod).append(" ")
+                            .append(hashes.algorithm()).append(" ")
+                            .append(toHex(hashes.hashFor(mod))));
         }
 
         output(sb.toString());
     }
 
     private static String toHex(byte[] ba) {
-        StringBuilder sb = new StringBuilder(ba.length);
+        StringBuilder sb = new StringBuilder(ba.length << 1);
         for (byte b: ba) {
             sb.append(String.format("%02x", b & 0xff));
         }
         return sb.toString();
     }
 
-    private static String toBinaryName(String classname) {
+    static String toBinaryName(String classname) {
         return (classname.replace('.', '/')) + ".class";
     }
 
-    /* A module must have the implementation class of the services it 'provides'. */
-    private boolean checkServices(byte[] moduleInfoBytes)
+    private boolean checkModuleInfo(byte[] moduleInfoBytes, Set<String> entries)
         throws IOException
     {
-        ModuleDescriptor md = ModuleDescriptor.read(ByteBuffer.wrap(moduleInfoBytes));
-        Set<String> missing = md.provides()
-                                .stream()
-                                .map(Provides::providers)
-                                .flatMap(List::stream)
-                                .filter(p -> !jarEntries.contains(toBinaryName(p)))
-                                .collect(Collectors.toSet());
-        if (missing.size() > 0) {
-            missing.stream().forEach(s -> fatalError(formatMsg("error.missing.provider", s)));
-            return false;
+        boolean ok = true;
+        if (moduleInfoBytes != null) {  // no root module-info.class if null
+            try {
+                // ModuleDescriptor.read() checks open/exported pkgs vs packages
+                ModuleDescriptor md = ModuleDescriptor.read(ByteBuffer.wrap(moduleInfoBytes));
+                // A module must have the implementation class of the services it 'provides'.
+                if (md.provides().stream().map(Provides::providers).flatMap(List::stream)
+                      .filter(p -> !entries.contains(toBinaryName(p)))
+                      .peek(p -> fatalError(formatMsg("error.missing.provider", p)))
+                      .count() != 0) {
+                    ok = false;
+                }
+            } catch (InvalidModuleDescriptorException x) {
+                fatalError(x.getMessage());
+                ok = false;
+            }
         }
-        return true;
+        return ok;
     }
 
     /**
      * Adds extended modules attributes to the given module-info's.  The given
      * Map values are updated in-place. Returns false if an error occurs.
      */
-    private boolean addExtendedModuleAttributes(Map<String,byte[]> moduleInfos)
+    private void addExtendedModuleAttributes(Map<String,byte[]> moduleInfos,
+                                                Set<String> packages)
         throws IOException
     {
-        assert !moduleInfos.isEmpty() && moduleInfos.get(MODULE_INFO) != null;
-
-        ByteBuffer bb = ByteBuffer.wrap(moduleInfos.get(MODULE_INFO));
-        ModuleDescriptor rd = ModuleDescriptor.read(bb);
-
-        concealedPackages = findConcealedPackages(rd);
-
         for (Map.Entry<String,byte[]> e: moduleInfos.entrySet()) {
-            ModuleDescriptor vd = ModuleDescriptor.read(ByteBuffer.wrap(e.getValue()));
-            if (!(isValidVersionedDescriptor(vd, rd)))
-                return false;
-            e.setValue(extendedInfoBytes(rd, vd, e.getValue(), packages));
+            ModuleDescriptor md = ModuleDescriptor.read(ByteBuffer.wrap(e.getValue()));
+            e.setValue(extendedInfoBytes(md, e.getValue(), packages));
         }
-        return true;
-    }
-
-    private Set<String> findConcealedPackages(ModuleDescriptor md) {
-        Objects.requireNonNull(md);
-        Set<String> concealed = new HashSet<>(packages);
-        md.exports().stream().map(Exports::source).forEach(concealed::remove);
-        md.opens().stream().map(Opens::source).forEach(concealed::remove);
-        return concealed;
-    }
-
-    private static boolean isPlatformModule(String name) {
-        return name.startsWith("java.") || name.startsWith("jdk.");
     }
 
-    /**
-     * Tells whether or not the given versioned module descriptor's attributes
-     * are valid when compared against the given root module descriptor.
-     *
-     * A versioned module descriptor must be identical to the root module
-     * descriptor, with two exceptions:
-     *  - A versioned descriptor can have different non-public `requires`
-     *    clauses of platform ( `java.*` and `jdk.*` ) modules, and
-     *  - A versioned descriptor can have different `uses` clauses, even of
-     *    service types defined outside of the platform modules.
-     */
-    private boolean isValidVersionedDescriptor(ModuleDescriptor vd,
-                                               ModuleDescriptor rd)
-        throws IOException
-    {
-        if (!rd.name().equals(vd.name())) {
-            fatalError(getMsg("error.versioned.info.name.notequal"));
-            return false;
-        }
-        if (!rd.requires().equals(vd.requires())) {
-            Set<Requires> rootRequires = rd.requires();
-            for (Requires r : vd.requires()) {
-                if (rootRequires.contains(r)) {
-                    continue;
-                } else if (r.modifiers().contains(Requires.Modifier.TRANSITIVE)) {
-                    fatalError(getMsg("error.versioned.info.requires.transitive"));
+    static boolean isModuleInfoEntry(String name) {
+        // root or versioned module-info.class
+        if (name.endsWith(MODULE_INFO)) {
+            int end = name.length() - MODULE_INFO.length();
+            if (end == 0)
+                return true;
+            if (name.startsWith(VERSIONS_DIR)) {
+                int off = VERSIONS_DIR.length();
+                if (off == end)      // meta-inf/versions/module-info.class
                     return false;
-                } else if (!isPlatformModule(r.name())) {
-                    fatalError(getMsg("error.versioned.info.requires.added"));
-                    return false;
+                while (off < end - 1) {
+                    char c = name.charAt(off++);
+                    if (c < '0' || c > '9')
+                        return false;
                 }
-            }
-            for (Requires r : rootRequires) {
-                Set<Requires> mdRequires = vd.requires();
-                if (mdRequires.contains(r)) {
-                    continue;
-                } else if (!isPlatformModule(r.name())) {
-                    fatalError(getMsg("error.versioned.info.requires.dropped"));
-                    return false;
-                }
+                return name.charAt(off) == '/';
             }
         }
-        if (!rd.exports().equals(vd.exports())) {
-            fatalError(getMsg("error.versioned.info.exports.notequal"));
-            return false;
-        }
-        if (!rd.opens().equals(vd.opens())) {
-            fatalError(getMsg("error.versioned.info.opens.notequal"));
-            return false;
-        }
-        if (!rd.provides().equals(vd.provides())) {
-            fatalError(getMsg("error.versioned.info.provides.notequal"));
-            return false;
-        }
-        return true;
+        return false;
     }
 
     /**
@@ -2185,8 +1901,7 @@
      * then the corresponding class file attributes are added to the
      * module-info here.
      */
-    private byte[] extendedInfoBytes(ModuleDescriptor rootDescriptor,
-                                     ModuleDescriptor md,
+    private byte[] extendedInfoBytes(ModuleDescriptor md,
                                      byte[] miBytes,
                                      Set<String> packages)
         throws IOException
@@ -2201,14 +1916,10 @@
         // --main-class
         if (ename != null)
             extender.mainClass(ename);
-        else if (rootDescriptor.mainClass().isPresent())
-            extender.mainClass(rootDescriptor.mainClass().get());
 
         // --module-version
         if (moduleVersion != null)
             extender.version(moduleVersion);
-        else if (rootDescriptor.version().isPresent())
-            extender.version(rootDescriptor.version().get());
 
         // --hash-modules
         if (modulesToHash != null) {
@@ -2218,8 +1929,7 @@
             if (moduleHashes != null) {
                 extender.hashes(moduleHashes);
             } else {
-                // should it issue warning or silent?
-                System.out.println("warning: no module is recorded in hash in " + mn);
+                warn("warning: no module is recorded in hash in " + mn);
             }
         }
 
@@ -2235,10 +1945,9 @@
      * Compute and record hashes
      */
     private class Hasher {
+        final ModuleHashesBuilder hashesBuilder;
         final ModuleFinder finder;
-        final Map<String, Path> moduleNameToPath;
         final Set<String> modules;
-        final Configuration configuration;
         Hasher(ModuleDescriptor descriptor, String fname) throws IOException {
             // Create a module finder that finds the modular JAR
             // being created/updated
@@ -2268,119 +1977,46 @@
                     }
                 });
 
-            // Determine the modules that matches the modulesToHash pattern
-            this.modules = moduleFinder.findAll().stream()
-                .map(moduleReference -> moduleReference.descriptor().name())
+            // Determine the modules that matches the pattern {@code modulesToHash}
+            Set<String> roots = finder.findAll().stream()
+                .map(ref -> ref.descriptor().name())
                 .filter(mn -> modulesToHash.matcher(mn).find())
                 .collect(Collectors.toSet());
 
-            // a map from a module name to Path of the modular JAR
-            this.moduleNameToPath = moduleFinder.findAll().stream()
-                .map(ModuleReference::descriptor)
-                .map(ModuleDescriptor::name)
-                .collect(Collectors.toMap(Function.identity(), mn -> moduleToPath(mn)));
-
-            Configuration config = null;
-            try {
-                config = Configuration.empty()
-                    .resolveRequires(ModuleFinder.ofSystem(), finder, modules);
-            } catch (ResolutionException e) {
-                // should it throw an error?  or emit a warning
-                System.out.println("warning: " + e.getMessage());
+            // use system module path unless it creates a modular JAR for
+            // a module that is present in the system image e.g. upgradeable
+            // module
+            ModuleFinder system;
+            String name = descriptor.name();
+            if (name != null && ModuleFinder.ofSystem().find(name).isPresent()) {
+                system = ModuleFinder.of();
+            } else {
+                system = ModuleFinder.ofSystem();
             }
-            this.configuration = config;
-        }
+            // get a resolved module graph
+            Configuration config =
+                Configuration.empty().resolveRequires(system, finder, roots);
 
-        /**
-         * Compute hashes of the modules that depend upon the specified
-         * module directly or indirectly.
-         */
-        ModuleHashes computeHashes(String name) {
-            // the transposed graph includes all modules in the resolved graph
-            Map<String, Set<String>> graph = transpose();
+            // filter modules resolved from the system module finder
+            this.modules = config.modules().stream()
+                .map(ResolvedModule::name)
+                .filter(mn -> roots.contains(mn) && !system.find(mn).isPresent())
+                .collect(Collectors.toSet());
 
-            // find the modules that transitively depend upon the specified name
-            Deque<String> deque = new ArrayDeque<>();
-            deque.add(name);
-            Set<String> mods = visitNodes(graph, deque);
-
-            // filter modules matching the pattern specified in --hash-modules,
-            // as well as the modular jar file that is being created / updated
-            Map<String, Path> modulesForHash = mods.stream()
-                .filter(mn -> !mn.equals(name) && modules.contains(mn))
-                .collect(Collectors.toMap(Function.identity(), moduleNameToPath::get));
-
-            if (modulesForHash.isEmpty())
-                return null;
-
-            return ModuleHashes.generate(modulesForHash, "SHA-256");
+            this.hashesBuilder = new ModuleHashesBuilder(config, modules);
         }
 
         /**
-         * Returns all nodes traversed from the given roots.
+         * Compute hashes of the specified module.
+         *
+         * It records the hashing modules that depend upon the specified
+         * module directly or indirectly.
          */
-        private Set<String> visitNodes(Map<String, Set<String>> graph,
-                                       Deque<String> roots) {
-            Set<String> visited = new HashSet<>();
-            while (!roots.isEmpty()) {
-                String mn = roots.pop();
-                if (!visited.contains(mn)) {
-                    visited.add(mn);
-
-                    // the given roots may not be part of the graph
-                    if (graph.containsKey(mn)) {
-                        for (String dm : graph.get(mn)) {
-                            if (!visited.contains(dm))
-                                roots.push(dm);
-                        }
-                    }
-                }
-            }
-            return visited;
-        }
-
-        /**
-         * Returns a transposed graph from the resolved module graph.
-         */
-        private Map<String, Set<String>> transpose() {
-            Map<String, Set<String>> transposedGraph = new HashMap<>();
-            Deque<String> deque = new ArrayDeque<>(modules);
+        ModuleHashes computeHashes(String name) {
+            if (hashesBuilder == null)
+                return null;
 
-            Set<String> visited = new HashSet<>();
-            while (!deque.isEmpty()) {
-                String mn = deque.pop();
-                if (!visited.contains(mn)) {
-                    visited.add(mn);
-
-                    // add an empty set
-                    transposedGraph.computeIfAbsent(mn, _k -> new HashSet<>());
-
-                    ResolvedModule resolvedModule = configuration.findModule(mn).get();
-                    for (ResolvedModule dm : resolvedModule.reads()) {
-                        String name = dm.name();
-                        if (!visited.contains(name)) {
-                            deque.push(name);
-                        }
-                        // reverse edge
-                        transposedGraph.computeIfAbsent(name, _k -> new HashSet<>())
-                                       .add(mn);
-                    }
-                }
-            }
-            return transposedGraph;
-        }
-
-        private Path moduleToPath(String name) {
-            ModuleReference mref = moduleFinder.find(name).orElseThrow(
-                () -> new InternalError(formatMsg2("error.hash.dep",name , name)));
-
-            URI uri = mref.location().get();
-            Path path = Paths.get(uri);
-            String fn = path.getFileName().toString();
-            if (!fn.endsWith(".jar")) {
-                throw new UnsupportedOperationException(path + " is not a modular JAR");
-            }
-            return path;
+            return hashesBuilder.computeHashes(Set.of(name)).get(name);
         }
     }
 }
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Validator.java	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Validator.java	Tue Jan 17 11:35:28 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -25,32 +25,120 @@
 
 package sun.tools.jar;
 
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.module.InvalidModuleDescriptorException;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.InvalidModuleDescriptorException;
+import java.lang.module.ModuleDescriptor.Opens;
+import java.lang.module.ModuleDescriptor.Provides;
+import java.lang.module.ModuleDescriptor.Requires;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.function.Consumer;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
 
-final class Validator implements Consumer<JarEntry> {
+import static java.util.jar.JarFile.MANIFEST_NAME;
+import static sun.tools.jar.Main.VERSIONS_DIR;
+import static sun.tools.jar.Main.MODULE_INFO;
+import static sun.tools.jar.Main.getMsg;
+import static sun.tools.jar.Main.formatMsg;
+import static sun.tools.jar.Main.formatMsg2;
+import static sun.tools.jar.Main.toBinaryName;
+import static sun.tools.jar.Main.isModuleInfoEntry;
+
+final class Validator {
     private final static boolean DEBUG = Boolean.getBoolean("jar.debug");
     private final  Map<String,FingerPrint> fps = new HashMap<>();
-    private final int vdlen = Main.VERSIONS_DIR.length();
+    private static final int vdlen = VERSIONS_DIR.length();
     private final Main main;
     private final JarFile jf;
     private int oldVersion = -1;
     private String currentTopLevelName;
     private boolean isValid = true;
+    private Set<String> concealedPkgs;
+    private ModuleDescriptor md;
 
-    Validator(Main main, JarFile jf) {
+    private Validator(Main main, JarFile jf) {
         this.main = main;
         this.jf = jf;
+        loadModuleDescriptor();
+    }
+
+    static boolean validate(Main main, JarFile jf) throws IOException {
+        return new Validator(main, jf).validate();
+    }
+
+    private boolean validate() {
+        try {
+            jf.stream()
+              .filter(e -> !e.isDirectory() &&
+                      !e.getName().equals(MANIFEST_NAME))
+              .sorted(entryComparator)
+              .forEachOrdered(e -> validate(e));
+            return isValid;
+        } catch (InvalidJarException e) {
+            error(formatMsg("error.validator.bad.entry.name", e.getMessage()));
+        }
+        return false;
+    }
+
+    private static class InvalidJarException extends RuntimeException {
+        private static final long serialVersionUID = -3642329147299217726L;
+        InvalidJarException(String msg) {
+            super(msg);
+        }
     }
 
-    boolean isValid() {
-        return isValid;
-    }
+    // sort base entries before versioned entries, and sort entry classes with
+    // nested classes so that the top level class appears before the associated
+    // nested class
+    private static Comparator<JarEntry> entryComparator = (je1, je2) ->  {
+        String s1 = je1.getName();
+        String s2 = je2.getName();
+        if (s1.equals(s2)) return 0;
+        boolean b1 = s1.startsWith(VERSIONS_DIR);
+        boolean b2 = s2.startsWith(VERSIONS_DIR);
+        if (b1 && !b2) return 1;
+        if (!b1 && b2) return -1;
+        int n = 0; // starting char for String compare
+        if (b1 && b2) {
+            // normally strings would be sorted so "10" goes before "9", but
+            // version number strings need to be sorted numerically
+            n = VERSIONS_DIR.length();   // skip the common prefix
+            int i1 = s1.indexOf('/', n);
+            int i2 = s1.indexOf('/', n);
+            if (i1 == -1) throw new InvalidJarException(s1);
+            if (i2 == -1) throw new InvalidJarException(s2);
+            // shorter version numbers go first
+            if (i1 != i2) return i1 - i2;
+            // otherwise, handle equal length numbers below
+        }
+        int l1 = s1.length();
+        int l2 = s2.length();
+        int lim = Math.min(l1, l2);
+        for (int k = n; k < lim; k++) {
+            char c1 = s1.charAt(k);
+            char c2 = s2.charAt(k);
+            if (c1 != c2) {
+                // change natural ordering so '.' comes before '$'
+                // i.e. top level classes come before nested classes
+                if (c1 == '$' && c2 == '.') return 1;
+                if (c1 == '.' && c2 == '$') return -1;
+                return c1 - c2;
+            }
+        }
+        return l1 - l2;
+    };
 
     /*
      *  Validator has state and assumes entries provided to accept are ordered
@@ -59,7 +147,7 @@
      *  classes must be ordered so that the top level class is before the associated
      *  nested class(es).
     */
-    public void accept(JarEntry je) {
+    public void validate(JarEntry je) {
         String entryName = je.getName();
 
         // directories are always accepted
@@ -68,13 +156,20 @@
             return;
         }
 
+        // validate the versioned module-info
+        if (isModuleInfoEntry(entryName)) {
+            if (entryName.length() != MODULE_INFO.length())
+                checkModuleDescriptor(je);
+            return;
+        }
+
         // figure out the version and basename from the JarEntry
         int version;
         String basename;
-        if (entryName.startsWith(Main.VERSIONS_DIR)) {
+        if (entryName.startsWith(VERSIONS_DIR)) {
             int n = entryName.indexOf("/", vdlen);
             if (n == -1) {
-                main.error(Main.formatMsg("error.validator.version.notnumber", entryName));
+                error(formatMsg("error.validator.version.notnumber", entryName));
                 isValid = false;
                 return;
             }
@@ -82,12 +177,12 @@
             try {
                 version = Integer.parseInt(v);
             } catch (NumberFormatException x) {
-                main.error(Main.formatMsg("error.validator.version.notnumber", entryName));
+                error(formatMsg("error.validator.version.notnumber", entryName));
                 isValid = false;
                 return;
             }
             if (n == entryName.length()) {
-                main.error(Main.formatMsg("error.validator.entryname.tooshort", entryName));
+                error(formatMsg("error.validator.entryname.tooshort", entryName));
                 isValid = false;
                 return;
             }
@@ -108,7 +203,7 @@
         try (InputStream is = jf.getInputStream(je)) {
             fp = new FingerPrint(basename, is.readAllBytes());
         } catch (IOException x) {
-            main.error(x.getMessage());
+            error(x.getMessage());
             isValid = false;
             return;
         }
@@ -123,7 +218,7 @@
                     fps.put(internalName, fp);
                     return;
                 }
-                main.error(Main.formatMsg("error.validator.isolated.nested.class", entryName));
+                error(formatMsg("error.validator.isolated.nested.class", entryName));
                 isValid = false;
                 return;
             }
@@ -153,11 +248,11 @@
                 }
                 if (fp.isPublicClass()) {
                     if (!isConcealed(internalName)) {
-                        main.error(Main.formatMsg("error.validator.new.public.class", entryName));
+                        error(Main.formatMsg("error.validator.new.public.class", entryName));
                         isValid = false;
                         return;
                     }
-                    main.warn(Main.formatMsg("warn.validator.concealed.public.class", entryName));
+                    warn(formatMsg("warn.validator.concealed.public.class", entryName));
                     debug("%s is a public class entry in a concealed package", entryName);
                 }
                 debug("%s is a non-public class entry", entryName);
@@ -173,7 +268,7 @@
 
         // are the two classes/resources identical?
         if (fp.isIdentical(matchFp)) {
-            main.warn(Main.formatMsg("warn.validator.identical.entry", entryName));
+            warn(formatMsg("warn.validator.identical.entry", entryName));
             return;  // it's okay, just takes up room
         }
         debug("sha1 not equal -- different bytes");
@@ -188,12 +283,12 @@
             }
             debug("%s is a class entry", entryName);
             if (!fp.isCompatibleVersion(matchFp)) {
-                main.error(Main.formatMsg("error.validator.incompatible.class.version", entryName));
+                error(formatMsg("error.validator.incompatible.class.version", entryName));
                 isValid = false;
                 return;
             }
             if (!fp.isSameAPI(matchFp)) {
-                main.error(Main.formatMsg("error.validator.different.api", entryName));
+                error(formatMsg("error.validator.different.api", entryName));
                 isValid = false;
                 return;
             }
@@ -208,17 +303,118 @@
         }
         debug("%s is a resource", entryName);
 
-        main.warn(Main.formatMsg("warn.validator.resources.with.same.name", entryName));
+        warn(formatMsg("warn.validator.resources.with.same.name", entryName));
         fps.put(internalName, fp);
         return;
     }
 
+    private void loadModuleDescriptor() {
+        ZipEntry je = jf.getEntry(MODULE_INFO);
+        if (je != null) {
+            try (InputStream jis = jf.getInputStream(je)) {
+                md = ModuleDescriptor.read(jis);
+                concealedPkgs = new HashSet<>(md.packages());
+                md.exports().stream().map(Exports::source).forEach(concealedPkgs::remove);
+                md.opens().stream().map(Opens::source).forEach(concealedPkgs::remove);
+                return;
+            } catch (Exception x) {
+                error(x.getMessage() + " : " + je.getName());
+                this.isValid = false;
+            }
+        }
+        md = null;
+        concealedPkgs = Collections.emptySet();
+    }
+
+    private static boolean isPlatformModule(String name) {
+        return name.startsWith("java.") || name.startsWith("jdk.");
+    }
+
+    /**
+     * Checks whether or not the given versioned module descriptor's attributes
+     * are valid when compared against the root module descriptor.
+     *
+     * A versioned module descriptor must be identical to the root module
+     * descriptor, with two exceptions:
+     *  - A versioned descriptor can have different non-public `requires`
+     *    clauses of platform ( `java.*` and `jdk.*` ) modules, and
+     *  - A versioned descriptor can have different `uses` clauses, even of
+     *    service types defined outside of the platform modules.
+     */
+    private void checkModuleDescriptor(JarEntry je) {
+        try (InputStream is = jf.getInputStream(je)) {
+            ModuleDescriptor root = this.md;
+            ModuleDescriptor md = null;
+            try {
+                md = ModuleDescriptor.read(is);
+            } catch (InvalidModuleDescriptorException x) {
+                error(x.getMessage());
+                isValid = false;
+                return;
+            }
+            if (root == null) {
+                this.md = md;
+            } else {
+                if (!root.name().equals(md.name())) {
+                    error(getMsg("error.versioned.info.name.notequal"));
+                    isValid = false;
+                }
+                if (!root.requires().equals(md.requires())) {
+                    Set<Requires> rootRequires = root.requires();
+                    for (Requires r : md.requires()) {
+                        if (rootRequires.contains(r))
+                            continue;
+                        if (r.modifiers().contains(Requires.Modifier.TRANSITIVE)) {
+                            error(getMsg("error.versioned.info.requires.transitive"));
+                            isValid = false;
+                        } else if (!isPlatformModule(r.name())) {
+                            error(getMsg("error.versioned.info.requires.added"));
+                            isValid = false;
+                        }
+                    }
+                    for (Requires r : rootRequires) {
+                        Set<Requires> mdRequires = md.requires();
+                        if (mdRequires.contains(r))
+                            continue;
+                        if (!isPlatformModule(r.name())) {
+                            error(getMsg("error.versioned.info.requires.dropped"));
+                            isValid = false;
+                        }
+                    }
+                }
+                if (!root.exports().equals(md.exports())) {
+                    error(getMsg("error.versioned.info.exports.notequal"));
+                    isValid = false;
+                }
+                if (!root.opens().equals(md.opens())) {
+                    error(getMsg("error.versioned.info.opens.notequal"));
+                    isValid = false;
+                }
+                if (!root.provides().equals(md.provides())) {
+                    error(getMsg("error.versioned.info.provides.notequal"));
+                    isValid = false;
+                }
+                if (!root.mainClass().equals(md.mainClass())) {
+                    error(formatMsg("error.validator.info.manclass.notequal", je.getName()));
+                    isValid = false;
+                }
+                if (!root.version().equals(md.version())) {
+                    error(formatMsg("error.validator.info.version.notequal", je.getName()));
+                    isValid = false;
+                }
+            }
+        } catch (IOException x) {
+            error(x.getMessage());
+            isValid = false;
+        }
+    }
+
     private boolean checkInternalName(String entryName, String basename, String internalName) {
         String className = className(basename);
         if (internalName.equals(className)) {
             return true;
         }
-        main.error(Main.formatMsg2("error.validator.names.mismatch",
+        error(formatMsg2("error.validator.names.mismatch",
                 entryName, internalName.replace("/", ".")));
         return false;
     }
@@ -231,7 +427,7 @@
             return true;
         }
         debug("top level class was not accepted");
-        main.error(Main.formatMsg("error.validator.isolated.nested.class", entryName));
+        error(formatMsg("error.validator.isolated.nested.class", entryName));
         return false;
     }
 
@@ -240,16 +436,24 @@
     }
 
     private boolean isConcealed(String internalName) {
-        if (main.concealedPackages.isEmpty()) {
+        if (concealedPkgs.isEmpty()) {
             return false;
         }
         int idx = internalName.lastIndexOf('/');
         String pkgName = idx != -1 ? internalName.substring(0, idx).replace('/', '.') : "";
-        return main.concealedPackages.contains(pkgName);
+        return concealedPkgs.contains(pkgName);
     }
 
     private void debug(String fmt, Object... args) {
         if (DEBUG) System.err.format(fmt, args);
     }
+
+    private void error(String msg) {
+        main.error(msg);
+    }
+
+    private void warn(String msg) {
+        main.warn(msg);
+    }
+
 }
-
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties	Tue Jan 17 11:35:28 2017 -0800
@@ -66,23 +66,6 @@
         Unexpected module descriptor {0}
 error.module.descriptor.not.found=\
         Module descriptor not found
-error.versioned.info.without.root=\
-        module-info.class found in a versioned directory without module-info.class \
-        in the root
-error.versioned.info.name.notequal=\
-        module-info.class in a versioned directory contains incorrect name
-error.versioned.info.requires.transitive=\
-        module-info.class in a versioned directory contains additional "requires transitive"
-error.versioned.info.requires.added=\
-        module-info.class in a versioned directory contains additional "requires"
-error.versioned.info.requires.dropped=\
-        module-info.class in a versioned directory contains missing "requires"
-error.versioned.info.exports.notequal=\
-        module-info.class in a versioned directory contains different "exports"
-error.versioned.info.opens.notequal=\
-        module-info.class in a versioned directory contains different "opens"
-error.versioned.info.provides.notequal=\
-        module-info.class in a versioned directory contains different "provides"
 error.invalid.versioned.module.attribute=\
         Invalid module descriptor attribute {0}
 error.missing.provider=\
@@ -113,6 +96,24 @@
         entry: {0}, contains a class with different api from earlier version
 error.validator.names.mismatch=\
         entry: {0}, contains a class with internal name {1}, names do not match
+error.validator.info.name.notequal=\
+        module-info.class in a versioned directory contains incorrect name
+error.validator.info.requires.transitive=\
+        module-info.class in a versioned directory contains additional "requires transitive"
+error.validator.info.requires.added=\
+        module-info.class in a versioned directory contains additional "requires"
+error.validator.info.requires.dropped=\
+        module-info.class in a versioned directory contains missing "requires"
+error.validator.info.exports.notequal=\
+        module-info.class in a versioned directory contains different "exports"
+error.validator.info.opens.notequal=\
+        module-info.class in a versioned directory contains different "opens"
+error.validator.info.provides.notequal=\
+        module-info.class in a versioned directory contains different "provides"
+error.validator.info.version.notequal=\
+        {0}: module-info.class in a versioned directory contains different "version"
+error.validator.info.manclass.notequal=\
+        {0}: module-info.class in a versioned directory contains different "main-class"
 warn.validator.identical.entry=\
         Warning: entry {0} contains a class that\n\
         is identical to an entry already in the jar
@@ -122,6 +123,8 @@
         Warning: entry {0} is a public class\n\
         in a concealed package, placing this jar on the class path will result\n\
         in incompatible public interfaces
+warn.release.unexpected.versioned.entry=\
+        unexpected versioned entry {0}
 out.added.manifest=\
         added manifest
 out.added.module-info=\
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_de.properties	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_de.properties	Tue Jan 17 11:35:28 2017 -0800
@@ -42,13 +42,13 @@
 error.module.options.without.info=--module-version oder --hash-modules ohne module-info.class
 error.unexpected.module-info=Unerwarteter Moduldeskriptor {0}
 error.module.descriptor.not.found=Moduldeskriptor nicht gefunden
-error.versioned.info.without.root=module-info.class in einem versionierten Verzeichnis gefunden, in der Root ist module-info.class jedoch nicht vorhanden
-error.versioned.info.name.notequal=module-info.class in einem versionierten Verzeichnis enth\u00E4lt falschen Namen
-error.versioned.info.requires.public=module-info.class in einem versionierten Verzeichnis enth\u00E4lt zus\u00E4tzlichen "requires public"
-error.versioned.info.requires.added=module-info.class in einem versionierten Verzeichnis enth\u00E4lt zus\u00E4tzlichen "requires"
-error.versioned.info.requires.dropped=module-info.class in einem versionierten Verzeichnis enth\u00E4lt fehlenden "requires"
-error.versioned.info.exports.notequal=module-info.class in einem versionierten Verzeichnis enth\u00E4lt unterschiedliche "exports"
-error.versioned.info.provides.notequal=module-info.class in einem versionierten Verzeichnis enth\u00E4lt unterschiedliche "provides"
+error.validator.info.without.root=module-info.class in einem versionierten Verzeichnis gefunden, in der Root ist module-info.class jedoch nicht vorhanden
+error.validator.info.name.notequal=module-info.class in einem versionierten Verzeichnis enth\u00E4lt falschen Namen
+error.validator.info.requires.public=module-info.class in einem versionierten Verzeichnis enth\u00E4lt zus\u00E4tzlichen "requires public"
+error.validator.info.requires.added=module-info.class in einem versionierten Verzeichnis enth\u00E4lt zus\u00E4tzlichen "requires"
+error.validator.info.requires.dropped=module-info.class in einem versionierten Verzeichnis enth\u00E4lt fehlenden "requires"
+error.validator.info.exports.notequal=module-info.class in einem versionierten Verzeichnis enth\u00E4lt unterschiedliche "exports"
+error.validator.info.provides.notequal=module-info.class in einem versionierten Verzeichnis enth\u00E4lt unterschiedliche "provides"
 error.invalid.versioned.module.attribute=Ung\u00FCltiges Moduldeskriptorattribut {0}
 error.missing.provider=Serviceprovider nicht gefunden: {0}
 error.release.value.notnumber=Release {0} nicht g\u00FCltig
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_es.properties	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_es.properties	Tue Jan 17 11:35:28 2017 -0800
@@ -42,13 +42,13 @@
 error.module.options.without.info=Uno de --module-version o -hash-modules sin module-info.class
 error.unexpected.module-info=Descriptor de m\u00F3dulo inesperado {0}
 error.module.descriptor.not.found=No se ha encontrado el descriptor de m\u00F3dulo
-error.versioned.info.without.root=Se ha encontrado module-info.class en un directorio con versi\u00F3n sin module-info.class en la ra\u00EDz
-error.versioned.info.name.notequal=module-info.class en un directorio con versi\u00F3n contiene un nombre incorrecto
-error.versioned.info.requires.public=module-info.class en un directorio con versiones contiene "requires public" adicionales
-error.versioned.info.requires.added=module-info.class en un directorio con versi\u00F3n contiene "requires" adicionales
-error.versioned.info.requires.dropped=module-info.class en un directorio con versiones contiene "requires" que faltan
-error.versioned.info.exports.notequal=module-info.class en un directorio con versiones contiene "exports" diferentes
-error.versioned.info.provides.notequal=module-info.class en un directorio con versiones contiene "provides" diferentes
+error.validator.info.without.root=Se ha encontrado module-info.class en un directorio con versi\u00F3n sin module-info.class en la ra\u00EDz
+error.validator.info.name.notequal=module-info.class en un directorio con versi\u00F3n contiene un nombre incorrecto
+error.validator.info.requires.public=module-info.class en un directorio con versiones contiene "requires public" adicionales
+error.validator.info.requires.added=module-info.class en un directorio con versi\u00F3n contiene "requires" adicionales
+error.validator.info.requires.dropped=module-info.class en un directorio con versiones contiene "requires" que faltan
+error.validator.info.exports.notequal=module-info.class en un directorio con versiones contiene "exports" diferentes
+error.validator.info.provides.notequal=module-info.class en un directorio con versiones contiene "provides" diferentes
 error.invalid.versioned.module.attribute=Atributo de descriptor de m\u00F3dulo no v\u00E1lido {0}
 error.missing.provider=No se ha encontrado el proveedor de servicios: {0}
 error.release.value.notnumber=versi\u00F3n {0} no v\u00E1lida
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_fr.properties	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_fr.properties	Tue Jan 17 11:35:28 2017 -0800
@@ -42,13 +42,13 @@
 error.module.options.without.info=Une des options --module-version ou --hash-modules sans module-info.class
 error.unexpected.module-info=Descripteur de module {0} inattendu
 error.module.descriptor.not.found=Descripteur de module introuvable
-error.versioned.info.without.root=module-info.class a \u00E9t\u00E9 d\u00E9tect\u00E9 dans un r\u00E9pertoire avec num\u00E9ro de version sans module-info.class dans la racine
-error.versioned.info.name.notequal=module-info.class dans un r\u00E9pertoire avec num\u00E9ro de version contient un nom incorrect
-error.versioned.info.requires.public=module-info.class dans un r\u00E9pertoire avec num\u00E9ro de version contient des mots-cl\u00E9s "requires public" suppl\u00E9mentaires
-error.versioned.info.requires.added=module-info.class dans un r\u00E9pertoire avec num\u00E9ro de version contient des mots-cl\u00E9s "requires" suppl\u00E9mentaires
-error.versioned.info.requires.dropped=module-info.class dans un r\u00E9pertoire avec num\u00E9ro de version contient des mots-cl\u00E9s "requires" manquants
-error.versioned.info.exports.notequal=module-info.class dans un r\u00E9pertoire avec num\u00E9ro de version contient des mots-cl\u00E9s "exports" diff\u00E9rents
-error.versioned.info.provides.notequal=module-info.class dans un r\u00E9pertoire avec num\u00E9ro de version contient des mots-cl\u00E9s "provides" diff\u00E9rents
+error.validator.info.without.root=module-info.class a \u00E9t\u00E9 d\u00E9tect\u00E9 dans un r\u00E9pertoire avec num\u00E9ro de version sans module-info.class dans la racine
+error.validator.info.name.notequal=module-info.class dans un r\u00E9pertoire avec num\u00E9ro de version contient un nom incorrect
+error.validator.info.requires.public=module-info.class dans un r\u00E9pertoire avec num\u00E9ro de version contient des mots-cl\u00E9s "requires public" suppl\u00E9mentaires
+error.validator.info.requires.added=module-info.class dans un r\u00E9pertoire avec num\u00E9ro de version contient des mots-cl\u00E9s "requires" suppl\u00E9mentaires
+error.validator.info.requires.dropped=module-info.class dans un r\u00E9pertoire avec num\u00E9ro de version contient des mots-cl\u00E9s "requires" manquants
+error.validator.info.exports.notequal=module-info.class dans un r\u00E9pertoire avec num\u00E9ro de version contient des mots-cl\u00E9s "exports" diff\u00E9rents
+error.validator.info.provides.notequal=module-info.class dans un r\u00E9pertoire avec num\u00E9ro de version contient des mots-cl\u00E9s "provides" diff\u00E9rents
 error.invalid.versioned.module.attribute=Attribut de descripteur de module non valide {0}
 error.missing.provider=Fournisseur de services introuvable : {0}
 error.release.value.notnumber=version {0} non valide
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_it.properties	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_it.properties	Tue Jan 17 11:35:28 2017 -0800
@@ -42,13 +42,13 @@
 error.module.options.without.info=Una delle opzioni --module-version o --hash-modules non contiene module-info.class
 error.unexpected.module-info=Descrittore di modulo {0} imprevisto
 error.module.descriptor.not.found=Descrittore di modulo non trovato
-error.versioned.info.without.root=module-info.class trovato in una directory con controllo delle versioni senza module-info.class nella radice
-error.versioned.info.name.notequal=module-info.class in una directory con controllo delle versioni contiene un nome errato
-error.versioned.info.requires.public=module-info.class in una directory con controllo delle versioni contiene valori "requires public" aggiuntivi
-error.versioned.info.requires.added=module-info.class in una directory con controllo delle versioni contiene valori "requires" aggiuntivi
-error.versioned.info.requires.dropped=module-info.class in una directory con controllo delle versioni contiene valori "requires" mancanti
-error.versioned.info.exports.notequal=module-info.class in una directory con controllo delle versioni contiene "exports" differenti
-error.versioned.info.provides.notequal=module-info.class in una directory con controllo delle versioni contiene valori "provides" differenti
+error.validator.info.without.root=module-info.class trovato in una directory con controllo delle versioni senza module-info.class nella radice
+error.validator.info.name.notequal=module-info.class in una directory con controllo delle versioni contiene un nome errato
+error.validator.info.requires.public=module-info.class in una directory con controllo delle versioni contiene valori "requires public" aggiuntivi
+error.validator.info.requires.added=module-info.class in una directory con controllo delle versioni contiene valori "requires" aggiuntivi
+error.validator.info.requires.dropped=module-info.class in una directory con controllo delle versioni contiene valori "requires" mancanti
+error.validator.info.exports.notequal=module-info.class in una directory con controllo delle versioni contiene "exports" differenti
+error.validator.info.provides.notequal=module-info.class in una directory con controllo delle versioni contiene valori "provides" differenti
 error.invalid.versioned.module.attribute=Attributo descrittore del modulo {0} non valido.
 error.missing.provider=Provider di servizi non trovato: {0}
 error.release.value.notnumber=release {0} non valida
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_ja.properties	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_ja.properties	Tue Jan 17 11:35:28 2017 -0800
@@ -42,13 +42,13 @@
 error.module.options.without.info=--module-version\u307E\u305F\u306F--hash-modules\u306E\u3044\u305A\u308C\u304B\u3067module-info.class\u304C\u3042\u308A\u307E\u305B\u3093
 error.unexpected.module-info=\u4E88\u671F\u3057\u306A\u3044\u30E2\u30B8\u30E5\u30FC\u30EB\u30FB\u30C7\u30A3\u30B9\u30AF\u30EA\u30D7\u30BF{0}
 error.module.descriptor.not.found=\u30E2\u30B8\u30E5\u30FC\u30EB\u30FB\u30C7\u30A3\u30B9\u30AF\u30EA\u30D7\u30BF\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093
-error.versioned.info.without.root=module-info.class\u304C\u3001\u30EB\u30FC\u30C8\u306Bmodule-info.class\u306E\u306A\u3044\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306B\u898B\u3064\u304B\u308A\u307E\u3057\u305F
-error.versioned.info.name.notequal=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306Emodule-info.class\u306B\u6B63\u3057\u304F\u306A\u3044\u540D\u524D\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059
-error.versioned.info.requires.public=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306Emodule-info.class\u306B\u8FFD\u52A0\u306E"requires public"\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059
-error.versioned.info.requires.added=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306Emodule-info.class\u306B\u8FFD\u52A0\u306E"requires"\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059
-error.versioned.info.requires.dropped=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306Emodule-info.class\u306B\u6B20\u843D\u3057\u3066\u3044\u308B"requires"\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059
-error.versioned.info.exports.notequal=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306Emodule-info.class\u306B\u7570\u306A\u308B"exports"\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059
-error.versioned.info.provides.notequal=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306Emodule-info.class\u306B\u7570\u306A\u308B"provides"\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059
+error.validator.info.without.root=module-info.class\u304C\u3001\u30EB\u30FC\u30C8\u306Bmodule-info.class\u306E\u306A\u3044\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306B\u898B\u3064\u304B\u308A\u307E\u3057\u305F
+error.validator.info.name.notequal=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306Emodule-info.class\u306B\u6B63\u3057\u304F\u306A\u3044\u540D\u524D\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059
+error.validator.info.requires.public=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306Emodule-info.class\u306B\u8FFD\u52A0\u306E"requires public"\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059
+error.validator.info.requires.added=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306Emodule-info.class\u306B\u8FFD\u52A0\u306E"requires"\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059
+error.validator.info.requires.dropped=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306Emodule-info.class\u306B\u6B20\u843D\u3057\u3066\u3044\u308B"requires"\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059
+error.validator.info.exports.notequal=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306Emodule-info.class\u306B\u7570\u306A\u308B"exports"\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059
+error.validator.info.provides.notequal=\u30D0\u30FC\u30B8\u30E7\u30CB\u30F3\u30B0\u3055\u308C\u305F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306Emodule-info.class\u306B\u7570\u306A\u308B"provides"\u304C\u542B\u307E\u308C\u3066\u3044\u307E\u3059
 error.invalid.versioned.module.attribute=\u30E2\u30B8\u30E5\u30FC\u30EB\u30FB\u30C7\u30A3\u30B9\u30AF\u30EA\u30D7\u30BF\u5C5E\u6027{0}\u304C\u7121\u52B9\u3067\u3059
 error.missing.provider=\u30B5\u30FC\u30D3\u30B9\u30FB\u30D7\u30ED\u30D0\u30A4\u30C0\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093: {0}
 error.release.value.notnumber=\u30EA\u30EA\u30FC\u30B9{0}\u306F\u6709\u52B9\u3067\u306F\u3042\u308A\u307E\u305B\u3093
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_ko.properties	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_ko.properties	Tue Jan 17 11:35:28 2017 -0800
@@ -42,13 +42,13 @@
 error.module.options.without.info=module-info.class \uC5C6\uC774 --module-version \uB610\uB294 --hash-modules \uC911 \uD558\uB098
 error.unexpected.module-info=\uC608\uC0C1\uCE58 \uC54A\uC740 \uBAA8\uB4C8 \uAE30\uC220\uC790 {0}
 error.module.descriptor.not.found=\uBAA8\uB4C8 \uAE30\uC220\uC790\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC74C
-error.versioned.info.without.root=\uB8E8\uD2B8\uC5D0\uC11C module-info.class \uC5C6\uC774 \uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C module-info.class\uAC00 \uBC1C\uACAC\uB428
-error.versioned.info.name.notequal=\uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC758 module-info.class\uC5D0 \uC798\uBABB\uB41C \uC774\uB984\uC774 \uD3EC\uD568\uB428
-error.versioned.info.requires.public=\uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC758 module-info.class\uC5D0 \uCD94\uAC00 "requires public" \uD56D\uBAA9\uC774 \uD3EC\uD568\uB428
-error.versioned.info.requires.added=\uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC758 module-info.class\uC5D0 \uCD94\uAC00 "requires" \uD56D\uBAA9\uC774 \uD3EC\uD568\uB428
-error.versioned.info.requires.dropped=\uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC758 module-info.class\uC5D0 \uB204\uB77D\uB41C "requires" \uD56D\uBAA9\uC774 \uD3EC\uD568\uB428
-error.versioned.info.exports.notequal=\uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC758 module-info.class\uC5D0 \uB2E4\uB978 "exports" \uD56D\uBAA9\uC774 \uD3EC\uD568\uB428
-error.versioned.info.provides.notequal=\uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC758 module-info.class\uC5D0 \uB2E4\uB978 "provides" \uD56D\uBAA9\uC774 \uD3EC\uD568\uB428
+error.validator.info.without.root=\uB8E8\uD2B8\uC5D0\uC11C module-info.class \uC5C6\uC774 \uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C module-info.class\uAC00 \uBC1C\uACAC\uB428
+error.validator.info.name.notequal=\uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC758 module-info.class\uC5D0 \uC798\uBABB\uB41C \uC774\uB984\uC774 \uD3EC\uD568\uB428
+error.validator.info.requires.public=\uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC758 module-info.class\uC5D0 \uCD94\uAC00 "requires public" \uD56D\uBAA9\uC774 \uD3EC\uD568\uB428
+error.validator.info.requires.added=\uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC758 module-info.class\uC5D0 \uCD94\uAC00 "requires" \uD56D\uBAA9\uC774 \uD3EC\uD568\uB428
+error.validator.info.requires.dropped=\uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC758 module-info.class\uC5D0 \uB204\uB77D\uB41C "requires" \uD56D\uBAA9\uC774 \uD3EC\uD568\uB428
+error.validator.info.exports.notequal=\uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC758 module-info.class\uC5D0 \uB2E4\uB978 "exports" \uD56D\uBAA9\uC774 \uD3EC\uD568\uB428
+error.validator.info.provides.notequal=\uBC84\uC804 \uC9C0\uC815\uB41C \uB514\uB809\uD1A0\uB9AC\uC758 module-info.class\uC5D0 \uB2E4\uB978 "provides" \uD56D\uBAA9\uC774 \uD3EC\uD568\uB428
 error.invalid.versioned.module.attribute=\uBD80\uC801\uD569\uD55C \uBAA8\uB4C8 \uAE30\uC220\uC790 \uC18D\uC131 {0}
 error.missing.provider=\uC11C\uBE44\uC2A4 \uC81C\uACF5\uC790\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC74C: {0}
 error.release.value.notnumber=\uB9B4\uB9AC\uC2A4 {0}\uC774(\uAC00) \uBD80\uC801\uD569\uD568
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_pt_BR.properties	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_pt_BR.properties	Tue Jan 17 11:35:28 2017 -0800
@@ -42,13 +42,13 @@
 error.module.options.without.info=Um dentre --module-version ou --hash-modules est\u00E1 sem module-info.class
 error.unexpected.module-info=Descritor de m\u00F3dulo inesperado {0}
 error.module.descriptor.not.found=Descritor de m\u00F3dulo n\u00E3o encontrado
-error.versioned.info.without.root=module-info.class encontrado em um diret\u00F3rio com controle de vers\u00E3o sem module-info.class na raiz
-error.versioned.info.name.notequal=module-info.class em um diret\u00F3rio com controle de vers\u00E3o cont\u00E9m nome incorreto
-error.versioned.info.requires.public=module-info.class em um diret\u00F3rio com controle de vers\u00E3o cont\u00E9m "requires public" adicional
-error.versioned.info.requires.added=module-info.class em um diret\u00F3rio com controle de vers\u00E3o cont\u00E9m "requires" adicional
-error.versioned.info.requires.dropped=module-info.class em um diret\u00F3rio com controle de vers\u00E3o falta "requires"
-error.versioned.info.exports.notequal=module-info.class em um diret\u00F3rio com controle de vers\u00E3o cont\u00E9m "exports" diferente
-error.versioned.info.provides.notequal=module-info.class em um diret\u00F3rio com controle de vers\u00E3o cont\u00E9m "provides" diferente
+error.validator.info.without.root=module-info.class encontrado em um diret\u00F3rio com controle de vers\u00E3o sem module-info.class na raiz
+error.validator.info.name.notequal=module-info.class em um diret\u00F3rio com controle de vers\u00E3o cont\u00E9m nome incorreto
+error.validator.info.requires.public=module-info.class em um diret\u00F3rio com controle de vers\u00E3o cont\u00E9m "requires public" adicional
+error.validator.info.requires.added=module-info.class em um diret\u00F3rio com controle de vers\u00E3o cont\u00E9m "requires" adicional
+error.validator.info.requires.dropped=module-info.class em um diret\u00F3rio com controle de vers\u00E3o falta "requires"
+error.validator.info.exports.notequal=module-info.class em um diret\u00F3rio com controle de vers\u00E3o cont\u00E9m "exports" diferente
+error.validator.info.provides.notequal=module-info.class em um diret\u00F3rio com controle de vers\u00E3o cont\u00E9m "provides" diferente
 error.invalid.versioned.module.attribute=Atributo {0} de descritor de m\u00F3dulo inv\u00E1lido
 error.missing.provider=Prestador de servi\u00E7os  n\u00E3o encontrado: {0}
 error.release.value.notnumber=release {0} n\u00E3o v\u00E1lida
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_sv.properties	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_sv.properties	Tue Jan 17 11:35:28 2017 -0800
@@ -42,13 +42,13 @@
 error.module.options.without.info=--module-version eller --hash-modules utan module-info.class
 error.unexpected.module-info=Ov\u00E4ntad moduldeskriptor, {0}
 error.module.descriptor.not.found=Moduldeskriptorn hittades inte
-error.versioned.info.without.root=module-info.class hittades i en versionshanterad katalog utan module-info.class i roten
-error.versioned.info.name.notequal=module-info.class i en versionshanterad katalog inneh\u00E5ller ett felaktigt namn
-error.versioned.info.requires.public=module-info.class i en versionshanterad katalog inneh\u00E5ller fler "requires public"
-error.versioned.info.requires.added=module-info.class i en versionshanterad katalog inneh\u00E5ller fler "requires"
-error.versioned.info.requires.dropped=module-info.class i en versionshanterad katalog inneh\u00E5ller saknade "requires"
-error.versioned.info.exports.notequal=module-info.class i en versionshanterad katalog inneh\u00E5ller olika "exports"
-error.versioned.info.provides.notequal=module-info.class i en versionshanterad katalog inneh\u00E5ller olika "provides"
+error.validator.info.without.root=module-info.class hittades i en versionshanterad katalog utan module-info.class i roten
+error.validator.info.name.notequal=module-info.class i en versionshanterad katalog inneh\u00E5ller ett felaktigt namn
+error.validator.info.requires.public=module-info.class i en versionshanterad katalog inneh\u00E5ller fler "requires public"
+error.validator.info.requires.added=module-info.class i en versionshanterad katalog inneh\u00E5ller fler "requires"
+error.validator.info.requires.dropped=module-info.class i en versionshanterad katalog inneh\u00E5ller saknade "requires"
+error.validator.info.exports.notequal=module-info.class i en versionshanterad katalog inneh\u00E5ller olika "exports"
+error.validator.info.provides.notequal=module-info.class i en versionshanterad katalog inneh\u00E5ller olika "provides"
 error.invalid.versioned.module.attribute=Ogiltigt attribut f\u00F6r moduldeskriptor, {0}
 error.missing.provider=Tj\u00E4nsteleverant\u00F6ren hittades inte: {0}
 error.release.value.notnumber=utg\u00E5va {0} \u00E4r inte giltig
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_zh_CN.properties	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_zh_CN.properties	Tue Jan 17 11:35:28 2017 -0800
@@ -42,13 +42,13 @@
 error.module.options.without.info=--module-version \u6216 --hash-modules \u4E4B\u4E00\u6CA1\u6709 module-info.class
 error.unexpected.module-info=\u610F\u5916\u7684\u6A21\u5757\u63CF\u8FF0\u7B26 {0}
 error.module.descriptor.not.found=\u627E\u4E0D\u5230\u6A21\u5757\u63CF\u8FF0\u7B26
-error.versioned.info.without.root=\u5728\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u627E\u5230\u4E86 module-info.class, \u4F46\u6839\u4E2D\u6CA1\u6709 module-info.class
-error.versioned.info.name.notequal=\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u7684 module-info.class \u5305\u542B\u4E0D\u6B63\u786E\u7684\u540D\u79F0
-error.versioned.info.requires.public=\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u7684 module-info.class \u5305\u542B\u989D\u5916\u7684 "requires public"
-error.versioned.info.requires.added=\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u7684 module-info.class \u5305\u542B\u989D\u5916\u7684 "requires"
-error.versioned.info.requires.dropped=\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u7684 module-info.class \u5305\u542B\u7F3A\u5C11\u7684 "requires"
-error.versioned.info.exports.notequal=\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u7684 module-info.class \u5305\u542B\u4E0D\u540C\u7684 "exports"
-error.versioned.info.provides.notequal=\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u7684 module-info.class \u5305\u542B\u4E0D\u540C\u7684 "provides"
+error.validator.info.without.root=\u5728\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u627E\u5230\u4E86 module-info.class, \u4F46\u6839\u4E2D\u6CA1\u6709 module-info.class
+error.validator.info.name.notequal=\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u7684 module-info.class \u5305\u542B\u4E0D\u6B63\u786E\u7684\u540D\u79F0
+error.validator.info.requires.public=\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u7684 module-info.class \u5305\u542B\u989D\u5916\u7684 "requires public"
+error.validator.info.requires.added=\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u7684 module-info.class \u5305\u542B\u989D\u5916\u7684 "requires"
+error.validator.info.requires.dropped=\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u7684 module-info.class \u5305\u542B\u7F3A\u5C11\u7684 "requires"
+error.validator.info.exports.notequal=\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u7684 module-info.class \u5305\u542B\u4E0D\u540C\u7684 "exports"
+error.validator.info.provides.notequal=\u7248\u672C\u5316\u76EE\u5F55\u4E2D\u7684 module-info.class \u5305\u542B\u4E0D\u540C\u7684 "provides"
 error.invalid.versioned.module.attribute=\u65E0\u6548\u7684\u6A21\u5757\u63CF\u8FF0\u7B26\u5C5E\u6027 {0}
 error.missing.provider=\u672A\u627E\u5230\u670D\u52A1\u63D0\u4F9B\u65B9: {0}
 error.release.value.notnumber=\u53D1\u884C\u7248 {0} \u65E0\u6548
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_zh_TW.properties	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar_zh_TW.properties	Tue Jan 17 11:35:28 2017 -0800
@@ -42,13 +42,13 @@
 error.module.options.without.info=--module-version \u6216 --hash-modules \u5176\u4E2D\u4E00\u500B\u6C92\u6709 module-info.class
 error.unexpected.module-info=\u672A\u9810\u671F\u7684\u6A21\u7D44\u63CF\u8FF0\u5340 {0}
 error.module.descriptor.not.found=\u627E\u4E0D\u5230\u6A21\u7D44\u63CF\u8FF0\u5340
-error.versioned.info.without.root=\u5728\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u767C\u73FE module-info.class\uFF0C\u4F46\u662F\u6839\u4E2D\u6C92\u6709 module-info.class
-error.versioned.info.name.notequal=\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u7684 module-info.class \u5305\u542B\u4E0D\u6B63\u78BA\u7684\u540D\u7A31
-error.versioned.info.requires.public=\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u7684 module-info.class \u5305\u542B\u984D\u5916\u7684 "requires public"
-error.versioned.info.requires.added=\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u7684 module-info.class \u5305\u542B\u984D\u5916\u7684 "requires"
-error.versioned.info.requires.dropped=\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u7684 module-info.class \u5305\u542B\u907A\u6F0F\u7684 "requires"
-error.versioned.info.exports.notequal=\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u7684 module-info.class \u5305\u542B\u4E0D\u540C\u7684 "exports"
-error.versioned.info.provides.notequal=\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u7684 module-info.class \u5305\u542B\u4E0D\u540C\u7684 "provides"
+error.validator.info.without.root=\u5728\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u767C\u73FE module-info.class\uFF0C\u4F46\u662F\u6839\u4E2D\u6C92\u6709 module-info.class
+error.validator.info.name.notequal=\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u7684 module-info.class \u5305\u542B\u4E0D\u6B63\u78BA\u7684\u540D\u7A31
+error.validator.info.requires.public=\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u7684 module-info.class \u5305\u542B\u984D\u5916\u7684 "requires public"
+error.validator.info.requires.added=\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u7684 module-info.class \u5305\u542B\u984D\u5916\u7684 "requires"
+error.validator.info.requires.dropped=\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u7684 module-info.class \u5305\u542B\u907A\u6F0F\u7684 "requires"
+error.validator.info.exports.notequal=\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u7684 module-info.class \u5305\u542B\u4E0D\u540C\u7684 "exports"
+error.validator.info.provides.notequal=\u5DF2\u555F\u52D5\u591A\u7248\u672C\u529F\u80FD\u76EE\u9304\u4E2D\u7684 module-info.class \u5305\u542B\u4E0D\u540C\u7684 "provides"
 error.invalid.versioned.module.attribute=\u6A21\u7D44\u63CF\u8FF0\u5340\u5C6C\u6027 {0} \u7121\u6548
 error.missing.provider=\u627E\u4E0D\u5230\u670D\u52D9\u63D0\u4F9B\u8005: {0}
 error.release.value.notnumber=\u7248\u672C {0} \u7121\u6548
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java	Tue Jan 17 11:35:28 2017 -0800
@@ -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
@@ -58,13 +58,10 @@
 import java.nio.file.StandardCopyOption;
 import java.nio.file.attribute.BasicFileAttributes;
 import java.text.MessageFormat;
-import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.Deque;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -101,6 +98,7 @@
 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;
@@ -286,7 +284,27 @@
     }
 
     private boolean hashModules() {
-        return new Hasher(options.moduleFinder).run();
+        if (options.dryrun) {
+            out.println("Dry run:");
+        }
+
+        Hasher hasher = new Hasher(options.moduleFinder);
+        hasher.computeHashes().forEach((mn, hashes) -> {
+            if (options.dryrun) {
+                out.format("%s%n", mn);
+                hashes.names().stream()
+                    .sorted()
+                    .forEach(name -> out.format("  hashes %s %s %s%n",
+                        name, hashes.algorithm(), toHex(hashes.hashFor(name))));
+            } else {
+                try {
+                    hasher.updateModuleInfo(mn, hashes);
+                } catch (IOException ex) {
+                    throw new UncheckedIOException(ex);
+                }
+            }
+        });
+        return true;
     }
 
     private boolean describe() throws IOException {
@@ -377,7 +395,7 @@
         // create jmod with temporary name to avoid it being examined
         // when scanning the module path
         Path target = options.jmodFile;
-        Path tempTarget = target.resolveSibling(target.getFileName() + ".tmp");
+        Path tempTarget = Files.createTempFile(target.getFileName().toString(), ".tmp");
         try {
             try (JmodOutputStream jos = JmodOutputStream.newOutputStream(tempTarget)) {
                 jmod.write(jos);
@@ -411,7 +429,6 @@
         final String osArch = options.osArch;
         final String osVersion = options.osVersion;
         final List<PathMatcher> excludes = options.excludes;
-        final Hasher hasher = hasher();
         final ModuleResolution moduleResolution = options.moduleResolution;
 
         JmodFileWriter() { }
@@ -514,8 +531,17 @@
                 if (moduleVersion != null)
                     extender.version(moduleVersion);
 
-                if (hasher != null) {
-                    ModuleHashes moduleHashes = hasher.computeHashes(descriptor.name());
+                // --hash-modules
+                if (options.modulesToHash != null) {
+                    // To compute hashes, it creates a Configuration to resolve
+                    // a module graph.  The post-resolution check requires
+                    // the packages in ModuleDescriptor be available for validation.
+                    ModuleDescriptor md;
+                    try (InputStream is = miSupplier.get()) {
+                        md = ModuleDescriptor.read(is, () -> packages);
+                    }
+
+                    ModuleHashes moduleHashes = computeHashes(md);
                     if (moduleHashes != null) {
                         extender.hashes(moduleHashes);
                     } else {
@@ -557,50 +583,34 @@
          * The jmod file is being created and does not exist in the
          * given modulepath.
          */
-        private Hasher hasher() {
-            if (options.modulesToHash == null)
-                return null;
-
-            try {
-                Supplier<InputStream> miSupplier = newModuleInfoSupplier();
-                if (miSupplier == null) {
-                    throw new IOException(MODULE_INFO + " not found");
+        private ModuleHashes computeHashes(ModuleDescriptor descriptor) {
+            String mn = descriptor.name();
+            URI uri = options.jmodFile.toUri();
+            ModuleReference mref = new ModuleReference(descriptor, uri) {
+                @Override
+                public ModuleReader open() {
+                    throw new UnsupportedOperationException("opening " + mn);
                 }
+            };
 
-                ModuleDescriptor descriptor;
-                try (InputStream in = miSupplier.get()) {
-                    descriptor = ModuleDescriptor.read(in);
-                }
-
-                URI uri = options.jmodFile.toUri();
-                ModuleReference mref = new ModuleReference(descriptor, uri) {
+            // compose a module finder with the module path and also
+            // a module finder that can find the jmod file being created
+            ModuleFinder finder = ModuleFinder.compose(options.moduleFinder,
+                new ModuleFinder() {
                     @Override
-                    public ModuleReader open() {
-                        throw new UnsupportedOperationException();
+                    public Optional<ModuleReference> find(String name) {
+                        if (descriptor.name().equals(name))
+                            return Optional.of(mref);
+                        else return Optional.empty();
                     }
-                };
 
-                // compose a module finder with the module path and also
-                // a module finder that can find the jmod file being created
-                ModuleFinder finder = ModuleFinder.compose(options.moduleFinder,
-                    new ModuleFinder() {
-                        @Override
-                        public Optional<ModuleReference> find(String name) {
-                            if (descriptor.name().equals(name))
-                                return Optional.of(mref);
-                            else return Optional.empty();
-                        }
+                    @Override
+                    public Set<ModuleReference> findAll() {
+                        return Collections.singleton(mref);
+                    }
+                });
 
-                        @Override
-                        public Set<ModuleReference> findAll() {
-                            return Collections.singleton(mref);
-                        }
-                    });
-
-                return new Hasher(finder);
-            } catch (IOException e) {
-                throw new UncheckedIOException(e);
-            }
+            return new Hasher(mn, finder).computeHashes().get(mn);
         }
 
         /**
@@ -789,192 +799,93 @@
      * Compute and record hashes
      */
     private class Hasher {
-        final ModuleFinder moduleFinder;
-        final Map<String, Path> moduleNameToPath;
+        final Configuration configuration;
+        final ModuleHashesBuilder hashesBuilder;
         final Set<String> modules;
-        final Configuration configuration;
-        final boolean dryrun = options.dryrun;
+        final String moduleName;  // a specific module to record hashes, if set
+
+        /**
+         * This constructor is for jmod hash command.
+         *
+         * This Hasher will determine which modules to record hashes, i.e.
+         * the module in a subgraph of modules to be hashed and that
+         * has no outgoing edges.  It will record in each of these modules,
+         * say `M`, with the the hashes of modules that depend upon M
+         * directly or indirectly matching the specified --hash-modules pattern.
+         */
         Hasher(ModuleFinder finder) {
-            this.moduleFinder = finder;
+            this(null, finder);
+        }
+
+        /**
+         * Constructs a Hasher to compute hashes.
+         *
+         * If a module name `M` is specified, it will compute the hashes of
+         * modules that depend upon M directly or indirectly matching the
+         * specified --hash-modules pattern and record in the ModuleHashes
+         * attribute in M's module-info.class.
+         *
+         * @param name    name of the module to record hashes
+         * @param finder  module finder for the specified --module-path
+         */
+        Hasher(String name, ModuleFinder finder) {
             // Determine the modules that matches the pattern {@code modulesToHash}
-            this.modules = moduleFinder.findAll().stream()
+            Set<String> roots = finder.findAll().stream()
                 .map(mref -> mref.descriptor().name())
                 .filter(mn -> options.modulesToHash.matcher(mn).find())
                 .collect(Collectors.toSet());
 
-            // a map from a module name to Path of the packaged module
-            this.moduleNameToPath = moduleFinder.findAll().stream()
-                .map(mref -> mref.descriptor().name())
-                .collect(Collectors.toMap(Function.identity(), mn -> moduleToPath(mn)));
-
+            // use system module path unless it creates a JMOD file for
+            // a module that is present in the system image e.g. upgradeable
+            // module
+            ModuleFinder system;
+            if (name != null && ModuleFinder.ofSystem().find(name).isPresent()) {
+                system = ModuleFinder.of();
+            } else {
+                system = ModuleFinder.ofSystem();
+            }
             // get a resolved module graph
             Configuration config = null;
             try {
-                config = Configuration.empty()
-                    .resolveRequires(ModuleFinder.ofSystem(), moduleFinder, modules);
+                config = Configuration.empty().resolveRequires(system, finder, roots);
             } catch (ResolutionException e) {
-                warning("warn.module.resolution.fail", e.getMessage());
+                throw new CommandException("err.module.resolution.fail", e.getMessage());
             }
+
+            this.moduleName = name;
             this.configuration = config;
+
+            // filter modules resolved from the system module finder
+            this.modules = config.modules().stream()
+                .map(ResolvedModule::name)
+                .filter(mn -> roots.contains(mn) && !system.find(mn).isPresent())
+                .collect(Collectors.toSet());
+
+            this.hashesBuilder = new ModuleHashesBuilder(config, modules);
         }
 
         /**
-         * This method is for jmod hash command.
+         * Returns a map of a module M to record hashes of the modules
+         * that depend upon M directly or indirectly.
          *
-         * Identify the base modules in the module graph, i.e. no outgoing edge
-         * to any of the modules to be hashed.
+         * For jmod hash command, the returned map contains one entry
+         * for each module M that has no outgoing edges to any of the
+         * modules matching the specified --hash-modules pattern.
          *
-         * For each base module M, compute the hashes of all modules that depend
-         * upon M directly or indirectly.  Then update M's module-info.class
-         * to record the hashes.
+         * Each entry represents a leaf node in a connected subgraph containing
+         * M and other candidate modules from the module graph where M's outgoing
+         * edges to any module other than the ones matching the specified
+         * --hash-modules pattern are excluded.
          */
-        boolean run() {
-            if (configuration == null)
-                return false;
-
-            // transposed graph containing the the packaged modules and
-            // its transitive dependences matching --hash-modules
-            Map<String, Set<String>> graph = new HashMap<>();
-            for (String root : modules) {
-                Deque<String> deque = new ArrayDeque<>();
-                deque.add(root);
-                Set<String> visited = new HashSet<>();
-                while (!deque.isEmpty()) {
-                    String mn = deque.pop();
-                    if (!visited.contains(mn)) {
-                        visited.add(mn);
-
-                        if (modules.contains(mn))
-                            graph.computeIfAbsent(mn, _k -> new HashSet<>());
-
-                        ResolvedModule resolvedModule = configuration.findModule(mn).get();
-                        for (ResolvedModule dm : resolvedModule.reads()) {
-                            String name = dm.name();
-                            if (!visited.contains(name)) {
-                                deque.push(name);
-                            }
-
-                            // reverse edge
-                            if (modules.contains(name) && modules.contains(mn)) {
-                                graph.computeIfAbsent(name, _k -> new HashSet<>()).add(mn);
-                            }
-                        }
-                    }
-                }
-            }
-
-            if (dryrun)
-                out.println("Dry run:");
-
-            // each node in a transposed graph is a matching packaged module
-            // in which the hash of the modules that depend upon it is recorded
-            graph.entrySet().stream()
-                .filter(e -> !e.getValue().isEmpty())
-                .forEach(e -> {
-                    String mn = e.getKey();
-                    Map<String, Path> modulesForHash = e.getValue().stream()
-                            .collect(Collectors.toMap(Function.identity(),
-                                                      moduleNameToPath::get));
-                    ModuleHashes hashes = ModuleHashes.generate(modulesForHash, "SHA-256");
-                    if (dryrun) {
-                        out.format("%s%n", mn);
-                        hashes.names().stream()
-                              .sorted()
-                              .forEach(name -> out.format("  hashes %s %s %s%n",
-                                  name, hashes.algorithm(), hashes.hashFor(name)));
-                    } else {
-                        try {
-                            updateModuleInfo(mn, hashes);
-                        } catch (IOException ex) {
-                            throw new UncheckedIOException(ex);
-                        }
-                    }
-                });
-            return true;
-        }
-
-        /**
-         * Compute hashes of the specified module.
-         *
-         * It records the hashing modules that depend upon the specified
-         * module directly or indirectly.
-         */
-        ModuleHashes computeHashes(String name) {
-            if (configuration == null)
+        Map<String, ModuleHashes> computeHashes() {
+            if (hashesBuilder == null)
                 return null;
 
-            // the transposed graph includes all modules in the resolved graph
-            Map<String, Set<String>> graph = transpose();
-
-            // find the modules that transitively depend upon the specified name
-            Deque<String> deque = new ArrayDeque<>();
-            deque.add(name);
-            Set<String> mods = visitNodes(graph, deque);
-
-            // filter modules matching the pattern specified --hash-modules
-            // as well as itself as the jmod file is being generated
-            Map<String, Path> modulesForHash = mods.stream()
-                .filter(mn -> !mn.equals(name) && modules.contains(mn))
-                .collect(Collectors.toMap(Function.identity(), moduleNameToPath::get));
-
-            if (modulesForHash.isEmpty())
-                return null;
-
-           return ModuleHashes.generate(modulesForHash, "SHA-256");
-        }
-
-        /**
-         * Returns all nodes traversed from the given roots.
-         */
-        private Set<String> visitNodes(Map<String, Set<String>> graph,
-                                       Deque<String> roots) {
-            Set<String> visited = new HashSet<>();
-            while (!roots.isEmpty()) {
-                String mn = roots.pop();
-                if (!visited.contains(mn)) {
-                    visited.add(mn);
-                    // the given roots may not be part of the graph
-                    if (graph.containsKey(mn)) {
-                        for (String dm : graph.get(mn)) {
-                            if (!visited.contains(dm)) {
-                                roots.push(dm);
-                            }
-                        }
-                    }
-                }
+            if (moduleName != null) {
+                return hashesBuilder.computeHashes(Set.of(moduleName));
+            } else {
+                return hashesBuilder.computeHashes(modules);
             }
-            return visited;
-        }
-
-        /**
-         * Returns a transposed graph from the resolved module graph.
-         */
-        private Map<String, Set<String>> transpose() {
-            Map<String, Set<String>> transposedGraph = new HashMap<>();
-            Deque<String> deque = new ArrayDeque<>(modules);
-
-            Set<String> visited = new HashSet<>();
-            while (!deque.isEmpty()) {
-                String mn = deque.pop();
-                if (!visited.contains(mn)) {
-                    visited.add(mn);
-
-                    transposedGraph.computeIfAbsent(mn, _k -> new HashSet<>());
-
-                    ResolvedModule resolvedModule = configuration.findModule(mn).get();
-                    for (ResolvedModule dm : resolvedModule.reads()) {
-                        String name = dm.name();
-                        if (!visited.contains(name)) {
-                            deque.push(name);
-                        }
-
-                        // reverse edge
-                        transposedGraph.computeIfAbsent(name, _k -> new HashSet<>())
-                                .add(mn);
-                    }
-                }
-            }
-            return transposedGraph;
         }
 
         /**
@@ -993,11 +904,11 @@
             extender.write(out);
         }
 
-        private void updateModuleInfo(String name, ModuleHashes moduleHashes)
+        void updateModuleInfo(String name, ModuleHashes moduleHashes)
             throws IOException
         {
-            Path target = moduleNameToPath.get(name);
-            Path tempTarget = target.resolveSibling(target.getFileName() + ".tmp");
+            Path target = moduleToPath(name);
+            Path tempTarget = Files.createTempFile(target.getFileName().toString(), ".tmp");
             try {
                 if (target.getFileName().toString().endsWith(".jmod")) {
                     updateJmodFile(target, tempTarget, moduleHashes);
@@ -1075,10 +986,10 @@
         }
 
         private Path moduleToPath(String name) {
-            ModuleReference mref = moduleFinder.find(name).orElseThrow(
+            ResolvedModule rm = configuration.findModule(name).orElseThrow(
                 () -> new InternalError("Selected module " + name + " not on module path"));
 
-            URI uri = mref.location().get();
+            URI uri = rm.reference().location().get();
             Path path = Paths.get(uri);
             String fn = path.getFileName().toString();
             if (!fn.endsWith(".jar") && !fn.endsWith(".jmod")) {
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties	Tue Jan 17 11:35:28 2017 -0800
@@ -108,9 +108,9 @@
 err.invalid.dryrun.option=--dry-run can only be used with hash mode
 err.module.descriptor.not.found=Module descriptor not found
 err.missing.export.or.open.packages=Packages that are exported or open in {0} are not present: {1}
+err.module.resolution.fail=Resolution failed: {0}
 warn.invalid.arg=Invalid classname or pathname not exist: {0}
 warn.no.module.hashes=No hashes recorded: no module specified for hashing depends on {0}
-warn.module.resolution.fail=No hashes recorded: {0}
 warn.ignore.entry=ignoring entry {0}, in section {1}
 warn.ignore.duplicate.entry=ignoring duplicate entry {0}, in section {1}
 
--- a/jdk/src/jdk.sctp/unix/native/libsctp/SctpChannelImpl.c	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/jdk.sctp/unix/native/libsctp/SctpChannelImpl.c	Tue Jan 17 11:35:28 2017 -0800
@@ -418,7 +418,6 @@
   (JNIEnv *env, jclass klass, jint fd, jobject resultContainerObj,
    jlong address, jint length, jboolean peek) {
     SOCKETADDRESS sa;
-    int sa_len = sizeof(SOCKETADDRESS);
     ssize_t rv = 0;
     jlong *addr = jlong_to_ptr(address);
     struct iovec iov[1];
@@ -429,7 +428,7 @@
     /* Set up the msghdr structure for receiving */
     memset(msg, 0, sizeof (*msg));
     msg->msg_name = &sa;
-    msg->msg_namelen = sa_len;
+    msg->msg_namelen = sizeof(sa);
     iov->iov_base = addr;
     iov->iov_len = length;
     msg->msg_iov = iov;
@@ -538,7 +537,7 @@
    jobject targetAddress, jint targetPort, jint assocId, jint streamNumber,
    jboolean unordered, jint ppid) {
     SOCKETADDRESS sa;
-    int sa_len = sizeof(SOCKETADDRESS);
+    int sa_len = 0;
     ssize_t rv = 0;
     jlong *addr = jlong_to_ptr(address);
     struct iovec iov[1];
@@ -555,13 +554,12 @@
      *    Association already existing, assocId != -1, targetAddress = preferred addr
      */
     if (targetAddress != NULL /*&& assocId <= 0*/) {
-        if (NET_InetAddressToSockaddr(env, targetAddress, targetPort, &sa.sa,
+        if (NET_InetAddressToSockaddr(env, targetAddress, targetPort, &sa,
                                       &sa_len, JNI_TRUE) != 0) {
             return IOS_THROWN;
         }
     } else {
-        memset(&sa, '\x0', sa_len);
-        sa_len = 0;
+        memset(&sa, '\x0', sizeof(sa));
     }
 
     /* Set up the msghdr structure for sending */
--- a/jdk/src/jdk.sctp/unix/native/libsctp/SctpNet.c	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/src/jdk.sctp/unix/native/libsctp/SctpNet.c	Tue Jan 17 11:35:28 2017 -0800
@@ -211,22 +211,22 @@
   (JNIEnv *env, jclass klass, jint fd, jobjectArray addrs, jint port,
    jint addrsLength, jboolean add, jboolean preferIPv6) {
     SOCKETADDRESS *sap, *tmpSap;
-    int i, sa_len = sizeof(SOCKETADDRESS);
+    int i;
     jobject ia;
 
     if (addrsLength < 1)
         return;
 
-    if ((sap = calloc(addrsLength, sa_len)) == NULL) {
-          JNU_ThrowOutOfMemoryError(env, "heap allocation failure");
+    if ((sap = calloc(addrsLength, sizeof(SOCKETADDRESS))) == NULL) {
+        JNU_ThrowOutOfMemoryError(env, "heap allocation failure");
         return;
     }
 
     tmpSap = sap;
     for (i = 0; i < addrsLength; i++) {
         ia = (*env)->GetObjectArrayElement(env, addrs, i);
-        if (NET_InetAddressToSockaddr(env, ia, port, (struct sockaddr*)tmpSap,
-                                      &sa_len, preferIPv6) != 0) {
+        if (NET_InetAddressToSockaddr(env, ia, port, tmpSap, NULL,
+                                      preferIPv6) != 0) {
             free(sap);
             return;
         }
@@ -262,11 +262,11 @@
 Java_sun_nio_ch_sctp_SctpNet_connect0
   (JNIEnv *env, jclass clazz, int fd, jobject iao, jint port) {
     SOCKETADDRESS sa;
-    int sa_len = sizeof(SOCKETADDRESS);
+    int sa_len = 0;
     int rv;
 
-    if (NET_InetAddressToSockaddr(env, iao, port, &sa.sa,
-                                  &sa_len, JNI_TRUE) != 0) {
+    if (NET_InetAddressToSockaddr(env, iao, port, &sa, &sa_len,
+                                  JNI_TRUE) != 0) {
         return IOS_THROWN;
     }
 
@@ -311,8 +311,7 @@
     }
 }
 
-void initializeISA
-  (JNIEnv* env) {
+void initializeISA(JNIEnv* env) {
     if (isaCls == 0) {
         jclass c = (*env)->FindClass(env, "java/net/InetSocketAddress");
         CHECK_NULL(c);
@@ -325,8 +324,7 @@
     }
 }
 
-jobject SockAddrToInetSocketAddress
-  (JNIEnv *env, struct sockaddr* sap) {
+jobject SockAddrToInetSocketAddress(JNIEnv *env, SOCKETADDRESS *sap) {
     int port = 0;
 
     jobject ia = NET_SockaddrToInetAddress(env, sap, &port);
@@ -347,9 +345,9 @@
  * Signature: (I)[Ljava/net/SocketAddress;
  */
 JNIEXPORT jobjectArray JNICALL Java_sun_nio_ch_sctp_SctpNet_getLocalAddresses0
-  (JNIEnv *env, jclass klass, jint fd) {
+  (JNIEnv *env, jclass klass, jint fd)
+{
     void *addr_buf, *laddr;
-    struct sockaddr* sap;
     int i, addrCount;
     jobjectArray isaa;
 
@@ -377,38 +375,35 @@
     }
 
     laddr = addr_buf;
-    for (i=0; i<addrCount; i++) {
+    for (i = 0; i < addrCount; i++) {
         int port = 0;
-        jobject isa = NULL, ia;
-        sap = (struct sockaddr*)addr_buf;
-        ia = NET_SockaddrToInetAddress(env, sap, &port);
+        jobject ia, isa = NULL;
+        ia = NET_SockaddrToInetAddress(env, (SOCKETADDRESS *)addr_buf, &port);
         if (ia != NULL)
             isa = (*env)->NewObject(env, isaCls, isaCtrID, ia, port);
         if (isa == NULL)
             break;
         (*env)->SetObjectArrayElement(env, isaa, i, isa);
 
-        if (sap->sa_family == AF_INET)
-            addr_buf = ((struct sockaddr_in*)addr_buf) + 1;
+        if (((struct sockaddr *)addr_buf)->sa_family == AF_INET)
+            addr_buf = ((struct sockaddr_in *)addr_buf) + 1;
         else
-            addr_buf = ((struct sockaddr_in6*)addr_buf) + 1;
+            addr_buf = ((struct sockaddr_in6 *)addr_buf) + 1;
     }
 
     nio_sctp_freeladdrs(laddr);
     return isaa;
 }
 
-jobjectArray getRemoteAddresses
-  (JNIEnv *env, jint fd, sctp_assoc_t id) {
+jobjectArray getRemoteAddresses(JNIEnv *env, jint fd, sctp_assoc_t id) {
     void *addr_buf, *paddr;
-    struct sockaddr* sap;
     int i, addrCount;
     jobjectArray isaa;
 
 #if __solaris__
     if ((addrCount = nio_sctp_getpaddrs(fd, id, (void **)&addr_buf)) == -1) {
 #else /* __linux__ */
-    if ((addrCount = nio_sctp_getpaddrs(fd, id, (struct sockaddr**)&addr_buf)) == -1) {
+    if ((addrCount = nio_sctp_getpaddrs(fd, id, (struct sockaddr **)&addr_buf)) == -1) {
 #endif
         handleSocketError(env, errno);
         return NULL;
@@ -429,25 +424,23 @@
     }
 
     paddr = addr_buf;
-    for (i=0; i<addrCount; i++) {
-        jobject ia, isa = NULL;
+    for (i = 0; i < addrCount; i++) {
         int port = 0;
-        sap = (struct sockaddr*)addr_buf;
-        ia = NET_SockaddrToInetAddress(env, sap, &port);
+        jobject ia, isa = NULL;
+        ia = NET_SockaddrToInetAddress(env, (SOCKETADDRESS *)addr_buf, &port);
         if (ia != NULL)
             isa = (*env)->NewObject(env, isaCls, isaCtrID, ia, port);
         if (isa == NULL)
             break;
         (*env)->SetObjectArrayElement(env, isaa, i, isa);
 
-        if (sap->sa_family == AF_INET)
-            addr_buf = ((struct sockaddr_in*)addr_buf) + 1;
+        if (((struct sockaddr *)addr_buf)->sa_family == AF_INET)
+            addr_buf = ((struct sockaddr_in *)addr_buf) + 1;
         else
-            addr_buf = ((struct sockaddr_in6*)addr_buf) + 1;
+            addr_buf = ((struct sockaddr_in6 *)addr_buf) + 1;
     }
 
     nio_sctp_freepaddrs(paddr);
-
     return isaa;
 }
 
@@ -579,7 +572,6 @@
   (JNIEnv *env, jclass klass, jint fd, jint assocId) {
     struct sctp_setprim prim;
     unsigned int prim_len = sizeof(prim);
-    struct sockaddr* sap = (struct sockaddr*)&prim.ssp_addr;
 
     prim.ssp_assoc_id = assocId;
 
@@ -589,7 +581,7 @@
         return NULL;
     }
 
-    return SockAddrToInetSocketAddress(env, sap);
+    return SockAddrToInetSocketAddress(env, (SOCKETADDRESS *)&prim.ssp_addr);
 }
 
 /*
@@ -600,11 +592,10 @@
 JNIEXPORT void JNICALL Java_sun_nio_ch_sctp_SctpNet_setPrimAddrOption0
   (JNIEnv *env, jclass klass, jint fd, jint assocId, jobject iaObj, jint port) {
     struct sctp_setprim prim;
-    struct sockaddr* sap = (struct sockaddr*)&prim.ssp_addr;
-    int sap_len = sizeof(sap);
 
-    if (NET_InetAddressToSockaddr(env, iaObj, port, sap,
-                                  &sap_len, JNI_TRUE) != 0) {
+    if (NET_InetAddressToSockaddr(env, iaObj, port,
+                                  (SOCKETADDRESS *)&prim.ssp_addr,
+                                  NULL, JNI_TRUE) != 0) {
         return;
     }
 
@@ -625,18 +616,17 @@
   (JNIEnv *env, jclass klass, jint fd, jint assocId,
    jobject iaObj, jint port, jboolean preferIPv6) {
     struct sctp_setpeerprim prim;
-    struct sockaddr* sap = (struct sockaddr*)&prim.sspp_addr;
-    int sap_len = sizeof(sap);
 
-    if (NET_InetAddressToSockaddr(env, iaObj, port, sap,
-                                  &sap_len, preferIPv6) != 0) {
+    if (NET_InetAddressToSockaddr(env, iaObj, port,
+                                  (SOCKETADDRESS *)&prim.sspp_addr,
+                                  NULL, preferIPv6) != 0) {
         return;
     }
 
     prim.sspp_assoc_id = assocId;
 
     if (setsockopt(fd, IPPROTO_SCTP, SCTP_SET_PEER_PRIMARY_ADDR, &prim,
-            sizeof(prim)) < 0) {
+                   sizeof(prim)) < 0) {
         JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
                                      "sun.nio.ch.SctpNet.setPeerPrimAddrOption0");
     }
--- a/jdk/test/ProblemList.txt	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/test/ProblemList.txt	Tue Jan 17 11:35:28 2017 -0800
@@ -1,6 +1,6 @@
 ###########################################################################
 #
-# Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -141,8 +141,6 @@
 
 # jdk_io
 
-java/io/pathNames/GeneralWin32.java                             8156595 windows-all
-
 ############################################################################
 
 # jdk_management
@@ -203,8 +201,6 @@
 
 sun/rmi/rmic/newrmic/equivalence/run.sh                         8145980 generic-all
 
-java/rmi/registry/readTest/readTest.sh                          7146543 generic-all
-
 ############################################################################
 
 # jdk_security
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/File/WinDirRelative.java	Tue Jan 17 11:35:28 2017 -0800
@@ -0,0 +1,96 @@
+/*
+ * 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
+ * @bug 8153250
+ * @summary Tests that files are correctly listed for a directory-relative path
+ * @requires (os.family == "windows")
+ */
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+public class WinDirRelative {
+    private static final char COLON = ':';
+    private static final String BASENAME = "TestFile_";
+    private static final String EXTENSION = ".txt";
+    private static final int NUM_FILES = 10;
+
+    private static boolean isLetter(char c) {
+        return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'));
+    }
+
+    public static void main(String[] args) throws Throwable {
+        // Get the working directory which is also the default
+        // directory for the current drive.
+        String userDir = System.getProperty("user.dir");
+
+        // Test only if a leading drive letter is found
+        if (isLetter(userDir.charAt(0)) && userDir.charAt(1) == COLON) {
+            // Create some empty files
+            List<String> filenames = new ArrayList<String>(NUM_FILES);
+            for (int i = 0; i < NUM_FILES; i++) {
+                String filename = BASENAME + i + EXTENSION;
+                filenames.add(filename);
+                File f = new File(filename);
+                f.createNewFile();
+                f.deleteOnExit();
+                System.out.printf("Created %s (%s)%n", filename,
+                    f.getAbsolutePath());
+            }
+
+            // List files and verify that the ones with recognized names exist.
+            String prefix = userDir.substring(0, 2);
+            File p = new File(prefix);
+            int failures = 0;
+            int successes = 0;
+            for (File f : p.listFiles()) {
+                if (f.getName().toString().startsWith(BASENAME)) {
+                    if (!f.exists()) {
+                        System.err.printf("%s (%s) does not exist%n", f,
+                            f.getAbsolutePath());
+                        failures++;
+                    } else {
+                        successes++;
+                    }
+                }
+            }
+
+            // Fail if there was an existence test failure or if not
+            // enough of the created files were found
+            boolean testFailed = false;
+            if (failures > 0) {
+                System.err.println("Existence check failed");
+                testFailed = true;
+            }
+            if (successes != NUM_FILES) {
+                System.err.println("Count check failed");
+                testFailed = true;
+            }
+            if (testFailed) {
+                throw new RuntimeException("Test failed");
+            }
+        }
+    }
+}
--- a/jdk/test/java/io/File/createTempFile/Patterns.java	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/test/java/io/File/createTempFile/Patterns.java	Tue Jan 17 11:35:28 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,7 +22,7 @@
  */
 
 /* @test
-   @bug 4152178
+   @bug 4152178 8152272
    @summary Check various temp-file prefix/suffix cases */
 
 import java.io.File;
@@ -66,6 +66,7 @@
         cky("xxx", "");
         cky("xxx", "y");
         cky("xxx", ".y");
+        cky("xyz", "Directory" + System.getProperty("file.separator"));
     }
 
 }
--- a/jdk/test/java/io/pathNames/General.java	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/test/java/io/pathNames/General.java	Tue Jan 17 11:35:28 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -40,6 +40,7 @@
     private static int gensymCounter = 0;
 
     protected static final String userDir = System.getProperty("user.dir");
+    protected static final String workSubDir = "tmp";
 
     protected static String baseDir = null;
     protected static String relative = null;
@@ -60,7 +61,10 @@
      *                  direct or indirect calling) in a whole test.
      */
     protected static void initTestData(int depth) throws IOException {
-        File parent = new File(userDir);
+        File parent = new File(userDir + File.separator + workSubDir);
+        if (!parent.mkdir()) {
+            throw new IOException("Fail to create directory: " + parent);
+        }
         for (int i = 0; i < depth; i++) {
             File tmp = new File(parent, gensym());
             tmp.createNewFile();
--- a/jdk/test/java/io/pathNames/GeneralWin32.java	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/test/java/io/pathNames/GeneralWin32.java	Tue Jan 17 11:35:28 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -53,7 +53,8 @@
     private static void checkCaseLookup() throws IOException {
         /* Use long names here to avoid 8.3 format, which Samba servers often
            force to lowercase */
-        File d = new File("XyZzY0123", "FOO_bar_BAZ");
+        File r = new File (workSubDir, "XyZzY0123");
+        File d = new File(r, "FOO_bar_BAZ");
         File f = new File(d, "GLORPified");
         if (!f.exists()) {
             if (!d.exists()) {
@@ -74,9 +75,9 @@
            case of filenames, rather than just using the input case */
         File y = new File(userDir, f.getPath());
         String ans = y.getPath();
-        check(ans, "XyZzY0123\\FOO_bar_BAZ\\GLORPified");
-        check(ans, "xyzzy0123\\foo_bar_baz\\glorpified");
-        check(ans, "XYZZY0123\\FOO_BAR_BAZ\\GLORPIFIED");
+        check(ans, workSubDir + File.separator + "XyZzY0123\\FOO_bar_BAZ\\GLORPified");
+        check(ans, workSubDir + File.separator + "xyzzy0123\\foo_bar_baz\\glorpified");
+        check(ans, workSubDir + File.separator + "XYZZY0123\\FOO_BAR_BAZ\\GLORPIFIED");
     }
 
     private static void checkWild(File f) throws Exception {
@@ -125,20 +126,19 @@
         throw new RuntimeException("Can't find an active drive");
     }
 
-    private static void checkDrive(int depth, char drive, boolean exists)
+    private static void checkDrive(int depth, String drive, boolean exists)
         throws Exception
     {
-        String d = drive + ":";
-        File df = new File(d);
-        String ans = exists ? df.getAbsolutePath() : d;
+        File df = new File(drive);
+        String ans = exists ? df.getAbsolutePath() : drive;
         if (!ans.endsWith("\\"))
             ans = ans + "\\";
-        checkNames(depth, false, ans, d);
+        checkNames(depth, false, ans, drive);
     }
 
     private static void checkDrivePaths(int depth) throws Exception {
-        checkDrive(depth, findActiveDrive(), true);
-        checkDrive(depth, findInactiveDrive(), false);
+        checkDrive(depth, findActiveDrive() + ":" + workSubDir + File.separator, true);
+        checkDrive(depth, findInactiveDrive() + ":", false);
     }
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/rmi/registry/readTest/CodebaseTest.java	Tue Jan 17 11:35:28 2017 -0800
@@ -0,0 +1,90 @@
+/*
+ * 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
+ * @bug 7102369 7094468 7100592
+ * @modules java.rmi/sun.rmi.registry
+ *          java.rmi/sun.rmi.server
+ *          java.rmi/sun.rmi.transport
+ *          java.rmi/sun.rmi.transport.tcp
+ * @library ../../testlibrary
+ * @build TestLibrary RMIRegistryRunner RegistryVM JavaVM testPkg.* RegistryLookup
+ * @summary remove java.rmi.server.codebase property parsing from registyimpl
+ * @run main/othervm CodebaseTest
+*/
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.rmi.registry.Registry;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+
+public class CodebaseTest {
+
+    public static void main(String args[]) throws Exception {
+        RegistryVM rmiregistry = null;
+        JavaVM client = null;
+        try {
+            File src = new File(System.getProperty("test.classes", "."), "testPkg");
+            File dest = new File(System.getProperty("user.dir", "."), "testPkg");
+            Files.move(src.toPath(), dest.toPath(),
+                    StandardCopyOption.REPLACE_EXISTING);
+
+            File rmiregistryDir =
+                new File(System.getProperty("user.dir", "."), "rmi_tmp");
+            rmiregistryDir.mkdirs();
+            rmiregistry = RegistryVM.createRegistryVMWithRunner(
+                    "RMIRegistryRunner",
+                    " -Djava.rmi.server.useCodebaseOnly=false"
+                    + " -Duser.dir=" + rmiregistryDir.getAbsolutePath());
+            rmiregistry.start();
+            int port = rmiregistry.getPort();
+
+            File srcReadTest = new File(System.getProperty("test.classes", "."),
+                                    "RegistryLookup.class");
+            File destReadTest = new File(System.getProperty("user.dir", "."),
+                                    "RegistryLookup.class");
+            Files.move(srcReadTest.toPath(), destReadTest.toPath(),
+                                    StandardCopyOption.REPLACE_EXISTING);
+
+            File codebase = new File(System.getProperty("user.dir", "."));
+            client = new JavaVM("RegistryLookup",
+                    " -Djava.rmi.server.codebase=" + codebase.toURI().toURL()
+                    + " -cp ." + File.pathSeparator + System.getProperty("test.class.path"),
+                    Integer.toString(port));
+            int exit = client.execute();
+            if (exit == RegistryLookup.EXIT_FAIL) {
+                throw new RuntimeException("Test Fails");
+            }
+        } finally {
+            if (rmiregistry != null) {
+                rmiregistry.cleanup();
+            }
+            if (client != null) {
+                client.cleanup();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/rmi/registry/readTest/RegistryLookup.java	Tue Jan 17 11:35:28 2017 -0800
@@ -0,0 +1,62 @@
+/*
+ * 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
+ * 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.rmi.registry.Registry;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+
+public class RegistryLookup {
+    public static final int EXIT_FAIL = 1;
+
+    public static void main(String args[]) throws Exception {
+        Registry registry = null;
+        int exit = 0;
+        try {
+            int port = Integer.valueOf(args[0]);
+
+            testPkg.Server obj = new testPkg.Server();
+            testPkg.Hello stub =
+                    (testPkg.Hello) UnicastRemoteObject.exportObject(obj, 0);
+            // Bind the remote object's stub in the registry
+            registry = LocateRegistry.getRegistry(port);
+            registry.bind("Hello", stub);
+            System.err.println("Server ready");
+
+            testPkg.Client client = new testPkg.Client(port);
+            String testStubReturn = client.testStub();
+            if(!testStubReturn.equals(obj.hello)) {
+                throw new RuntimeException("Test Fails : "
+                        + "unexpected string from stub call");
+            }
+            registry.unbind("Hello");
+            System.out.println("Test passed");
+        } catch (Exception ex) {
+            exit = EXIT_FAIL;
+            ex.printStackTrace();
+        }
+        // need to exit explicitly, and parent process uses exit value
+        // to tell if the test passed.
+        System.exit(exit);
+    }
+}
--- a/jdk/test/java/rmi/registry/readTest/readTest.java	Tue Jan 17 18:24:28 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.rmi.registry.Registry;
-import java.rmi.registry.LocateRegistry;
-import java.rmi.RemoteException;
-import java.rmi.server.UnicastRemoteObject;
-
-public class readTest {
-
-    public static void main(String args[]) throws Exception {
-        try {
-            testPkg.Server obj = new testPkg.Server();
-            testPkg.Hello stub = (testPkg.Hello) UnicastRemoteObject.exportObject(obj, 0);
-            // Bind the remote object's stub in the registry
-            Registry registry =
-                LocateRegistry.getRegistry(TestLibrary.READTEST_REGISTRY_PORT);
-            registry.bind("Hello", stub);
-
-            System.err.println("Server ready");
-
-            // now, let's test client
-            testPkg.Client client =
-                new testPkg.Client(TestLibrary.READTEST_REGISTRY_PORT);
-            String testStubReturn = client.testStub();
-            if(!testStubReturn.equals(obj.hello)) {
-                throw new RuntimeException("Test Fails : unexpected string from stub call");
-            } else {
-                System.out.println("Test passed");
-            }
-            registry.unbind("Hello");
-
-        } catch (Exception e) {
-            System.err.println("Server exception: " + e.toString());
-            e.printStackTrace();
-        }
-
-    }
-}
--- a/jdk/test/java/rmi/registry/readTest/readTest.sh	Tue Jan 17 18:24:28 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,137 +0,0 @@
-#
-# Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-# @test
-# @bug 7102369 7094468 7100592
-# @modules java.rmi/sun.rmi.registry
-#          java.rmi/sun.rmi.server
-#          java.rmi/sun.rmi.transport
-#          java.rmi/sun.rmi.transport.tcp
-# @library ../../testlibrary
-# @build TestLibrary
-# @summary remove java.rmi.server.codebase property parsing from registyimpl
-# @run shell readTest.sh
-# @key intermittent
-
-OS=`uname -s`
-VER=`uname -r`
-ARGS=""
-REGARGS=""
-
-case "$OS" in
-  SunOS | Linux | Darwin | AIX )
-    PS=":"
-    FS="/"
-    CHMOD="${FS}bin${FS}chmod"
-    FILEURL="file:"
-    ;;
-  Windows* )
-    PS=";"
-    FS="\\"
-    CHMOD="chmod"
-    FILEURL="file:/"
-    if [ "$VER" -eq "5" ]; then
-        ARGS="-Djdk.net.ephemeralPortRange.low=1024 -Djdk.net.ephemeralPortRange.high=65000"
-        REGARGS="-J-Djdk.net.ephemeralPortRange.low=1024 -J-Djdk.net.ephemeralPortRange.high=65000"
-    fi
-    ;;
-  CYGWIN* )
-    PS=";"
-    FS="/"
-    CHMOD="chmod"
-    FILEURL="file:/"
-    if [ "$VER" -eq "5" ]; then
-        ARGS="-Djdk.net.ephemeralPortRange.low=1024 -Djdk.net.ephemeralPortRange.high=65000"
-        REGARGS="-J-Djdk.net.ephemeralPortRange.low=1024 -J-Djdk.net.ephemeralPortRange.high=65000"
-    fi
-    ;;
-  * )
-    echo "Unrecognized system!"
-    exit 1;
-    ;;
-esac
-
-TEST_CLASSPATH=.$PS${TESTCLASSPATH:-$TESTCLASSES}
-cp -r ${TESTSRC}${FS}* .
-${CHMOD} -R u+w *
-${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} testPkg${FS}*java
-${COMPILEJAVA}${FS}bin${FS}javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} -cp $TEST_CLASSPATH readTest.java
-
-mkdir rmi_tmp
-RMIREG_OUT=rmi.out
-#start rmiregistry without any local classes on classpath
-cd rmi_tmp
-# NOTE: This RMI Registry port must match TestLibrary.READTEST_REGISTRY_PORT
-${TESTJAVA}${FS}bin${FS}rmiregistry ${REGARGS} -J-Djava.rmi.server.useCodebaseOnly=false \
-    ${TESTTOOLVMOPTS} 60005 > ..${FS}${RMIREG_OUT} 2>&1 &
-RMIREG_PID=$!
-# allow some time to start
-sleep 3
-cd ..
-
-case "$OS" in
-  CYGWIN* )
-    CODEBASE=`cygpath -w $PWD`
-    ;;
-  * )
-    CODEBASE=`pwd`
-    ;;
-esac
-# trailing / after code base is important for rmi codebase property.
-TESTVMOPTS="${TESTVMOPTS} \
- --add-exports java.rmi/sun.rmi.registry=ALL-UNNAMED \
- --add-exports java.rmi/sun.rmi.server=ALL-UNNAMED \
- --add-exports java.rmi/sun.rmi.transport=ALL-UNNAMED \
- --add-exports java.rmi/sun.rmi.transport.tcp=ALL-UNNAMED"
-${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -cp $TEST_CLASSPATH ${ARGS} -Djava.rmi.server.codebase=${FILEURL}$CODEBASE/ readTest > OUT.TXT 2>&1 &
-TEST_PID=$!
-#bulk of testcase - let it run for a while
-sleep 5
-
-#we're done, kill processes first
-kill -9 ${RMIREG_PID} ${TEST_PID}
-sleep 3
-
-echo "Test output : "
-
-cat OUT.TXT
-echo "=============="
-echo "rmiregistry output  : "
-cat ${RMIREG_OUT}
-echo "=============="
-
-grep "Server ready" OUT.TXT
-result1=$?
-grep "Test passed" OUT.TXT
-result2=$?
-
-if [ $result1 -eq 0  -a $result2 -eq 0 ]
-then
-    echo "Passed"
-    exitCode=0;
-else
-    echo "Failed"
-    exitCode=1
-fi
-rm -rf OUT.TXT ${RMIREG_OUT} rmi_tmp
-exit ${exitCode}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/rmi/registry/readTest/registry.security.policy	Tue Jan 17 11:35:28 2017 -0800
@@ -0,0 +1,12 @@
+grant {
+  permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.registry";
+  permission java.util.PropertyPermission "env.class.path", "read";
+  permission java.io.FilePermission ".", "read";
+  permission java.util.PropertyPermission "user.dir", "read";
+  permission java.lang.RuntimePermission "createClassLoader";
+  permission java.lang.RuntimePermission "setContextClassLoader";
+  permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.server";
+  permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport";
+  permission java.lang.RuntimePermission "accessClassInPackage.sun.rmi.transport.tcp";
+  permission java.net.SocketPermission "*:1024-", "listen,resolve,connect,accept";
+};
--- a/jdk/test/lib/security/SecurityTools.java	Tue Jan 17 18:24:28 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,122 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import jdk.testlibrary.JDKToolLauncher;
-import jdk.testlibrary.OutputAnalyzer;
-import jdk.testlibrary.ProcessTools;
-
-public class SecurityTools {
-
-    public static final String NO_ALIAS = null;
-
-    // keytool
-
-    public static OutputAnalyzer keytool(List<String> options)
-            throws Throwable {
-
-        JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("keytool")
-                .addVMArg("-Duser.language=en")
-                .addVMArg("-Duser.country=US");
-        for (String option : options) {
-            if (option.startsWith("-J")) {
-                launcher.addVMArg(option.substring(2));
-            } else {
-                launcher.addToolArg(option);
-            }
-        }
-        return ProcessTools.executeCommand(launcher.getCommand());
-    }
-
-    public static OutputAnalyzer keytool(String options) throws Throwable {
-        return keytool(options.split("\\s+"));
-    }
-
-    public static OutputAnalyzer keytool(String... options) throws Throwable {
-        return keytool(List.of(options));
-    }
-
-    // jarsigner
-
-    public static OutputAnalyzer jarsigner(String jar, String alias,
-            List<String> options) throws Throwable {
-        JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jarsigner")
-                .addVMArg("-Duser.language=en")
-                .addVMArg("-Duser.country=US");
-        for (String option : options) {
-            if (option.startsWith("-J")) {
-                launcher.addVMArg(option.substring(2));
-            } else {
-                launcher.addToolArg(option);
-            }
-        }
-        launcher.addToolArg(jar);
-        if (alias != null) {
-            launcher.addToolArg(alias);
-        }
-        return ProcessTools.executeCommand(launcher.getCommand());
-    }
-
-    public static OutputAnalyzer jarsigner(String jar, String alias,
-            String options) throws Throwable {
-
-        return jarsigner(jar, alias, options.split("\\s+"));
-    }
-
-    public static OutputAnalyzer jarsigner(String jar, String alias,
-            String... options) throws Throwable {
-
-        return jarsigner(jar, alias, List.of(options));
-    }
-
-    public static OutputAnalyzer sign(String jar, String alias, String... options)
-            throws Throwable {
-
-        return jarsigner(jar, alias,
-                mergeOptions("-J-Djava.security.egd=file:/dev/./urandom", options));
-    }
-
-    public static OutputAnalyzer verify(String jar, String... options)
-            throws Throwable {
-
-        return jarsigner(jar, NO_ALIAS, mergeOptions("-verify", options));
-    }
-
-    // helper methods
-
-    private static List<String> mergeOptions(
-            String firstOption, String... secondPart) {
-
-        return mergeOptions(List.of(firstOption), secondPart);
-    }
-
-    private static List<String> mergeOptions(
-            List<String> firstPart, String... secondPart) {
-
-        List<String> options = new ArrayList<>(firstPart);
-        Collections.addAll(options, secondPart);
-        return options;
-    }
-}
--- a/jdk/test/sun/net/www/protocol/http/SetIfModifiedSince.java	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/test/sun/net/www/protocol/http/SetIfModifiedSince.java	Tue Jan 17 11:35:28 2017 -0800
@@ -22,7 +22,7 @@
  */
 
 /* @test
-   @bug 4213164
+   @bug 4213164 8172253
    @summary setIfModifiedSince mehtod in HttpURLConnection sometimes fails
    */
 import java.util.*;
@@ -88,7 +88,7 @@
      //url = new URL(args[0]);
      url = new URL("http://localhost:" + String.valueOf(port) +
                    "/anything");
-     con = (HttpURLConnection)url.openConnection();
+     con = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
 
      con.setIfModifiedSince(date.getTime());
      con.connect();
--- a/jdk/test/sun/security/pkcs11/sslecc/CipherTest.java	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/test/sun/security/pkcs11/sslecc/CipherTest.java	Tue Jan 17 11:35:28 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2016, 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
@@ -28,7 +28,6 @@
 
 import java.security.*;
 import java.security.cert.*;
-import java.security.cert.Certificate;
 
 import javax.net.ssl.*;
 
@@ -61,6 +60,8 @@
 
     private static PeerFactory peerFactory;
 
+    static final CountDownLatch clientCondition = new CountDownLatch(1);
+
     static abstract class Server implements Runnable {
 
         final CipherTest cipherTest;
@@ -313,6 +314,10 @@
             }
             threads[i].start();
         }
+
+        // The client threads are ready.
+        clientCondition.countDown();
+
         try {
             for (int i = 0; i < THREADS; i++) {
                 threads[i].join();
@@ -367,6 +372,10 @@
                 try {
                     runTest(params);
                     System.out.println("Passed " + params);
+                } catch (SocketTimeoutException ste) {
+                    System.out.println("The client connects to the server timeout, "
+                            + "so ignore the test.");
+                    break;
                 } catch (Exception e) {
                     cipherTest.setFailed();
                     System.out.println("** Failed " + params + "**");
--- a/jdk/test/sun/security/pkcs11/sslecc/JSSEClient.java	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/test/sun/security/pkcs11/sslecc/JSSEClient.java	Tue Jan 17 11:35:28 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2006, 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
@@ -23,10 +23,7 @@
 
 import java.io.*;
 import java.net.*;
-import java.util.*;
 
-import java.security.*;
-import java.security.cert.*;
 import java.security.cert.Certificate;
 
 import javax.net.ssl.*;
@@ -46,10 +43,30 @@
         SSLSocket socket = null;
         try {
             keyManager.setAuthType(params.clientAuth);
-            sslContext.init(new KeyManager[] {keyManager}, new TrustManager[] {cipherTest.trustManager}, cipherTest.secureRandom);
-            SSLSocketFactory factory = (SSLSocketFactory)sslContext.getSocketFactory();
-            socket = (SSLSocket)factory.createSocket("127.0.0.1", cipherTest.serverPort);
-            socket.setSoTimeout(cipherTest.TIMEOUT);
+            sslContext.init(
+                    new KeyManager[] { keyManager },
+                    new TrustManager[] { CipherTest.trustManager },
+                    CipherTest.secureRandom);
+            SSLSocketFactory factory
+                    = (SSLSocketFactory) sslContext.getSocketFactory();
+
+            socket = (SSLSocket) factory.createSocket();
+            try {
+                socket.connect(new InetSocketAddress("127.0.0.1",
+                        CipherTest.serverPort), 15000);
+            } catch (IOException ioe) {
+                // The server side may be impacted by naughty test cases or
+                // third party routines, and cannot accept connections.
+                //
+                // Just ignore the test if the connection cannot be
+                // established.
+                System.out.println(
+                        "Cannot make a connection in 15 seconds. " +
+                        "Ignore in client side.");
+                return;
+            }
+
+            socket.setSoTimeout(CipherTest.TIMEOUT);
             socket.setEnabledCipherSuites(new String[] {params.cipherSuite});
             socket.setEnabledProtocols(new String[] {params.protocol});
             InputStream in = socket.getInputStream();
--- a/jdk/test/sun/security/pkcs11/sslecc/JSSEServer.java	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/test/sun/security/pkcs11/sslecc/JSSEServer.java	Tue Jan 17 11:35:28 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2016, 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
@@ -24,8 +24,11 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.net.SocketTimeoutException;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
 import javax.net.ssl.KeyManager;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLServerSocket;
@@ -40,24 +43,37 @@
     JSSEServer(CipherTest cipherTest) throws Exception {
         super(cipherTest);
         SSLContext serverContext = SSLContext.getInstance("TLS");
-        serverContext.init(new KeyManager[] {cipherTest.keyManager}, new TrustManager[] {cipherTest.trustManager}, cipherTest.secureRandom);
+        serverContext.init(
+                new KeyManager[] { CipherTest.keyManager },
+                new TrustManager[] { CipherTest.trustManager },
+                CipherTest.secureRandom);
 
         SSLServerSocketFactory factory = (SSLServerSocketFactory)serverContext.getServerSocketFactory();
         serverSocket = (SSLServerSocket)factory.createServerSocket(0);
-        cipherTest.serverPort = serverSocket.getLocalPort();
+        serverSocket.setSoTimeout(CipherTest.TIMEOUT);
+        CipherTest.serverPort = serverSocket.getLocalPort();
         serverSocket.setEnabledCipherSuites(factory.getSupportedCipherSuites());
         serverSocket.setWantClientAuth(true);
     }
 
     @Override
     public void run() {
-        System.out.println("JSSE Server listening on port " + cipherTest.serverPort);
+        System.out.println("JSSE Server listening on port " + CipherTest.serverPort);
         Executor exec = Executors.newFixedThreadPool
                             (CipherTest.THREADS, DaemonThreadFactory.INSTANCE);
+
         try {
+            if (!CipherTest.clientCondition.await(CipherTest.TIMEOUT,
+                    TimeUnit.MILLISECONDS)) {
+                System.out.println(
+                        "The client is not the expected one or timeout. "
+                                + "Ignore in server side.");
+                return;
+            }
+
             while (true) {
                 final SSLSocket socket = (SSLSocket)serverSocket.accept();
-                socket.setSoTimeout(cipherTest.TIMEOUT);
+                socket.setSoTimeout(CipherTest.TIMEOUT);
                 Runnable r = new Runnable() {
                     @Override
                     public void run() {
@@ -86,11 +102,12 @@
                 };
                 exec.execute(r);
             }
-        } catch (IOException e) {
+        } catch (SocketTimeoutException ste) {
+            System.out.println("The server got timeout for waiting for the connection, "
+                    + "so ignore the test.");
+        } catch (Exception e) {
             cipherTest.setFailed();
             e.printStackTrace();
-            //
         }
     }
-
 }
--- a/jdk/test/sun/security/tools/keytool/PrintSSL.java	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/test/sun/security/tools/keytool/PrintSSL.java	Tue Jan 17 11:35:28 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,8 +25,7 @@
  * @test
  * @bug 6480981 8160624
  * @summary keytool should be able to import certificates from remote SSL server
- * @library /lib/security
- * @library /lib/testlibrary
+ * @library /test/lib
  * @run main/othervm PrintSSL
  */
 
@@ -36,7 +35,8 @@
 import java.util.concurrent.CountDownLatch;
 import javax.net.ssl.SSLServerSocketFactory;
 import javax.net.ssl.SSLSocket;
-import jdk.testlibrary.OutputAnalyzer;
+import jdk.test.lib.SecurityTools;
+import jdk.test.lib.process.OutputAnalyzer;
 
 public class PrintSSL {
 
--- a/jdk/test/sun/security/tools/keytool/ReadJar.java	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/test/sun/security/tools/keytool/ReadJar.java	Tue Jan 17 11:35:28 2017 -0800
@@ -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
@@ -25,14 +25,15 @@
  * @test
  * @bug 6890872 8168882
  * @summary keytool -printcert to recognize signed jar files
- * @library /lib/security
+ * @library /test/lib
  * @library /lib/testlibrary
  */
 
 import java.nio.file.Files;
 import java.nio.file.Paths;
+import jdk.test.lib.SecurityTools;
+import jdk.test.lib.process.OutputAnalyzer;
 import jdk.testlibrary.JarUtils;
-import jdk.testlibrary.OutputAnalyzer;
 
 public class ReadJar {
 
--- a/jdk/test/tools/jar/InputFilesTest.java	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/test/tools/jar/InputFilesTest.java	Tue Jan 17 11:35:28 2017 -0800
@@ -102,6 +102,7 @@
                 "META-INF/MANIFEST.MF" + nl +
                 "testfile1" + nl +
                 "testfile2" + nl +
+                "META-INF/versions/9/" + nl +
                 "META-INF/versions/9/testfile3" + nl +
                 "META-INF/versions/9/testfile4" + nl;
         rm("test.jar test1 test2 test3 test4");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jar/mmrjar/Basic.java	Tue Jan 17 11:35:28 2017 -0800
@@ -0,0 +1,466 @@
+/*
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8146486 8172432
+ * @summary Fail to create a MR modular JAR with a versioned entry in
+ *          base-versioned empty package
+ * @modules java.base/jdk.internal.module
+ *          jdk.compiler
+ *          jdk.jartool
+ * @library /lib/testlibrary
+ * @build jdk.testlibrary.FileUtils
+ * @run testng Basic
+ */
+
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.UncheckedIOException;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Version;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Optional;
+import java.util.Set;
+import java.util.spi.ToolProvider;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.zip.ZipFile;
+
+import jdk.internal.module.ModuleInfoExtender;
+import jdk.testlibrary.FileUtils;
+
+public class Basic {
+    private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar")
+           .orElseThrow(() -> new RuntimeException("jar tool not found"));
+    private static final ToolProvider JAVAC_TOOL = ToolProvider.findFirst("javac")
+            .orElseThrow(() -> new RuntimeException("javac tool not found"));
+    private final String linesep = System.lineSeparator();
+    private final Path testsrc;
+    private final Path userdir;
+    private final ByteArrayOutputStream outbytes = new ByteArrayOutputStream();
+    private final PrintStream out = new PrintStream(outbytes, true);
+    private final ByteArrayOutputStream errbytes = new ByteArrayOutputStream();
+    private final PrintStream err = new PrintStream(errbytes, true);
+
+    public Basic() throws IOException {
+        testsrc = Paths.get(System.getProperty("test.src"));
+        userdir = Paths.get(System.getProperty("user.dir", "."));
+
+        // compile the classes directory
+        Path source = testsrc.resolve("src").resolve("classes");
+        Path destination = Paths.get("classes");
+        javac(source, destination);
+
+        // compile the mr9 directory including module-info.java
+        source = testsrc.resolve("src").resolve("mr9");
+        destination = Paths.get("mr9");
+        javac(source, destination);
+
+        // move module-info.class for later use
+        Files.move(destination.resolve("module-info.class"),
+                Paths.get("module-info.class"));
+    }
+
+    private void javac(Path source, Path destination) throws IOException {
+        String[] args = Stream.concat(
+                Stream.of("-d", destination.toString()),
+                Files.walk(source)
+                        .map(Path::toString)
+                        .filter(s -> s.endsWith(".java"))
+        ).toArray(String[]::new);
+        JAVAC_TOOL.run(System.out, System.err, args);
+    }
+
+    private int jar(String cmd) {
+        outbytes.reset();
+        errbytes.reset();
+        return JAR_TOOL.run(out, err, cmd.split(" +"));
+    }
+
+    @AfterClass
+    public void cleanup() throws IOException {
+        Files.walk(userdir, 1)
+                .filter(p -> !p.equals(userdir))
+                .forEach(p -> {
+                    try {
+                        if (Files.isDirectory(p)) {
+                            FileUtils.deleteFileTreeWithRetry(p);
+                        } else {
+                            FileUtils.deleteFileIfExistsWithRetry(p);
+                        }
+                    } catch (IOException x) {
+                        throw new UncheckedIOException(x);
+                    }
+                });
+    }
+
+    // updates a valid multi-release jar with a new public class in
+    // versioned section and fails
+    @Test
+    public void test1() {
+        // successful build of multi-release jar
+        int rc = jar("-cf mmr.jar -C classes . --release 9 -C mr9 p/Hi.class");
+        Assert.assertEquals(rc, 0);
+
+        jar("-tf mmr.jar");
+
+        Set<String> actual = lines(outbytes);
+        Set<String> expected = Set.of(
+                "META-INF/",
+                "META-INF/MANIFEST.MF",
+                "p/",
+                "p/Hi.class",
+                "META-INF/versions/9/p/Hi.class"
+        );
+        Assert.assertEquals(actual, expected);
+
+        // failed build because of new public class
+        rc = jar("-uf mmr.jar --release 9 -C mr9 p/internal/Bar.class");
+        Assert.assertEquals(rc, 1);
+
+        String s = new String(errbytes.toByteArray());
+        Assert.assertTrue(Message.NOT_FOUND_IN_BASE_ENTRY.match(s, "p/internal/Bar.class"));
+    }
+
+    // updates a valid multi-release jar with a module-info class and new
+    // concealed public class in versioned section and succeeds
+    @Test
+    public void test2() {
+        // successful build of multi-release jar
+        int rc = jar("-cf mmr.jar -C classes . --release 9 -C mr9 p/Hi.class");
+        Assert.assertEquals(rc, 0);
+
+        // successful build because of module-info and new public class
+        rc = jar("-uf mmr.jar module-info.class --release 9 -C mr9 p/internal/Bar.class");
+        Assert.assertEquals(rc, 0);
+
+        String s = new String(errbytes.toByteArray());
+        Assert.assertTrue(Message.NEW_CONCEALED_PACKAGE_WARNING.match(s, "p/internal/Bar.class"));
+
+        jar("-tf mmr.jar");
+
+        Set<String> actual = lines(outbytes);
+        Set<String> expected = Set.of(
+                "META-INF/",
+                "META-INF/MANIFEST.MF",
+                "p/",
+                "p/Hi.class",
+                "META-INF/versions/9/p/Hi.class",
+                "META-INF/versions/9/p/internal/Bar.class",
+                "module-info.class"
+        );
+        Assert.assertEquals(actual, expected);
+    }
+
+    // jar tool fails building mmr.jar because of new public class
+    @Test
+    public void test3() {
+        int rc = jar("-cf mmr.jar -C classes . --release 9 -C mr9 .");
+        Assert.assertEquals(rc, 1);
+
+        String s = new String(errbytes.toByteArray());
+        Assert.assertTrue(Message.NOT_FOUND_IN_BASE_ENTRY.match(s, "p/internal/Bar.class"));
+    }
+
+    // jar tool succeeds building mmr.jar because of concealed package
+    @Test
+    public void test4() {
+        int rc = jar("-cf mmr.jar module-info.class -C classes . " +
+                "--release 9 module-info.class -C mr9 .");
+        Assert.assertEquals(rc, 0);
+
+        String s = new String(errbytes.toByteArray());
+        Assert.assertTrue(Message.NEW_CONCEALED_PACKAGE_WARNING.match(s, "p/internal/Bar.class"));
+
+        jar("-tf mmr.jar");
+
+        Set<String> actual = lines(outbytes);
+        Set<String> expected = Set.of(
+                "META-INF/",
+                "META-INF/MANIFEST.MF",
+                "module-info.class",
+                "META-INF/versions/9/module-info.class",
+                "p/",
+                "p/Hi.class",
+                "META-INF/versions/9/",
+                "META-INF/versions/9/p/",
+                "META-INF/versions/9/p/Hi.class",
+                "META-INF/versions/9/p/internal/",
+                "META-INF/versions/9/p/internal/Bar.class"
+        );
+        Assert.assertEquals(actual, expected);
+    }
+
+    // jar tool does two updates, no exported packages, all concealed
+    @Test
+    public void test5() throws IOException {
+        // compile the mr10 directory
+        Path source = testsrc.resolve("src").resolve("mr10");
+        Path destination = Paths.get("mr10");
+        javac(source, destination);
+
+        // create a directory for this tests special files
+        Files.createDirectory(Paths.get("test5"));
+
+        // create an empty module-info.java
+        String hi = "module hi {" + linesep + "}" + linesep;
+        Path modinfo = Paths.get("test5", "module-info.java");
+        Files.write(modinfo, hi.getBytes());
+
+        // and compile it
+        javac(modinfo, Paths.get("test5"));
+
+        int rc = jar("--create --file mr.jar -C classes .");
+        Assert.assertEquals(rc, 0);
+
+        rc = jar("--update --file mr.jar -C test5 module-info.class"
+                + " --release 9 -C mr9 .");
+        Assert.assertEquals(rc, 0);
+
+        jar("tf mr.jar");
+
+        Set<String> actual = lines(outbytes);
+        Set<String> expected = Set.of(
+                "META-INF/",
+                "META-INF/MANIFEST.MF",
+                "p/",
+                "p/Hi.class",
+                "META-INF/versions/9/",
+                "META-INF/versions/9/p/",
+                "META-INF/versions/9/p/Hi.class",
+                "META-INF/versions/9/p/internal/",
+                "META-INF/versions/9/p/internal/Bar.class",
+                "module-info.class"
+        );
+        Assert.assertEquals(actual, expected);
+
+        jar("-d --file mr.jar");
+
+        actual = lines(outbytes);
+        expected = Set.of(
+                "hi",
+                "requires mandated java.base",
+                "contains p",
+                "contains p.internal"
+        );
+        Assert.assertEquals(actual, expected);
+
+        rc = jar("--update --file mr.jar --release 10 -C mr10 .");
+        Assert.assertEquals(rc, 0);
+
+        jar("tf mr.jar");
+
+        actual = lines(outbytes);
+        expected = Set.of(
+                "META-INF/",
+                "META-INF/MANIFEST.MF",
+                "p/",
+                "p/Hi.class",
+                "META-INF/versions/9/",
+                "META-INF/versions/9/p/",
+                "META-INF/versions/9/p/Hi.class",
+                "META-INF/versions/9/p/internal/",
+                "META-INF/versions/9/p/internal/Bar.class",
+                "META-INF/versions/10/",
+                "META-INF/versions/10/p/",
+                "META-INF/versions/10/p/internal/",
+                "META-INF/versions/10/p/internal/bar/",
+                "META-INF/versions/10/p/internal/bar/Gee.class",
+                "module-info.class"
+        );
+        Assert.assertEquals(actual, expected);
+
+        jar("-d --file mr.jar");
+
+        actual = lines(outbytes);
+        expected = Set.of(
+                "hi",
+                "requires mandated java.base",
+                "contains p",
+                "contains p.internal",
+                "contains p.internal.bar"
+        );
+        Assert.assertEquals(actual, expected);
+    }
+
+    // root and versioned module-info entries have different main-class, version
+    // attributes
+    @Test
+    public void test6() throws IOException {
+        // create a directory for this tests special files
+        Files.createDirectory(Paths.get("test6"));
+        Files.createDirectory(Paths.get("test6-v9"));
+
+        // compile the classes directory
+        Path src = testsrc.resolve("src").resolve("classes");
+        Path dst = Paths.get("test6");
+        javac(src, dst);
+
+        byte[] mdBytes = Files.readAllBytes(Paths.get("module-info.class"));
+
+        ModuleInfoExtender mie = ModuleInfoExtender.newExtender(
+            new ByteArrayInputStream(mdBytes));
+
+        mie.mainClass("foo.main");
+        mie.version(Version.parse("1.0"));
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        mie.write(baos);
+        Files.write(Paths.get("test6", "module-info.class"), baos.toByteArray());
+        Files.write(Paths.get("test6-v9", "module-info.class"), baos.toByteArray());
+
+        int rc = jar("--create --file mmr.jar -C test6 . --release 9 -C test6-v9 .");
+        Assert.assertEquals(rc, 0);
+
+
+        // different main-class
+        mie = ModuleInfoExtender.newExtender(new ByteArrayInputStream(mdBytes));
+        mie.mainClass("foo.main2");
+        mie.version(Version.parse("1.0"));
+        baos.reset();
+        mie.write(baos);
+        Files.write(Paths.get("test6-v9", "module-info.class"), baos.toByteArray());
+
+        rc = jar("--create --file mmr.jar -C test6 . --release 9 -C test6-v9 .");
+        Assert.assertEquals(rc, 1);
+
+        Assert.assertTrue(Message.CONTAINS_DIFFERENT_MAINCLASS.match(
+            new String(errbytes.toByteArray()),
+            "META-INF/versions/9/module-info.class"));
+
+        // different version
+        mie = ModuleInfoExtender.newExtender(new ByteArrayInputStream(mdBytes));
+        mie.mainClass("foo.main");
+        mie.version(Version.parse("2.0"));
+        baos.reset();
+        mie.write(baos);
+        Files.write(Paths.get("test6-v9", "module-info.class"), baos.toByteArray());
+
+        rc = jar("--create --file mmr.jar -C test6 . --release 9 -C test6-v9 .");
+        Assert.assertEquals(rc, 1);
+
+        Assert.assertTrue(Message.CONTAINS_DIFFERENT_VERSION.match(
+            new String(errbytes.toByteArray()),
+            "META-INF/versions/9/module-info.class"));
+
+    }
+
+    // versioned mmr without root module-info.class
+    @Test
+    public void test7() throws IOException {
+        // create a directory for this tests special files
+        Files.createDirectory(Paths.get("test7"));
+        Files.createDirectory(Paths.get("test7-v9"));
+        Files.createDirectory(Paths.get("test7-v10"));
+
+        // compile the classes directory
+        Path src = testsrc.resolve("src").resolve("classes");
+        Path dst = Paths.get("test7");
+        javac(src, dst);
+
+        // move module-info.class to v9 later use
+        Files.copy(Paths.get("module-info.class"),
+                   Paths.get("test7-v9", "module-info.class"));
+
+        Files.copy(Paths.get("test7-v9", "module-info.class"),
+                   Paths.get("test7-v10", "module-info.class"));
+
+        int rc = jar("--create --file mmr.jar --main-class=foo.main -C test7 . --release 9 -C test7-v9 . --release 10 -C test7-v10 .");
+
+System.out.println("-----------------------");
+System.out.println( new String(errbytes.toByteArray()));
+
+
+        Assert.assertEquals(rc, 0);
+
+
+        jar("-tf mmr.jar");
+
+System.out.println("-----------------------");
+System.out.println( new String(outbytes.toByteArray()));
+
+        Optional<String> exp = Optional.of("foo.main");
+        try (ZipFile zf = new ZipFile("mmr.jar")) {
+            Assert.assertTrue(zf.getEntry("module-info.class") == null);
+
+            ModuleDescriptor md = ModuleDescriptor.read(
+                zf.getInputStream(zf.getEntry("META-INF/versions/9/module-info.class")));
+            Assert.assertEquals(md.mainClass(), exp);
+
+            md = ModuleDescriptor.read(
+                zf.getInputStream(zf.getEntry("META-INF/versions/10/module-info.class")));
+            Assert.assertEquals(md.mainClass(), exp);
+        }
+    }
+
+    private static Set<String> lines(ByteArrayOutputStream baos) {
+        String s = new String(baos.toByteArray());
+        return Arrays.stream(s.split("\\R"))
+                     .map(l -> l.trim())
+                     .filter(l -> l.length() > 0)
+                     .collect(Collectors.toSet());
+    }
+
+    static enum Message {
+        CONTAINS_DIFFERENT_MAINCLASS(
+          ": module-info.class in a versioned directory contains different \"main-class\""
+        ),
+        CONTAINS_DIFFERENT_VERSION(
+          ": module-info.class in a versioned directory contains different \"version\""
+        ),
+        NOT_FOUND_IN_BASE_ENTRY(
+          ", contains a new public class not found in base entries"
+        ),
+        NEW_CONCEALED_PACKAGE_WARNING(
+            " is a public class" +
+            " in a concealed package, placing this jar on the class path will result" +
+            " in incompatible public interfaces"
+        );
+
+        final String msg;
+        Message(String msg) {
+            this.msg = msg;
+        }
+
+        /*
+         * Test if the given output contains this message ignoring the line break.
+         */
+        boolean match(String output, String entry) {
+            System.out.println("Expected: " + entry + msg);
+            System.out.println("Found: " + output);
+            return Arrays.stream(output.split("\\R"))
+                         .collect(Collectors.joining(" "))
+                         .contains(entry + msg);
+        }
+    }
+}
--- a/jdk/test/tools/jar/mmrjar/ConcealedPackage.java	Tue Jan 17 18:24:28 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,339 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 8146486
- * @summary Fail to create a MR modular JAR with a versioned entry in
- *          base-versioned empty package
- * @modules jdk.compiler
- *          jdk.jartool
- * @library /lib/testlibrary
- * @build jdk.testlibrary.FileUtils
- * @run testng ConcealedPackage
- */
-
-import org.testng.Assert;
-import org.testng.annotations.AfterClass;
-import org.testng.annotations.Test;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.io.UncheckedIOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Arrays;
-import java.util.Set;
-import java.util.spi.ToolProvider;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import jdk.testlibrary.FileUtils;
-
-public class ConcealedPackage {
-    private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar")
-           .orElseThrow(() -> new RuntimeException("jar tool not found"));
-    private static final ToolProvider JAVAC_TOOL = ToolProvider.findFirst("javac")
-            .orElseThrow(() -> new RuntimeException("javac tool not found"));
-    private final String linesep = System.lineSeparator();
-    private final Path testsrc;
-    private final Path userdir;
-    private final ByteArrayOutputStream outbytes = new ByteArrayOutputStream();
-    private final PrintStream out = new PrintStream(outbytes, true);
-    private final ByteArrayOutputStream errbytes = new ByteArrayOutputStream();
-    private final PrintStream err = new PrintStream(errbytes, true);
-
-    public ConcealedPackage() throws IOException {
-        testsrc = Paths.get(System.getProperty("test.src"));
-        userdir = Paths.get(System.getProperty("user.dir", "."));
-
-        // compile the classes directory
-        Path source = testsrc.resolve("src").resolve("classes");
-        Path destination = Paths.get("classes");
-        javac(source, destination);
-
-        // compile the mr9 directory including module-info.java
-        source = testsrc.resolve("src").resolve("mr9");
-        destination = Paths.get("mr9");
-        javac(source, destination);
-
-        // move module-info.class for later use
-        Files.move(destination.resolve("module-info.class"),
-                Paths.get("module-info.class"));
-    }
-
-    private void javac(Path source, Path destination) throws IOException {
-        String[] args = Stream.concat(
-                Stream.of("-d", destination.toString()),
-                Files.walk(source)
-                        .map(Path::toString)
-                        .filter(s -> s.endsWith(".java"))
-        ).toArray(String[]::new);
-        JAVAC_TOOL.run(System.out, System.err, args);
-    }
-
-    private int jar(String cmd) {
-        outbytes.reset();
-        errbytes.reset();
-        return JAR_TOOL.run(out, err, cmd.split(" +"));
-    }
-
-    @AfterClass
-    public void cleanup() throws IOException {
-        Files.walk(userdir, 1)
-                .filter(p -> !p.equals(userdir))
-                .forEach(p -> {
-                    try {
-                        if (Files.isDirectory(p)) {
-                            FileUtils.deleteFileTreeWithRetry(p);
-                        } else {
-                            FileUtils.deleteFileIfExistsWithRetry(p);
-                        }
-                    } catch (IOException x) {
-                        throw new UncheckedIOException(x);
-                    }
-                });
-    }
-
-    // updates a valid multi-release jar with a new public class in
-    // versioned section and fails
-    @Test
-    public void test1() {
-        // successful build of multi-release jar
-        int rc = jar("-cf mmr.jar -C classes . --release 9 -C mr9 p/Hi.class");
-        Assert.assertEquals(rc, 0);
-
-        jar("-tf mmr.jar");
-
-        Set<String> actual = lines(outbytes);
-        Set<String> expected = Set.of(
-                "META-INF/",
-                "META-INF/MANIFEST.MF",
-                "p/",
-                "p/Hi.class",
-                "META-INF/versions/9/p/Hi.class"
-        );
-        Assert.assertEquals(actual, expected);
-
-        // failed build because of new public class
-        rc = jar("-uf mmr.jar --release 9 -C mr9 p/internal/Bar.class");
-        Assert.assertEquals(rc, 1);
-
-        String s = new String(errbytes.toByteArray());
-        Assert.assertTrue(Message.NOT_FOUND_IN_BASE_ENTRY.match(s, "p/internal/Bar.class"));
-    }
-
-    // updates a valid multi-release jar with a module-info class and new
-    // concealed public class in versioned section and succeeds
-    @Test
-    public void test2() {
-        // successful build of multi-release jar
-        int rc = jar("-cf mmr.jar -C classes . --release 9 -C mr9 p/Hi.class");
-        Assert.assertEquals(rc, 0);
-
-        // successful build because of module-info and new public class
-        rc = jar("-uf mmr.jar module-info.class --release 9 -C mr9 p/internal/Bar.class");
-        Assert.assertEquals(rc, 0);
-
-        String s = new String(errbytes.toByteArray());
-        Assert.assertTrue(Message.NEW_CONCEALED_PACKAGE_WARNING.match(s, "p/internal/Bar.class"));
-
-        jar("-tf mmr.jar");
-
-        Set<String> actual = lines(outbytes);
-        Set<String> expected = Set.of(
-                "META-INF/",
-                "META-INF/MANIFEST.MF",
-                "p/",
-                "p/Hi.class",
-                "META-INF/versions/9/p/Hi.class",
-                "META-INF/versions/9/p/internal/Bar.class",
-                "module-info.class"
-        );
-        Assert.assertEquals(actual, expected);
-    }
-
-    // jar tool fails building mmr.jar because of new public class
-    @Test
-    public void test3() {
-        int rc = jar("-cf mmr.jar -C classes . --release 9 -C mr9 .");
-        Assert.assertEquals(rc, 1);
-
-        String s = new String(errbytes.toByteArray());
-        Assert.assertTrue(Message.NOT_FOUND_IN_BASE_ENTRY.match(s, "p/internal/Bar.class"));
-    }
-
-    // jar tool succeeds building mmr.jar because of concealed package
-    @Test
-    public void test4() {
-        int rc = jar("-cf mmr.jar module-info.class -C classes . " +
-                "--release 9 module-info.class -C mr9 .");
-        Assert.assertEquals(rc, 0);
-
-        String s = new String(errbytes.toByteArray());
-        Assert.assertTrue(Message.NEW_CONCEALED_PACKAGE_WARNING.match(s, "p/internal/Bar.class"));
-
-        jar("-tf mmr.jar");
-
-        Set<String> actual = lines(outbytes);
-        Set<String> expected = Set.of(
-                "META-INF/",
-                "META-INF/MANIFEST.MF",
-                "module-info.class",
-                "META-INF/versions/9/module-info.class",
-                "p/",
-                "p/Hi.class",
-                "META-INF/versions/9/p/",
-                "META-INF/versions/9/p/Hi.class",
-                "META-INF/versions/9/p/internal/",
-                "META-INF/versions/9/p/internal/Bar.class"
-        );
-        Assert.assertEquals(actual, expected);
-    }
-
-    // jar tool does two updates, no exported packages, all concealed
-    @Test
-    public void test5() throws IOException {
-        // compile the mr10 directory
-        Path source = testsrc.resolve("src").resolve("mr10");
-        Path destination = Paths.get("mr10");
-        javac(source, destination);
-
-        // create a directory for this tests special files
-        Files.createDirectory(Paths.get("test5"));
-
-        // create an empty module-info.java
-        String hi = "module hi {" + linesep + "}" + linesep;
-        Path modinfo = Paths.get("test5", "module-info.java");
-        Files.write(modinfo, hi.getBytes());
-
-        // and compile it
-        javac(modinfo, Paths.get("test5"));
-
-        int rc = jar("--create --file mr.jar -C classes .");
-        Assert.assertEquals(rc, 0);
-
-        rc = jar("--update --file mr.jar -C test5 module-info.class"
-                + " --release 9 -C mr9 .");
-        Assert.assertEquals(rc, 0);
-
-        jar("tf mr.jar");
-
-        Set<String> actual = lines(outbytes);
-        Set<String> expected = Set.of(
-                "META-INF/",
-                "META-INF/MANIFEST.MF",
-                "p/",
-                "p/Hi.class",
-                "META-INF/versions/9/p/",
-                "META-INF/versions/9/p/Hi.class",
-                "META-INF/versions/9/p/internal/",
-                "META-INF/versions/9/p/internal/Bar.class",
-                "module-info.class"
-        );
-        Assert.assertEquals(actual, expected);
-
-        jar("-d --file mr.jar");
-
-        actual = lines(outbytes);
-        expected = Set.of(
-                "hi",
-                "requires mandated java.base",
-                "contains p",
-                "contains p.internal"
-        );
-        Assert.assertEquals(actual, expected);
-
-        rc = jar("--update --file mr.jar --release 10 -C mr10 .");
-        Assert.assertEquals(rc, 0);
-
-        jar("tf mr.jar");
-
-        actual = lines(outbytes);
-        expected = Set.of(
-                "META-INF/",
-                "META-INF/MANIFEST.MF",
-                "p/",
-                "p/Hi.class",
-                "META-INF/versions/9/p/",
-                "META-INF/versions/9/p/Hi.class",
-                "META-INF/versions/9/p/internal/",
-                "META-INF/versions/9/p/internal/Bar.class",
-                "META-INF/versions/10/p/",
-                "META-INF/versions/10/p/internal/",
-                "META-INF/versions/10/p/internal/bar/",
-                "META-INF/versions/10/p/internal/bar/Gee.class",
-                "module-info.class"
-        );
-        Assert.assertEquals(actual, expected);
-
-        jar("-d --file mr.jar");
-
-        actual = lines(outbytes);
-        expected = Set.of(
-                "hi",
-                "requires mandated java.base",
-                "contains p",
-                "contains p.internal",
-                "contains p.internal.bar"
-        );
-        Assert.assertEquals(actual, expected);
-    }
-
-    private static Set<String> lines(ByteArrayOutputStream baos) {
-        String s = new String(baos.toByteArray());
-        return Arrays.stream(s.split("\\R"))
-                     .map(l -> l.trim())
-                     .filter(l -> l.length() > 0)
-                     .collect(Collectors.toSet());
-    }
-
-    static enum Message {
-        NOT_FOUND_IN_BASE_ENTRY(
-          ", contains a new public class not found in base entries"
-        ),
-        NEW_CONCEALED_PACKAGE_WARNING(
-            " is a public class" +
-            " in a concealed package, placing this jar on the class path will result" +
-            " in incompatible public interfaces"
-        );
-
-        final String msg;
-        Message(String msg) {
-            this.msg = msg;
-        }
-
-        /*
-         * Test if the given output contains this message ignoring the line break.
-         */
-        boolean match(String output, String entry) {
-            System.out.println("Expected: " + entry + msg);
-            System.out.println("Found: " + output);
-            return Arrays.stream(output.split("\\R"))
-                         .collect(Collectors.joining(" "))
-                         .contains(entry + msg);
-        }
-    }
-}
--- a/jdk/test/tools/jar/modularJar/Basic.java	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/test/tools/jar/modularJar/Basic.java	Tue Jan 17 11:35:28 2017 -0800
@@ -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
@@ -46,7 +46,7 @@
 
 /*
  * @test
- * @bug 8167328
+ * @bug 8167328 8171830
  * @library /lib/testlibrary
  * @modules jdk.compiler
  *          jdk.jartool
@@ -241,6 +241,11 @@
 
         java(mp, FOO.moduleName + "/" + FOO.mainClass)
             .assertSuccess()
+.resultChecker(r -> {
+        System.out.println("===================================");
+        System.out.println(r.output);
+        System.out.println("===================================");
+})
             .resultChecker(r -> assertModuleData(r, FOO));
         try (InputStream fis = Files.newInputStream(modularJar);
              JarInputStream jis = new JarInputStream(fis)) {
@@ -417,6 +422,7 @@
         jar("--update",
             "--file=" + modularJar.toString(),
             "--main-class=" + FOO.mainClass,
+            "--module-version=" + FOO.version,
             "-m", mrjarDir.resolve("META-INF/MANIFEST.MF").toRealPath().toString(),
             "-C", mrjarDir.toString(), "META-INF/versions/9/module-info.class")
             .assertSuccess();
@@ -734,6 +740,25 @@
     }
 
     @Test
+    public void exportCreateWithMissingPkg() throws IOException {
+
+        Path foobar = TEST_SRC.resolve("src").resolve("foobar");
+        Path dst = Files.createDirectories(MODULE_CLASSES.resolve("foobar"));
+        javac(dst, null, sourceList(foobar));
+
+        Path mp = Paths.get("exportWithMissingPkg");
+        createTestDir(mp);
+        Path modClasses = dst;
+        Path modularJar = mp.resolve("foofoo.jar");
+
+        jar("--create",
+            "--file=" + modularJar.toString(),
+            "-C", modClasses.toString(), "module-info.class",
+            "-C", modClasses.toString(), "jdk/test/foo/Foo.class")
+            .assertFailure();
+    }
+
+    @Test
     public void printModuleDescriptorFoo() throws IOException {
         Path mp = Paths.get("printModuleDescriptorFoo");
         createTestDir(mp);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jar/modularJar/src/foobar/Bar.java	Tue Jan 17 11:35:28 2017 -0800
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.bar;
+
+public class Bar {
+    public static void main(String[] args) {}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jar/modularJar/src/foobar/Foo.java	Tue Jan 17 11:35:28 2017 -0800
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.test.foo;
+
+public class Foo {
+    public static void main(String[] args) {}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jar/modularJar/src/foobar/module-info.java	Tue Jan 17 11:35:28 2017 -0800
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module foo {
+    exports jdk.test.foo;
+    exports jdk.test.bar;
+    opens jdk.test.foo;
+    opens jdk.test.bar;
+}
--- a/jdk/test/tools/jar/multiRelease/Basic1.java	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/test/tools/jar/multiRelease/Basic1.java	Tue Jan 17 11:35:28 2017 -0800
@@ -62,15 +62,20 @@
         Path source = Paths.get(src, "data", test, "base", "version");
         javac(classes, source.resolve("Main.java"), source.resolve("Version.java"));
 
-        Path v9 = Paths.get("v9").resolve("META-INF").resolve("versions").resolve("9");
+        Path v9 = Paths.get("v9");
         Files.createDirectories(v9);
         source = Paths.get(src, "data", test, "v9", "version");
         javac(v9, source.resolve("Version.java"));
 
-        Path v10 = Paths.get("v10").resolve("META-INF").resolve("versions").resolve("10");
+        Path v10 = Paths.get("v10");
         Files.createDirectories(v10);
         source = Paths.get(src, "data", test, "v10", "version");
         javac(v10, source.resolve("Version.java"));
+
+        Path v10_1 = Paths.get("v10_1").resolve("META-INF").resolve("versions").resolve("v10");
+        Files.createDirectories(v10_1);
+        source = Paths.get(src, "data", test, "v10", "version");
+        javac(v10_1, source.resolve("Version.java"));
     }
 
     @Test
@@ -95,28 +100,30 @@
             new String[] {"classes", "base", "version", "Version.class"},
 
             "META-INF/versions/9/version/Version.class",
-            new String[] {"v9", "META-INF", "versions", "9", "version", "Version.class"},
+            new String[] {"v9", "version", "Version.class"},
 
             "META-INF/versions/10/version/Version.class",
-            new String[] {"v10", "META-INF", "versions", "10", "version", "Version.class"}
+            new String[] {"v10", "version", "Version.class"}
         );
 
         compare(jarfile, names);
     }
 
+
     @Test
     public void testFail() throws IOException {
         String jarfile = "test.jar";
         Path classes = Paths.get("classes");
-        Path v9 = Paths.get("v9");
-        Path v10 = Paths.get("v10");
+        Path v10 = Paths.get("v10_1");
 
         jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
-            "--release", "9", "-C", v10.toString(), ".")
+            "--release", "10", "-C", v10.toString(), ".")
             .assertFailure()
             .outputContains("unexpected versioned entry META-INF/versions/");
     }
 
+
+
     private void checkMultiRelease(String jarFile, boolean expected) throws IOException {
         try (JarFile jf = new JarFile(new File(jarFile), true, ZipFile.OPEN_READ,
                 JarFile.runtimeVersion())) {
--- a/jdk/test/tools/jmod/JmodTest.java	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/test/tools/jmod/JmodTest.java	Tue Jan 17 11:35:28 2017 -0800
@@ -580,36 +580,24 @@
     }
 
     @Test
-    public void testTmpFileAlreadyExists() throws IOException {
-        // Implementation detail: jmod tool creates <jmod-file>.tmp
-        // Ensure that there are no problems if existing
-
-        Path jmod = MODS_DIR.resolve("testTmpFileAlreadyExists.jmod");
-        Path tmp = MODS_DIR.resolve("testTmpFileAlreadyExists.jmod.tmp");
-        FileUtils.deleteFileIfExistsWithRetry(jmod);
-        FileUtils.deleteFileIfExistsWithRetry(tmp);
-        Files.createFile(tmp);
-        String cp = EXPLODED_DIR.resolve("foo").resolve("classes").toString();
-
-        jmod("create",
-             "--class-path", cp,
-             jmod.toString())
-            .assertSuccess()
-            .resultChecker(r ->
-                assertTrue(Files.notExists(tmp), "Unexpected tmp file:" + tmp)
-            );
-    }
-
-    @Test
     public void testTmpFileRemoved() throws IOException {
         // Implementation detail: jmod tool creates <jmod-file>.tmp
         // Ensure that it is removed in the event of a failure.
         // The failure in this case is a class in the unnamed package.
 
-        Path jmod = MODS_DIR.resolve("testTmpFileRemoved.jmod");
-        Path tmp = MODS_DIR.resolve("testTmpFileRemoved.jmod.tmp");
+        String filename = "testTmpFileRemoved.jmod";
+        Path jmod = MODS_DIR.resolve(filename);
+
+        // clean up files
         FileUtils.deleteFileIfExistsWithRetry(jmod);
-        FileUtils.deleteFileIfExistsWithRetry(tmp);
+        findTmpFiles(filename).forEach(tmp -> {
+            try {
+                FileUtils.deleteFileIfExistsWithRetry(tmp);
+            } catch (IOException e) {
+                throw new UncheckedIOException(e);
+            }
+        });
+
         String cp = EXPLODED_DIR.resolve("foo").resolve("classes") + File.pathSeparator +
                     EXPLODED_DIR.resolve("foo").resolve("classes")
                                 .resolve("jdk").resolve("test").resolve("foo").toString();
@@ -620,10 +608,22 @@
              .assertFailure()
              .resultChecker(r -> {
                  assertContains(r.output, "unnamed package");
-                 assertTrue(Files.notExists(tmp), "Unexpected tmp file:" + tmp);
+                 Set<Path> tmpfiles = findTmpFiles(filename).collect(toSet());
+                 assertTrue(tmpfiles.isEmpty(), "Unexpected tmp file:" + tmpfiles);
              });
     }
 
+    private Stream<Path> findTmpFiles(String prefix) {
+        try {
+            Path tmpdir = Paths.get(System.getProperty("java.io.tmpdir"));
+            return Files.find(tmpdir, 1, (p, attrs) ->
+                p.getFileName().toString().startsWith(prefix)
+                    && p.getFileName().toString().endsWith(".tmp"));
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
     // ---
 
     static boolean compileModule(String name, Path dest) throws IOException {
--- a/jdk/test/tools/jmod/hashes/HashesTest.java	Tue Jan 17 18:24:28 2017 +0300
+++ b/jdk/test/tools/jmod/hashes/HashesTest.java	Tue Jan 17 11:35:28 2017 -0800
@@ -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
@@ -23,19 +23,22 @@
 
 /*
  * @test
+ * @bug 8160286
  * @summary Test the recording and checking of module hashes
- * @author Andrei Eremeev
  * @library /lib/testlibrary
  * @modules java.base/jdk.internal.misc
  *          java.base/jdk.internal.module
+ *          jdk.compiler
+ *          jdk.jartool
  *          jdk.jlink
- *          jdk.compiler
- * @build CompilerUtils
+ * @build CompilerUtils ModuleInfoMaker
  * @run testng HashesTest
  */
 
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.UncheckedIOException;
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleFinder;
 import java.lang.module.ModuleReader;
@@ -53,109 +56,311 @@
 import java.util.Set;
 import java.util.spi.ToolProvider;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import jdk.internal.module.ModuleInfo;
 import jdk.internal.module.ModuleHashes;
 import jdk.internal.module.ModulePath;
 
-import org.testng.annotations.BeforeTest;
 import org.testng.annotations.Test;
 
 import static org.testng.Assert.*;
+import static java.lang.module.ModuleDescriptor.Requires.Modifier.*;
 
 public class HashesTest {
     static final ToolProvider JMOD_TOOL = ToolProvider.findFirst("jmod")
         .orElseThrow(() ->
             new RuntimeException("jmod tool not found")
         );
+    static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar")
+        .orElseThrow(() ->
+            new RuntimeException("jar tool not found")
+        );
 
-    private final Path testSrc = Paths.get(System.getProperty("test.src"));
-    private final Path modSrc = testSrc.resolve("src");
-    private final Path mods = Paths.get("mods");
-    private final Path jmods = Paths.get("jmods");
-    private final String[] modules = new String[] { "m1", "m2", "m3"};
+    private final Path mods;
+    private final Path srcDir;
+    private final Path lib;
+    private final ModuleInfoMaker builder;
+    HashesTest(Path dest) throws IOException {
+        if (Files.exists(dest)) {
+            deleteDirectory(dest);
+        }
+        this.mods = dest.resolve("mods");
+        this.srcDir = dest.resolve("src");
+        this.lib = dest.resolve("lib");
+        this.builder = new ModuleInfoMaker(srcDir);
+
+        Files.createDirectories(lib);
+        Files.createDirectories(mods);
+    }
+
+    @Test
+    public static void test() throws IOException {
+        Path dest = Paths.get("test");
+        HashesTest ht = new HashesTest(dest);
 
-    @BeforeTest
-    private void setup() throws Exception {
-        if (Files.exists(jmods)) {
-            deleteDirectory(jmods);
-        }
-        Files.createDirectories(jmods);
+        // create modules for test cases
+        ht.makeModule("m2");
+        ht.makeModule("m3");
+        ht.makeModule("m1", "m2", "m3");
+
+        ht.makeModule("org.bar", TRANSITIVE, "m1");
+        ht.makeModule("org.foo", TRANSITIVE, "org.bar");
+
+        // create JMOD for m1, m2, m3
+        ht.makeJmod("m2");
+        ht.makeJmod("m3");
+
+        // no hash is recorded since m1 has outgoing edges
+        ht.jmodHashModules("m1", ".*");
+
+        // no hash is recorded in m1, m2, m3
+        assertTrue(ht.hashes("m1") == null);
+        assertTrue(ht.hashes("m2") == null);
+        assertTrue(ht.hashes("m3") == null);
+
+        // hash m1 in m2
+        ht.jmodHashModules("m2",  "m1");
+        ht.checkHashes("m2", "m1");
+
+        // hash m1 in m2
+        ht.jmodHashModules("m2",  ".*");
+        ht.checkHashes("m2", "m1");
 
-        // build m2, m3 required by m1
-        compileModule("m2", modSrc);
-        jmod("m2");
+        // create m2.jmod with no hash
+        ht.makeJmod("m2");
+        // run jmod hash command to hash m1 in m2 and m3
+        runJmod(List.of("hash", "--module-path", ht.lib.toString(),
+                        "--hash-modules", ".*"));
+        ht.checkHashes("m2", "m1");
+        ht.checkHashes("m3", "m1");
+
+        // check transitive requires
+        ht.makeJmod("org.bar");
+        ht.makeJmod("org.foo");
 
-        compileModule("m3", modSrc);
-        jmod("m3");
+        ht.jmodHashModules("org.bar", "org.*");
+        ht.checkHashes("org.bar", "org.foo");
+
+        ht.jmodHashModules( "m3", ".*");
+        ht.checkHashes("m3", "org.foo", "org.bar", "m1");
+    }
+
+    @Test
+    public static void multiBaseModules() throws IOException {
+        Path dest = Paths.get("test2");
+        HashesTest ht = new HashesTest(dest);
 
-        // build m1
-        compileModule("m1", modSrc);
-        // no hash is recorded since m1 has outgoing edges
-        jmod("m1", "--module-path", jmods.toString(), "--hash-modules", ".*");
+        /*
+         * y2 -----------> y1
+         *    |______
+         *    |      |
+         *    V      V
+         *    z3 -> z2
+         *    |      |
+         *    |      V
+         *    |---> z1
+         */
+
+        ht.makeModule("z1");
+        ht.makeModule("z2", "z1");
+        ht.makeModule("z3", "z1", "z2");
+
+        ht.makeModule("y1");
+        ht.makeModule("y2", "y1", "z2", "z3");
 
-        // compile org.bar and org.foo
-        compileModule("org.bar", modSrc);
-        compileModule("org.foo", modSrc);
+        Set<String> ys = Set.of("y1", "y2");
+        Set<String> zs = Set.of("z1", "z2", "z3");
+
+        // create JMOD files
+        Stream.concat(ys.stream(), zs.stream()).forEach(ht::makeJmod);
+
+        // run jmod hash command
+        runJmod(List.of("hash", "--module-path", ht.lib.toString(),
+                        "--hash-modules", ".*"));
+
+        /*
+         * z1 and y1 are the modules with hashes recorded.
+         */
+        ht.checkHashes("y1", "y2");
+        ht.checkHashes("z1", "z2", "z3", "y2");
+        Stream.concat(ys.stream(), zs.stream())
+              .filter(mn -> !mn.equals("y1") && !mn.equals("z1"))
+              .forEach(mn -> assertTrue(ht.hashes(mn) == null));
     }
 
     @Test
-    public void test() throws Exception {
-        for (String mn : modules) {
-            assertTrue(hashes(mn) == null);
+    public static void mixJmodAndJarFile() throws IOException {
+        Path dest = Paths.get("test3");
+        HashesTest ht = new HashesTest(dest);
+
+        /*
+         * j3 -----------> j2
+         *    |______
+         *    |      |
+         *    V      V
+         *    m3 -> m2
+         *    |      |
+         *    |      V
+         *    |---> m1 -> j1 -> jdk.jlink
+         */
+
+        ht.makeModule("j1");
+        ht.makeModule("j2");
+        ht.makeModule("m1", "j1");
+        ht.makeModule("m2", "m1");
+        ht.makeModule("m3", "m1", "m2");
+
+        ht.makeModule("j3", "j2", "m2", "m3");
+
+        Set<String> jars = Set.of("j1", "j2", "j3");
+        Set<String> jmods = Set.of("m1", "m2", "m3");
+
+        // create JMOD and JAR files
+        jars.forEach(ht::makeJar);
+        jmods.forEach(ht::makeJmod);
+
+        // run jmod hash command
+        runJmod(List.of("hash", "--module-path", ht.lib.toString(),
+                        "--hash-modules", "^j.*|^m.*"));
+
+        /*
+         * j1 and j2 are the modules with hashes recorded.
+         */
+        ht.checkHashes("j2", "j3");
+        ht.checkHashes("j1", "m1", "m2", "m3", "j3");
+        Stream.concat(jars.stream(), jmods.stream())
+              .filter(mn -> !mn.equals("j1") && !mn.equals("j2"))
+              .forEach(mn -> assertTrue(ht.hashes(mn) == null));
+    }
+
+    @Test
+    public static void upgradeableModule() throws IOException {
+        Path mpath = Paths.get(System.getProperty("java.home"), "jmods");
+        if (!Files.exists(mpath)) {
+            return;
         }
 
-        // hash m1 in m2
-        jmod("m2", "--module-path", jmods.toString(), "--hash-modules", "m1");
-        checkHashes(hashes("m2"), "m1");
-
-        // hash m1 in m2
-        jmod("m2", "--module-path", jmods.toString(), "--hash-modules", ".*");
-        checkHashes(hashes("m2"), "m1");
+        Path dest = Paths.get("test4");
+        HashesTest ht = new HashesTest(dest);
+        ht.makeModule("m1");
+        ht.makeModule("java.xml.bind", "m1");
+        ht.makeModule("java.xml.ws", "java.xml.bind");
+        ht.makeModule("m2", "java.xml.ws");
 
-        // create m2.jmod with no hash
-        jmod("m2");
-        // run jmod hash command to hash m1 in m2 and m3
-        runJmod(Arrays.asList("hash", "--module-path", jmods.toString(),
-                "--hash-modules", ".*"));
-        checkHashes(hashes("m2"), "m1");
-        checkHashes(hashes("m3"), "m1");
+        ht.makeJmod("m1");
+        ht.makeJmod("m2");
+        ht.makeJmod("java.xml.ws");
+        ht.makeJmod("java.xml.bind",
+                    "--module-path",
+                    ht.lib.toString() + File.pathSeparator + mpath,
+                    "--hash-modules", "^java.xml.*|^m.*");
 
-        jmod("org.bar");
-        jmod("org.foo");
-
-        jmod("org.bar", "--module-path", jmods.toString(), "--hash-modules", "org.*");
-        checkHashes(hashes("org.bar"), "org.foo");
-
-        jmod("m3", "--module-path", jmods.toString(), "--hash-modules", ".*");
-        checkHashes(hashes("m3"), "org.foo", "org.bar", "m1");
+        ht.checkHashes("java.xml.bind", "java.xml.ws", "m2");
     }
 
-    private void checkHashes(ModuleHashes hashes, String... hashModules) {
+    @Test
+    public static void testImageJmods() throws IOException {
+        Path mpath = Paths.get(System.getProperty("java.home"), "jmods");
+        if (!Files.exists(mpath)) {
+            return;
+        }
+
+        Path dest = Paths.get("test5");
+        HashesTest ht = new HashesTest(dest);
+        ht.makeModule("m1", "jdk.compiler", "jdk.attach");
+        ht.makeModule("m2", "m1");
+        ht.makeModule("m3", "java.compiler");
+
+        ht.makeJmod("m1");
+        ht.makeJmod("m2");
+
+        runJmod(List.of("hash",
+                        "--module-path",
+                        mpath.toString() + File.pathSeparator + ht.lib.toString(),
+                        "--hash-modules", ".*"));
+
+        validateImageJmodsTest(ht, mpath);
+    }
+
+    @Test
+    public static void testImageJmods1() throws IOException {
+        Path mpath = Paths.get(System.getProperty("java.home"), "jmods");
+        if (!Files.exists(mpath)) {
+            return;
+        }
+
+        Path dest = Paths.get("test6");
+        HashesTest ht = new HashesTest(dest);
+        ht.makeModule("m1", "jdk.compiler", "jdk.attach");
+        ht.makeModule("m2", "m1");
+        ht.makeModule("m3", "java.compiler");
+
+        ht.makeJar("m2");
+        ht.makeJar("m1",
+                    "--module-path",
+                    mpath.toString() + File.pathSeparator + ht.lib.toString(),
+                    "--hash-modules", ".*");
+        validateImageJmodsTest(ht, mpath);
+    }
+
+    private static void validateImageJmodsTest(HashesTest ht, Path mpath)
+        throws IOException
+    {
+        // hash is recorded in m1 and not any other packaged modules on module path
+        ht.checkHashes("m1", "m2");
+        assertTrue(ht.hashes("m2") == null);
+
+        // should not override any JDK packaged modules
+        ModuleFinder finder = new ModulePath(Runtime.version(),
+                                             true,
+                                             mpath);
+        assertTrue(ht.hashes(finder,"jdk.compiler") == null);
+        assertTrue(ht.hashes(finder,"jdk.attach") == null);
+    }
+
+    private void checkHashes(String mn, String... hashModules) throws IOException {
+        ModuleHashes hashes = hashes(mn);
         assertTrue(hashes.names().equals(Set.of(hashModules)));
     }
 
-    private ModuleHashes hashes(String name) throws Exception {
+    private ModuleHashes hashes(String name) {
         ModuleFinder finder = new ModulePath(Runtime.version(),
                                              true,
-                                             jmods.resolve(name + ".jmod"));
+                                             lib);
+        return hashes(finder, name);
+    }
+
+    private ModuleHashes hashes(ModuleFinder finder, String name) {
         ModuleReference mref = finder.find(name).orElseThrow(RuntimeException::new);
-        ModuleReader reader = mref.open();
-        try (InputStream in = reader.open("module-info.class").get()) {
-            ModuleHashes hashes = ModuleInfo.read(in, null).recordedHashes();
-            System.out.format("hashes in module %s %s%n", name,
+        try {
+            ModuleReader reader = mref.open();
+            try (InputStream in = reader.open("module-info.class").get()) {
+                ModuleHashes hashes = ModuleInfo.read(in, null).recordedHashes();
+                System.out.format("hashes in module %s %s%n", name,
                     (hashes != null) ? "present" : "absent");
-            if (hashes != null) {
-                hashes.names().stream()
-                    .sorted()
-                    .forEach(n -> System.out.format("  %s %s%n", n, hashes.hashFor(n)));
+                if (hashes != null) {
+                    hashes.names().stream().sorted().forEach(n ->
+                        System.out.format("  %s %s%n", n, toHex(hashes.hashFor(n)))
+                    );
+                }
+                return hashes;
+            } finally {
+                reader.close();
             }
-            return hashes;
-        } finally {
-            reader.close();
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
         }
     }
 
+    private String toHex(byte[] ba) {
+        StringBuilder sb = new StringBuilder(ba.length);
+        for (byte b: ba) {
+            sb.append(String.format("%02x", b & 0xff));
+        }
+        return sb.toString();
+    }
+
     private void deleteDirectory(Path dir) throws IOException {
         Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
             @Override
@@ -176,31 +381,94 @@
         });
     }
 
+
+    private void makeModule(String mn, String... deps) throws IOException {
+        makeModule(mn, null, deps);
+    }
+
+    private void makeModule(String mn, ModuleDescriptor.Requires.Modifier mod,  String... deps)
+        throws IOException
+    {
+        if (mod != null && mod != TRANSITIVE && mod != STATIC) {
+            throw new IllegalArgumentException(mod.toString());
+        }
+
+        StringBuilder sb = new StringBuilder();
+        sb.append("module " + mn + " {").append("\n");
+        Arrays.stream(deps).forEach(req -> {
+            sb.append("    requires ");
+            if (mod != null) {
+                sb.append(mod.toString().toLowerCase()).append(" ");
+            }
+            sb.append(req + ";\n");
+        });
+        sb.append("}\n");
+        builder.writeJavaFiles(mn, sb.toString());
+
+        compileModule(mn, srcDir);
+    }
+
     private void compileModule(String moduleName, Path src) throws IOException {
         Path msrc = src.resolve(moduleName);
         assertTrue(CompilerUtils.compile(msrc, mods, "--module-source-path", src.toString()));
     }
 
-    private void jmod(String moduleName, String... options) throws IOException {
+    private void jmodHashModules(String moduleName, String hashModulesPattern) {
+        makeJmod(moduleName, "--module-path", lib.toString(),
+                 "--hash-modules", hashModulesPattern);
+    }
+
+    private void makeJmod(String moduleName, String... options) {
         Path mclasses = mods.resolve(moduleName);
-        Path outfile = jmods.resolve(moduleName + ".jmod");
+        Path outfile = lib.resolve(moduleName + ".jmod");
         List<String> args = new ArrayList<>();
         args.add("create");
         Collections.addAll(args, options);
         Collections.addAll(args, "--class-path", mclasses.toString(),
                            outfile.toString());
 
-        if (Files.exists(outfile))
-            Files.delete(outfile);
-
+        if (Files.exists(outfile)) {
+            try {
+                Files.delete(outfile);
+            } catch (IOException e) {
+                throw new UncheckedIOException(e);
+            }
+        }
         runJmod(args);
     }
 
-    private void runJmod(List<String> args) {
+    private static void runJmod(List<String> args) {
         int rc = JMOD_TOOL.run(System.out, System.out, args.toArray(new String[args.size()]));
-        System.out.println("jmod options: " + args.stream().collect(Collectors.joining(" ")));
+        System.out.println("jmod " + args.stream().collect(Collectors.joining(" ")));
         if (rc != 0) {
-            throw new AssertionError("Jmod failed: rc = " + rc);
+            throw new AssertionError("jmod failed: rc = " + rc);
+        }
+    }
+
+    private void makeJar(String moduleName, String... options) {
+        Path mclasses = mods.resolve(moduleName);
+        Path outfile = lib.resolve(moduleName + ".jar");
+        List<String> args = new ArrayList<>();
+        Stream.concat(Stream.of("--create",
+                                "--file=" + outfile.toString()),
+                      Arrays.stream(options))
+              .forEach(args::add);
+        args.add("-C");
+        args.add(mclasses.toString());
+        args.add(".");
+
+        if (Files.exists(outfile)) {
+            try {
+                Files.delete(outfile);
+            } catch (IOException e) {
+                throw new UncheckedIOException(e);
+            }
+        }
+
+        int rc = JAR_TOOL.run(System.out, System.out, args.toArray(new String[args.size()]));
+        System.out.println("jar " + args.stream().collect(Collectors.joining(" ")));
+        if (rc != 0) {
+            throw new AssertionError("jar failed: rc = " + rc);
         }
     }
 }
--- a/jdk/test/tools/jmod/hashes/src/m1/module-info.java	Tue Jan 17 18:24:28 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-module m1 {
-    requires m2;
-    requires m3;
-}
--- a/jdk/test/tools/jmod/hashes/src/m1/org/m1/Main.java	Tue Jan 17 18:24:28 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package org.m1;
-
-import org.m2.Util;
-import org.m3.Name;
-
-public class Main {
-    public static void main(String[] args) {
-        System.out.println(Util.timeOfDay());
-        System.out.println(Name.name());
-    }
-}
--- a/jdk/test/tools/jmod/hashes/src/m2/module-info.java	Tue Jan 17 18:24:28 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-module m2 {
-    exports org.m2;
-}
--- a/jdk/test/tools/jmod/hashes/src/m2/org/m2/Util.java	Tue Jan 17 18:24:28 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package org.m2;
-
-public class Util {
-    private Util() { }
-
-    public static String timeOfDay() {
-        return "Time for lunch";
-    }
-}
--- a/jdk/test/tools/jmod/hashes/src/m3/module-info.java	Tue Jan 17 18:24:28 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-module m3 {
-    exports org.m3;
-}
--- a/jdk/test/tools/jmod/hashes/src/m3/org/m3/Name.java	Tue Jan 17 18:24:28 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package org.m3;
-
-public class Name {
-    private Name() { }
-
-    public static String name() {
-        return "m3";
-    }
-}
--- a/jdk/test/tools/jmod/hashes/src/org.bar/module-info.java	Tue Jan 17 18:24:28 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-module org.bar {
-    requires transitive m1;
-}
--- a/jdk/test/tools/jmod/hashes/src/org.foo/module-info.java	Tue Jan 17 18:24:28 2017 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-module org.foo {
-    requires transitive org.bar;
-}