changeset 16567:d4150b065b15

Merge
author ddehaven
date Fri, 20 Jan 2017 08:53:42 -0800
parents bfae5ff40ba4 467b3b7aeb1b
children a928fe94b745
files test/java/lang/SecurityManager/RestrictedPackages.java
diffstat 137 files changed, 3672 insertions(+), 2113 deletions(-) [+]
line wrap: on
line diff
--- a/make/CompileModuleTools.gmk	Fri Jan 20 10:28:34 2017 -0800
+++ b/make/CompileModuleTools.gmk	Fri Jan 20 08:53:42 2017 -0800
@@ -37,6 +37,5 @@
                 build/tools/jigsaw, \
     BIN := $(TOOLS_CLASSES_DIR), \
     ADD_JAVAC_FLAGS := \
-        --add-exports jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED \
         --add-exports java.base/jdk.internal.module=ALL-UNNAMED \
 ))
--- a/make/ModuleTools.gmk	Fri Jan 20 10:28:34 2017 -0800
+++ b/make/ModuleTools.gmk	Fri Jan 20 08:53:42 2017 -0800
@@ -39,7 +39,6 @@
     build.tools.jigsaw.GenGraphs
 
 TOOL_MODULESUMMARY := $(BUILD_JAVA) -esa -ea -cp $(TOOLS_CLASSES_DIR) \
-    --add-exports jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED \
     build.tools.jigsaw.ModuleSummary
 
 TOOL_ADD_PACKAGES_ATTRIBUTE := $(BUILD_JAVA) $(JAVA_FLAGS_SMALL) \
--- a/src/java.base/share/classes/com/sun/net/ssl/HttpsURLConnection.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/com/sun/net/ssl/HttpsURLConnection.java	Fri Jan 20 08:53:42 2017 -0800
@@ -69,6 +69,10 @@
     /**
      * Returns the server's X.509 certificate chain, or null if
      * the server did not authenticate.
+     * <P>
+     * Note: The returned value may not be a valid certificate chain
+     * and should not be relied on for trust decisions.
+     *
      * @return the server certificate chain
      */
     public abstract Certificate[] getServerCertificates()
--- a/src/java.base/share/classes/java/lang/Class.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/java/lang/Class.java	Fri Jan 20 08:53:42 2017 -0800
@@ -508,8 +508,9 @@
     public T newInstance()
         throws InstantiationException, IllegalAccessException
     {
-        if (System.getSecurityManager() != null) {
-            checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), false);
         }
 
         // NOTE: the following code may not be strictly correct under
@@ -1223,38 +1224,27 @@
 
             // Perform access check
             final Class<?> enclosingCandidate = enclosingInfo.getEnclosingClass();
-            enclosingCandidate.checkMemberAccess(Member.DECLARED,
-                                                 Reflection.getCallerClass(), true);
-            // Client is ok to access declared methods but j.l.Class might not be.
-            Method[] candidates = AccessController.doPrivileged(
-                    new PrivilegedAction<>() {
-                        @Override
-                        public Method[] run() {
-                            return enclosingCandidate.getDeclaredMethods();
-                        }
-                    });
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                enclosingCandidate.checkMemberAccess(sm, Member.DECLARED,
+                                                     Reflection.getCallerClass(), true);
+            }
+            Method[] candidates = enclosingCandidate.privateGetDeclaredMethods(false);
+
             /*
              * Loop over all declared methods; match method name,
              * number of and type of parameters, *and* return
              * type.  Matching return type is also necessary
              * because of covariant returns, etc.
              */
-            for(Method m: candidates) {
-                if (m.getName().equals(enclosingInfo.getName()) ) {
-                    Class<?>[] candidateParamClasses = m.getParameterTypes();
-                    if (candidateParamClasses.length == parameterClasses.length) {
-                        boolean matches = true;
-                        for(int i = 0; i < candidateParamClasses.length; i++) {
-                            if (!candidateParamClasses[i].equals(parameterClasses[i])) {
-                                matches = false;
-                                break;
-                            }
-                        }
-
-                        if (matches) { // finally, check return type
-                            if (m.getReturnType().equals(returnType) )
-                                return m;
-                        }
+            ReflectionFactory fact = getReflectionFactory();
+            for (Method m : candidates) {
+                if (m.getName().equals(enclosingInfo.getName()) &&
+                    arrayContentsEq(parameterClasses,
+                                    fact.getExecutableSharedParameterTypes(m))) {
+                    // finally, check return type
+                    if (m.getReturnType().equals(returnType)) {
+                        return fact.copyMethod(m);
                     }
                 }
             }
@@ -1390,33 +1380,23 @@
 
             // Perform access check
             final Class<?> enclosingCandidate = enclosingInfo.getEnclosingClass();
-            enclosingCandidate.checkMemberAccess(Member.DECLARED,
-                                                 Reflection.getCallerClass(), true);
-            // Client is ok to access declared methods but j.l.Class might not be.
-            Constructor<?>[] candidates = AccessController.doPrivileged(
-                    new PrivilegedAction<>() {
-                        @Override
-                        public Constructor<?>[] run() {
-                            return enclosingCandidate.getDeclaredConstructors();
-                        }
-                    });
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                enclosingCandidate.checkMemberAccess(sm, Member.DECLARED,
+                                                     Reflection.getCallerClass(), true);
+            }
+
+            Constructor<?>[] candidates = enclosingCandidate
+                    .privateGetDeclaredConstructors(false);
             /*
              * Loop over all declared constructors; match number
              * of and type of parameters.
              */
-            for(Constructor<?> c: candidates) {
-                Class<?>[] candidateParamClasses = c.getParameterTypes();
-                if (candidateParamClasses.length == parameterClasses.length) {
-                    boolean matches = true;
-                    for(int i = 0; i < candidateParamClasses.length; i++) {
-                        if (!candidateParamClasses[i].equals(parameterClasses[i])) {
-                            matches = false;
-                            break;
-                        }
-                    }
-
-                    if (matches)
-                        return c;
+            ReflectionFactory fact = getReflectionFactory();
+            for (Constructor<?> c : candidates) {
+                if (arrayContentsEq(parameterClasses,
+                                    fact.getExecutableSharedParameterTypes(c))) {
+                    return fact.copyConstructor(c);
                 }
             }
 
@@ -1446,9 +1426,13 @@
     public Class<?> getDeclaringClass() throws SecurityException {
         final Class<?> candidate = getDeclaringClass0();
 
-        if (candidate != null)
-            candidate.checkPackageAccess(
+        if (candidate != null) {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                candidate.checkPackageAccess(sm,
                     ClassLoader.getClassLoader(Reflection.getCallerClass()), true);
+            }
+        }
         return candidate;
     }
 
@@ -1496,9 +1480,13 @@
                 enclosingCandidate = enclosingClass;
         }
 
-        if (enclosingCandidate != null)
-            enclosingCandidate.checkPackageAccess(
+        if (enclosingCandidate != null) {
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                enclosingCandidate.checkPackageAccess(sm,
                     ClassLoader.getClassLoader(Reflection.getCallerClass()), true);
+            }
+        }
         return enclosingCandidate;
     }
 
@@ -1688,7 +1676,10 @@
      */
     @CallerSensitive
     public Class<?>[] getClasses() {
-        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), false);
+        }
 
         // Privileged so this implementation can look at DECLARED classes,
         // something the caller might not have privilege to do.  The code here
@@ -1754,7 +1745,10 @@
      */
     @CallerSensitive
     public Field[] getFields() throws SecurityException {
-        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), true);
+        }
         return copyFields(privateGetPublicFields(null));
     }
 
@@ -1841,7 +1835,10 @@
      */
     @CallerSensitive
     public Method[] getMethods() throws SecurityException {
-        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), true);
+        }
         return copyMethods(privateGetPublicMethods());
     }
 
@@ -1877,7 +1874,10 @@
      */
     @CallerSensitive
     public Constructor<?>[] getConstructors() throws SecurityException {
-        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), true);
+        }
         return copyConstructors(privateGetDeclaredConstructors(true));
     }
 
@@ -1928,7 +1928,10 @@
     public Field getField(String name)
         throws NoSuchFieldException, SecurityException {
         Objects.requireNonNull(name);
-        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), true);
+        }
         Field field = getField0(name);
         if (field == null) {
             throw new NoSuchFieldException(name);
@@ -2034,10 +2037,13 @@
     public Method getMethod(String name, Class<?>... parameterTypes)
         throws NoSuchMethodException, SecurityException {
         Objects.requireNonNull(name);
-        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), true);
+        }
         Method method = getMethod0(name, parameterTypes);
         if (method == null) {
-            throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
+            throw new NoSuchMethodException(methodToString(name, parameterTypes));
         }
         return getReflectionFactory().copyMethod(method);
     }
@@ -2092,8 +2098,12 @@
      */
     @CallerSensitive
     public Constructor<T> getConstructor(Class<?>... parameterTypes)
-        throws NoSuchMethodException, SecurityException {
-        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
+        throws NoSuchMethodException, SecurityException
+    {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), true);
+        }
         return getReflectionFactory().copyConstructor(
             getConstructor0(parameterTypes, Member.PUBLIC));
     }
@@ -2136,7 +2146,10 @@
      */
     @CallerSensitive
     public Class<?>[] getDeclaredClasses() throws SecurityException {
-        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), false);
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), false);
+        }
         return getDeclaredClasses0();
     }
 
@@ -2185,7 +2198,10 @@
      */
     @CallerSensitive
     public Field[] getDeclaredFields() throws SecurityException {
-        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true);
+        }
         return copyFields(privateGetDeclaredFields(false));
     }
 
@@ -2244,7 +2260,10 @@
      */
     @CallerSensitive
     public Method[] getDeclaredMethods() throws SecurityException {
-        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true);
+        }
         return copyMethods(privateGetDeclaredMethods(false));
     }
 
@@ -2289,7 +2308,10 @@
      */
     @CallerSensitive
     public Constructor<?>[] getDeclaredConstructors() throws SecurityException {
-        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true);
+        }
         return copyConstructors(privateGetDeclaredConstructors(false));
     }
 
@@ -2338,7 +2360,10 @@
     public Field getDeclaredField(String name)
         throws NoSuchFieldException, SecurityException {
         Objects.requireNonNull(name);
-        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true);
+        }
         Field field = searchFields(privateGetDeclaredFields(false), name);
         if (field == null) {
             throw new NoSuchFieldException(name);
@@ -2399,10 +2424,13 @@
     public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
         throws NoSuchMethodException, SecurityException {
         Objects.requireNonNull(name);
-        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true);
+        }
         Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);
         if (method == null) {
-            throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
+            throw new NoSuchMethodException(methodToString(name, parameterTypes));
         }
         return getReflectionFactory().copyMethod(method);
     }
@@ -2448,8 +2476,13 @@
      */
     @CallerSensitive
     public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
-        throws NoSuchMethodException, SecurityException {
-        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
+        throws NoSuchMethodException, SecurityException
+    {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            checkMemberAccess(sm, Member.DECLARED, Reflection.getCallerClass(), true);
+        }
+
         return getReflectionFactory().copyConstructor(
             getConstructor0(parameterTypes, Member.DECLARED));
     }
@@ -2697,51 +2730,49 @@
      *
      * <p> Default policy: allow all clients access with normal Java access
      * control.
+     *
+     * <p> NOTE: should only be called if a SecurityManager is installed
      */
-    private void checkMemberAccess(int which, Class<?> caller, boolean checkProxyInterfaces) {
-        final SecurityManager s = System.getSecurityManager();
-        if (s != null) {
-            /* Default policy allows access to all {@link Member#PUBLIC} members,
-             * as well as access to classes that have the same class loader as the caller.
-             * In all other cases, it requires RuntimePermission("accessDeclaredMembers")
-             * permission.
-             */
-            final ClassLoader ccl = ClassLoader.getClassLoader(caller);
+    private void checkMemberAccess(SecurityManager sm, int which,
+                                   Class<?> caller, boolean checkProxyInterfaces) {
+        /* Default policy allows access to all {@link Member#PUBLIC} members,
+         * as well as access to classes that have the same class loader as the caller.
+         * In all other cases, it requires RuntimePermission("accessDeclaredMembers")
+         * permission.
+         */
+        final ClassLoader ccl = caller.getClassLoader0();
+        if (which != Member.PUBLIC) {
             final ClassLoader cl = getClassLoader0();
-            if (which != Member.PUBLIC) {
-                if (ccl != cl) {
-                    s.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
-                }
+            if (ccl != cl) {
+                sm.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
             }
-            this.checkPackageAccess(ccl, checkProxyInterfaces);
         }
+        this.checkPackageAccess(sm, ccl, checkProxyInterfaces);
     }
 
     /*
      * Checks if a client loaded in ClassLoader ccl is allowed to access this
      * class under the current package access policy. If access is denied,
      * throw a SecurityException.
+     *
+     * NOTE: this method should only be called if a SecurityManager is active
      */
-    private void checkPackageAccess(final ClassLoader ccl, boolean checkProxyInterfaces) {
-        final SecurityManager s = System.getSecurityManager();
-        if (s != null) {
-            final ClassLoader cl = getClassLoader0();
-
-            if (ReflectUtil.needsPackageAccessCheck(ccl, cl)) {
-                String name = this.getName();
-                int i = name.lastIndexOf('.');
-                if (i != -1) {
-                    // skip the package access check on a proxy class in default proxy package
-                    String pkg = name.substring(0, i);
-                    if (!Proxy.isProxyClass(this) || ReflectUtil.isNonPublicProxyClass(this)) {
-                        s.checkPackageAccess(pkg);
-                    }
+    private void checkPackageAccess(SecurityManager sm, final ClassLoader ccl,
+                                    boolean checkProxyInterfaces) {
+        final ClassLoader cl = getClassLoader0();
+
+        if (ReflectUtil.needsPackageAccessCheck(ccl, cl)) {
+            String pkg = this.getPackageName();
+            if (pkg != null && !pkg.isEmpty()) {
+                // skip the package access check on a proxy class in default proxy package
+                if (!Proxy.isProxyClass(this) || ReflectUtil.isNonPublicProxyClass(this)) {
+                    sm.checkPackageAccess(pkg);
                 }
             }
-            // check package access on the proxy interfaces
-            if (checkProxyInterfaces && Proxy.isProxyClass(this)) {
-                ReflectUtil.checkProxyPackageAccess(ccl, this.getInterfaces());
-            }
+        }
+        // check package access on the proxy interfaces
+        if (checkProxyInterfaces && Proxy.isProxyClass(this)) {
+            ReflectUtil.checkProxyPackageAccess(ccl, this.getInterfaces());
         }
     }
 
@@ -2755,11 +2786,9 @@
             while (c.isArray()) {
                 c = c.getComponentType();
             }
-            String baseName = c.getName();
-            int index = baseName.lastIndexOf('.');
-            if (index != -1) {
-                name = baseName.substring(0, index).replace('.', '/')
-                    +"/"+name;
+            String baseName = c.getPackageName();
+            if (baseName != null && !baseName.isEmpty()) {
+                name = baseName.replace('.', '/') + "/" + name;
             }
         } else {
             name = name.substring(1);
@@ -3233,7 +3262,7 @@
                 return constructor;
             }
         }
-        throw new NoSuchMethodException(getName() + ".<init>" + argumentTypesToString(parameterTypes));
+        throw new NoSuchMethodException(methodToString("<init>", parameterTypes));
     }
 
     //
@@ -3294,8 +3323,11 @@
     private native Constructor<T>[] getDeclaredConstructors0(boolean publicOnly);
     private native Class<?>[]   getDeclaredClasses0();
 
-    private static String        argumentTypesToString(Class<?>[] argTypes) {
-        StringJoiner sj = new StringJoiner(", ", "(", ")");
+    /**
+     * Helper method to get the method name from arguments.
+     */
+    private String methodToString(String name, Class<?>[] argTypes) {
+        StringJoiner sj = new StringJoiner(", ", getName() + "." + name + "(", ")");
         if (argTypes != null) {
             for (int i = 0; i < argTypes.length; i++) {
                 Class<?> c = argTypes[i];
--- a/src/java.base/share/classes/java/lang/SecurityManager.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/java/lang/SecurityManager.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,18 +25,30 @@
 
 package java.lang;
 
-import java.security.*;
+import java.lang.RuntimePermission;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Opens;
+import java.lang.reflect.Layer;
+import java.lang.reflect.Member;
+import java.lang.reflect.Module;
 import java.io.FileDescriptor;
 import java.io.File;
 import java.io.FilePermission;
+import java.net.InetAddress;
+import java.net.SocketPermission;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.Permission;
+import java.security.PrivilegedAction;
+import java.security.Security;
+import java.security.SecurityPermission;
+import java.util.HashSet;
+import java.util.Objects;
 import java.util.PropertyPermission;
-import java.lang.RuntimePermission;
-import java.net.SocketPermission;
-import java.net.NetPermission;
-import java.util.Hashtable;
-import java.net.InetAddress;
-import java.lang.reflect.*;
-import java.net.URL;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import jdk.internal.reflect.CallerSensitive;
 import sun.security.util.SecurityConstants;
@@ -1415,46 +1427,108 @@
             }
         }
 
-        if (packages == null)
+        if (packages == null) {
             packages = new String[0];
+        }
         return packages;
     }
 
+    // The non-exported packages of the modules in the boot layer that are
+    // loaded by the platform class loader or its ancestors. A non-exported
+    // package is a package that either is not exported at all by its containing
+    // module or is exported in a qualified fashion by its containing module.
+    private static final Set<String> nonExportedPkgs;
+
+    static {
+        // Get the modules in the boot layer
+        Stream<Module> bootLayerModules = Layer.boot().modules().stream();
+
+        // Filter out the modules loaded by the boot or platform loader
+        PrivilegedAction<Set<Module>> pa = () ->
+            bootLayerModules.filter(SecurityManager::isBootOrPlatformModule)
+                            .collect(Collectors.toSet());
+        Set<Module> modules = AccessController.doPrivileged(pa);
+
+        // Filter out the non-exported packages
+        nonExportedPkgs = modules.stream()
+                                 .map(Module::getDescriptor)
+                                 .map(SecurityManager::nonExportedPkgs)
+                                 .flatMap(Set::stream)
+                                 .collect(Collectors.toSet());
+    }
+
     /**
-     * Throws a <code>SecurityException</code> if the
-     * calling thread is not allowed to access the package specified by
-     * the argument.
+     * Returns true if the module's loader is the boot or platform loader.
+     */
+    private static boolean isBootOrPlatformModule(Module m) {
+        return m.getClassLoader() == null ||
+               m.getClassLoader() == ClassLoader.getPlatformClassLoader();
+    }
+
+    /**
+     * Returns the non-exported packages of the specified module.
+     */
+    private static Set<String> nonExportedPkgs(ModuleDescriptor md) {
+        // start with all packages in the module
+        Set<String> pkgs = new HashSet<>(md.packages());
+
+        // remove the non-qualified exported packages
+        md.exports().stream()
+                    .filter(p -> !p.isQualified())
+                    .map(Exports::source)
+                    .forEach(pkgs::remove);
+
+        // remove the non-qualified open packages
+        md.opens().stream()
+                  .filter(p -> !p.isQualified())
+                  .map(Opens::source)
+                  .forEach(pkgs::remove);
+
+        return pkgs;
+    }
+
+    /**
+     * Throws a {@code SecurityException} if the calling thread is not allowed
+     * to access the specified package.
      * <p>
-     * This method is used by the <code>loadClass</code> method of class
-     * loaders.
+     * This method is called by the {@code loadClass} method of class loaders.
      * <p>
-     * This method first gets a list of
-     * restricted packages by obtaining a comma-separated list from
-     * a call to
-     * <code>java.security.Security.getProperty("package.access")</code>,
-     * and checks to see if <code>pkg</code> starts with or equals
-     * any of the restricted packages. If it does, then
-     * <code>checkPermission</code> gets called with the
-     * <code>RuntimePermission("accessClassInPackage."+pkg)</code>
-     * permission.
+     * This method checks if the specified package starts with or equals
+     * any of the packages in the {@code package.access} Security Property.
+     * An implementation may also check the package against an additional
+     * list of restricted packages as noted below. If the package is restricted,
+     * {@link #checkPermission(Permission)} is called with a
+     * {@code RuntimePermission("accessClassInPackage."+pkg)} permission.
      * <p>
-     * If this method is overridden, then
-     * <code>super.checkPackageAccess</code> should be called
-     * as the first line in the overridden method.
+     * If this method is overridden, then {@code super.checkPackageAccess}
+     * should be called as the first line in the overridden method.
+     *
+     * @implNote
+     * This implementation also restricts all non-exported packages of modules
+     * loaded by {@linkplain ClassLoader#getPlatformClassLoader
+     * the platform class loader} or its ancestors. A "non-exported package"
+     * refers to a package that is not exported to all modules. Specifically,
+     * it refers to a package that either is not exported at all by its
+     * containing module or is exported in a qualified fashion by its
+     * containing module.
      *
      * @param      pkg   the package name.
-     * @exception  SecurityException  if the calling thread does not have
+     * @throws     SecurityException  if the calling thread does not have
      *             permission to access the specified package.
-     * @exception  NullPointerException if the package name argument is
-     *             <code>null</code>.
-     * @see        java.lang.ClassLoader#loadClass(java.lang.String, boolean)
-     *  loadClass
+     * @throws     NullPointerException if the package name argument is
+     *             {@code null}.
+     * @see        java.lang.ClassLoader#loadClass(String, boolean) loadClass
      * @see        java.security.Security#getProperty getProperty
-     * @see        #checkPermission(java.security.Permission) checkPermission
+     * @see        #checkPermission(Permission) checkPermission
      */
     public void checkPackageAccess(String pkg) {
-        if (pkg == null) {
-            throw new NullPointerException("package name can't be null");
+        Objects.requireNonNull(pkg, "package name can't be null");
+
+        // check if pkg is not exported to all modules
+        if (nonExportedPkgs.contains(pkg)) {
+            checkPermission(
+                new RuntimePermission("accessClassInPackage." + pkg));
+            return;
         }
 
         String[] restrictedPkgs;
@@ -1512,36 +1586,48 @@
     }
 
     /**
-     * Throws a <code>SecurityException</code> if the
-     * calling thread is not allowed to define classes in the package
-     * specified by the argument.
+     * Throws a {@code SecurityException} if the calling thread is not
+     * allowed to define classes in the specified package.
      * <p>
-     * This method is used by the <code>loadClass</code> method of some
+     * This method is called by the {@code loadClass} method of some
      * class loaders.
      * <p>
-     * This method first gets a list of restricted packages by
-     * obtaining a comma-separated list from a call to
-     * <code>java.security.Security.getProperty("package.definition")</code>,
-     * and checks to see if <code>pkg</code> starts with or equals
-     * any of the restricted packages. If it does, then
-     * <code>checkPermission</code> gets called with the
-     * <code>RuntimePermission("defineClassInPackage."+pkg)</code>
-     * permission.
+     * This method checks if the specified package starts with or equals
+     * any of the packages in the {@code package.definition} Security
+     * Property. An implementation may also check the package against an
+     * additional list of restricted packages as noted below. If the package
+     * is restricted, {@link #checkPermission(Permission)} is called with a
+     * {@code RuntimePermission("defineClassInPackage."+pkg)} permission.
      * <p>
-     * If this method is overridden, then
-     * <code>super.checkPackageDefinition</code> should be called
-     * as the first line in the overridden method.
+     * If this method is overridden, then {@code super.checkPackageDefinition}
+     * should be called as the first line in the overridden method.
+     *
+     * @implNote
+     * This implementation also restricts all non-exported packages of modules
+     * loaded by {@linkplain ClassLoader#getPlatformClassLoader
+     * the platform class loader} or its ancestors. A "non-exported package"
+     * refers to a package that is not exported to all modules. Specifically,
+     * it refers to a package that either is not exported at all by its
+     * containing module or is exported in a qualified fashion by its
+     * containing module.
      *
      * @param      pkg   the package name.
-     * @exception  SecurityException  if the calling thread does not have
+     * @throws     SecurityException  if the calling thread does not have
      *             permission to define classes in the specified package.
-     * @see        java.lang.ClassLoader#loadClass(java.lang.String, boolean)
+     * @throws     NullPointerException if the package name argument is
+     *             {@code null}.
+     * @see        java.lang.ClassLoader#loadClass(String, boolean)
      * @see        java.security.Security#getProperty getProperty
-     * @see        #checkPermission(java.security.Permission) checkPermission
+     * @see        #checkPermission(Permission) checkPermission
      */
     public void checkPackageDefinition(String pkg) {
-        if (pkg == null) {
-            throw new NullPointerException("package name can't be null");
+        Objects.requireNonNull(pkg, "package name can't be null");
+
+        // check if pkg is not exported to all modules
+        if (nonExportedPkgs.contains(pkg)) {
+            checkPermission(
+                new RuntimePermission("defineClassInPackage." + pkg));
+            return;
         }
 
         String[] pkgs;
--- a/src/java.base/share/classes/java/lang/System.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/java/lang/System.java	Fri Jan 20 08:53:42 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
@@ -310,12 +310,13 @@
      * @see SecurityManager#checkPermission
      * @see java.lang.RuntimePermission
      */
-    public static
-    void setSecurityManager(final SecurityManager s) {
-        try {
-            s.checkPackageAccess("java.lang");
-        } catch (Exception e) {
-            // no-op
+    public static void setSecurityManager(final SecurityManager s) {
+        if (s != null) {
+            try {
+                s.checkPackageAccess("java.lang");
+            } catch (Exception e) {
+                // no-op
+            }
         }
         setSecurityManager0(s);
     }
--- a/src/java.base/share/classes/java/lang/invoke/CallSite.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/java/lang/invoke/CallSite.java	Fri Jan 20 08:53:42 2017 -0800
@@ -28,6 +28,8 @@
 import static java.lang.invoke.MethodHandleStatics.*;
 import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
 
+import jdk.internal.vm.annotation.Stable;
+
 /**
  * A {@code CallSite} is a holder for a variable {@link MethodHandle},
  * which is called its {@code target}.
@@ -215,19 +217,36 @@
     public abstract MethodHandle dynamicInvoker();
 
     /*non-public*/ MethodHandle makeDynamicInvoker() {
-        MethodHandle getTarget = GET_TARGET.bindArgumentL(0, this);
+        MethodHandle getTarget = getTargetHandle().bindArgumentL(0, this);
         MethodHandle invoker = MethodHandles.exactInvoker(this.type());
         return MethodHandles.foldArguments(invoker, getTarget);
     }
 
-    private static final MethodHandle GET_TARGET;
-    private static final MethodHandle THROW_UCS;
-    static {
+    private static @Stable MethodHandle GET_TARGET;
+    private static MethodHandle getTargetHandle() {
+        MethodHandle handle = GET_TARGET;
+        if (handle != null) {
+            return handle;
+        }
         try {
-            GET_TARGET = IMPL_LOOKUP.
-                findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class));
-            THROW_UCS = IMPL_LOOKUP.
-                findStatic(CallSite.class, "uninitializedCallSite", MethodType.methodType(Object.class, Object[].class));
+            return GET_TARGET = IMPL_LOOKUP.
+                    findVirtual(CallSite.class, "getTarget",
+                                MethodType.methodType(MethodHandle.class));
+        } catch (ReflectiveOperationException e) {
+            throw newInternalError(e);
+        }
+    }
+
+    private static @Stable MethodHandle THROW_UCS;
+    private static MethodHandle uninitializedCallSiteHandle() {
+        MethodHandle handle = THROW_UCS;
+        if (handle != null) {
+            return handle;
+        }
+        try {
+            return THROW_UCS = IMPL_LOOKUP.
+                findStatic(CallSite.class, "uninitializedCallSite",
+                           MethodType.methodType(Object.class, Object[].class));
         } catch (ReflectiveOperationException e) {
             throw newInternalError(e);
         }
@@ -242,7 +261,7 @@
         MethodType basicType = targetType.basicType();
         MethodHandle invoker = basicType.form().cachedMethodHandle(MethodTypeForm.MH_UNINIT_CS);
         if (invoker == null) {
-            invoker = THROW_UCS.asType(basicType);
+            invoker = uninitializedCallSiteHandle().asType(basicType);
             invoker = basicType.form().setCachedMethodHandle(MethodTypeForm.MH_UNINIT_CS, invoker);
         }
         // unchecked view is OK since no values will be received or returned
@@ -250,12 +269,16 @@
     }
 
     // unsafe stuff:
-    private static final long  TARGET_OFFSET;
-    private static final long CONTEXT_OFFSET;
-    static {
+    private static @Stable long TARGET_OFFSET;
+    private static long getTargetOffset() {
+        long offset = TARGET_OFFSET;
+        if (offset > 0) {
+            return offset;
+        }
         try {
-            TARGET_OFFSET  = UNSAFE.objectFieldOffset(CallSite.class.getDeclaredField("target"));
-            CONTEXT_OFFSET = UNSAFE.objectFieldOffset(CallSite.class.getDeclaredField("context"));
+            offset = TARGET_OFFSET = UNSAFE.objectFieldOffset(CallSite.class.getDeclaredField("target"));
+            assert(offset > 0);
+            return offset;
         } catch (Exception ex) { throw newInternalError(ex); }
     }
 
@@ -265,7 +288,7 @@
     }
     /*package-private*/
     MethodHandle getTargetVolatile() {
-        return (MethodHandle) UNSAFE.getObjectVolatile(this, TARGET_OFFSET);
+        return (MethodHandle) UNSAFE.getObjectVolatile(this, getTargetOffset());
     }
     /*package-private*/
     void setTargetVolatile(MethodHandle newTarget) {
@@ -324,7 +347,7 @@
                         final int NON_SPREAD_ARG_COUNT = 3;  // (caller, name, type)
                         if (NON_SPREAD_ARG_COUNT + argv.length > MethodType.MAX_MH_ARITY)
                             throw new BootstrapMethodError("too many bootstrap method arguments");
-                        MethodType bsmType = bootstrapMethod.type();
+
                         MethodType invocationType = MethodType.genericMethodType(NON_SPREAD_ARG_COUNT + argv.length);
                         MethodHandle typedBSM = bootstrapMethod.asType(invocationType);
                         MethodHandle spreader = invocationType.invokers().spreadInvoker(NON_SPREAD_ARG_COUNT);
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Fri Jan 20 08:53:42 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
@@ -846,8 +846,11 @@
             // that does not bluntly restrict classes under packages within
             // java.base from looking up MethodHandles or VarHandles.
             if (allowedModes == ALL_MODES && lookupClass.getClassLoader() == null) {
-                if ((name.startsWith("java.") && !name.startsWith("java.util.concurrent.")) ||
-                        (name.startsWith("sun.") && !name.startsWith("sun.invoke."))) {
+                if ((name.startsWith("java.") &&
+                     !name.equals("java.lang.Thread") &&
+                     !name.startsWith("java.util.concurrent.")) ||
+                    (name.startsWith("sun.") &&
+                     !name.startsWith("sun.invoke."))) {
                     throw newIllegalArgumentException("illegal lookupClass: " + lookupClass);
                 }
             }
--- a/src/java.base/share/classes/java/lang/invoke/MethodType.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/java/lang/invoke/MethodType.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1128,7 +1128,7 @@
     public String toMethodDescriptorString() {
         String desc = methodDescriptor;
         if (desc == null) {
-            desc = BytecodeDescriptor.unparse(this);
+            desc = BytecodeDescriptor.unparseMethod(this.rtype, this.ptypes);
             methodDescriptor = desc;
         }
         return desc;
@@ -1256,7 +1256,7 @@
         private final ReferenceQueue<T> stale;
 
         public ConcurrentWeakInternSet() {
-            this.map = new ConcurrentHashMap<>();
+            this.map = new ConcurrentHashMap<>(512);
             this.stale = new ReferenceQueue<>();
         }
 
--- a/src/java.base/share/classes/java/net/SocketInputStream.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/java/net/SocketInputStream.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 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
@@ -155,11 +155,12 @@
         }
 
         // bounds check
-        if (length <= 0 || off < 0 || off + length > b.length) {
+        if (length <= 0 || off < 0 || length > b.length - off) {
             if (length == 0) {
                 return 0;
             }
-            throw new ArrayIndexOutOfBoundsException();
+            throw new ArrayIndexOutOfBoundsException("length == " + length
+                    + " off == " + off + " buffer length == " + b.length);
         }
 
         boolean gotReset = false;
--- a/src/java.base/share/classes/java/net/SocketOutputStream.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/java/net/SocketOutputStream.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 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
@@ -97,11 +97,13 @@
      */
     private void socketWrite(byte b[], int off, int len) throws IOException {
 
-        if (len <= 0 || off < 0 || off + len > b.length) {
+
+        if (len <= 0 || off < 0 || len > b.length - off) {
             if (len == 0) {
                 return;
             }
-            throw new ArrayIndexOutOfBoundsException();
+            throw new ArrayIndexOutOfBoundsException("len == " + len
+                    + " off == " + off + " buffer length == " + b.length);
         }
 
         FileDescriptor fd = impl.acquireFD();
--- a/src/java.base/share/classes/java/net/URL.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/java/net/URL.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1556,9 +1556,6 @@
                 path = file;
         }
 
-        if (port == -1) {
-            port = 0;
-        }
         // Set the object fields.
         this.protocol = protocol;
         this.host = host;
--- a/src/java.base/share/classes/java/net/URLClassLoader.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/java/net/URLClassLoader.java	Fri Jan 20 08:53:42 2017 -0800
@@ -115,8 +115,8 @@
         if (security != null) {
             security.checkCreateClassLoader();
         }
-        this.ucp = new URLClassPath(urls);
         this.acc = AccessController.getContext();
+        this.ucp = new URLClassPath(urls, acc);
     }
 
     URLClassLoader(String name, URL[] urls, ClassLoader parent,
@@ -127,8 +127,8 @@
         if (security != null) {
             security.checkCreateClassLoader();
         }
-        this.ucp = new URLClassPath(urls);
         this.acc = acc;
+        this.ucp = new URLClassPath(urls, acc);
     }
 
     /**
@@ -159,8 +159,8 @@
         if (security != null) {
             security.checkCreateClassLoader();
         }
-        this.ucp = new URLClassPath(urls);
         this.acc = AccessController.getContext();
+        this.ucp = new URLClassPath(urls, acc);
     }
 
     URLClassLoader(URL[] urls, AccessControlContext acc) {
@@ -170,8 +170,8 @@
         if (security != null) {
             security.checkCreateClassLoader();
         }
-        this.ucp = new URLClassPath(urls);
         this.acc = acc;
+        this.ucp = new URLClassPath(urls, acc);
     }
 
     /**
@@ -203,8 +203,8 @@
         if (security != null) {
             security.checkCreateClassLoader();
         }
-        this.ucp = new URLClassPath(urls, factory);
         this.acc = AccessController.getContext();
+        this.ucp = new URLClassPath(urls, factory, acc);
     }
 
 
@@ -238,8 +238,8 @@
         if (security != null) {
             security.checkCreateClassLoader();
         }
-        this.ucp = new URLClassPath(urls);
         this.acc = AccessController.getContext();
+        this.ucp = new URLClassPath(urls, acc);
     }
 
     /**
@@ -271,8 +271,8 @@
         if (security != null) {
             security.checkCreateClassLoader();
         }
-        this.ucp = new URLClassPath(urls, factory);
         this.acc = AccessController.getContext();
+        this.ucp = new URLClassPath(urls, factory, acc);
     }
 
     /* A map (used as a set) to keep track of closeable local resources
--- a/src/java.base/share/classes/java/net/URLStreamHandler.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/java/net/URLStreamHandler.java	Fri Jan 20 08:53:42 2017 -0800
@@ -161,9 +161,9 @@
             (spec.charAt(start + 1) == '/')) {
             start += 2;
             i = spec.indexOf('/', start);
-            if (i < 0) {
+            if (i < 0 || i > limit) {
                 i = spec.indexOf('?', start);
-                if (i < 0)
+                if (i < 0 || i > limit)
                     i = limit;
             }
 
@@ -171,8 +171,14 @@
 
             int ind = authority.indexOf('@');
             if (ind != -1) {
-                userInfo = authority.substring(0, ind);
-                host = authority.substring(ind+1);
+                if (ind != authority.lastIndexOf('@')) {
+                    // more than one '@' in authority. This is not server based
+                    userInfo = null;
+                    host = null;
+                } else {
+                    userInfo = authority.substring(0, ind);
+                    host = authority.substring(ind+1);
+                }
             } else {
                 userInfo = null;
             }
--- a/src/java.base/share/classes/java/util/ResourceBundle.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/java/util/ResourceBundle.java	Fri Jan 20 08:53:42 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
@@ -43,6 +43,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.UncheckedIOException;
+import java.lang.ref.Reference;
 import java.lang.ref.ReferenceQueue;
 import java.lang.ref.SoftReference;
 import java.lang.ref.WeakReference;
@@ -365,7 +366,7 @@
                 @Override
                 public ResourceBundle getBundle(String baseName, Locale locale, Module module) {
                     // use the given module as the caller to bypass the access check
-                    return getBundleImpl(module, module, getLoader(module),
+                    return getBundleImpl(module, module,
                                          baseName, locale, Control.INSTANCE);
                 }
 
@@ -537,63 +538,19 @@
         return locale;
     }
 
-    /*
-     * Automatic determination of the ClassLoader to be used to load
-     * resources on behalf of the client.
-     */
-    private static ClassLoader getLoader(Class<?> caller) {
-        ClassLoader cl = caller == null ? null : caller.getClassLoader();
-        if (cl == null) {
-            // When the caller's loader is the boot class loader, cl is null
-            // here. In that case, ClassLoader.getSystemClassLoader() may
-            // return the same class loader that the application is
-            // using. We therefore use a wrapper ClassLoader to create a
-            // separate scope for bundles loaded on behalf of the Java
-            // runtime so that these bundles cannot be returned from the
-            // cache to the application (5048280).
-            cl = RBClassLoader.INSTANCE;
-        }
-        return cl;
-    }
-
     private static ClassLoader getLoader(Module module) {
         PrivilegedAction<ClassLoader> pa = module::getClassLoader;
         return AccessController.doPrivileged(pa);
     }
 
     /**
-     * A wrapper of ClassLoader.getSystemClassLoader().
+     * @param module a non-null-screened module form the {@link CacheKey#getModule()}.
+     * @return the ClassLoader to use in {@link Control#needsReload}
+     *         and {@link Control#newBundle}
      */
-    private static class RBClassLoader extends ClassLoader {
-        private static final RBClassLoader INSTANCE = AccessController.doPrivileged(
-                    new PrivilegedAction<RBClassLoader>() {
-                        public RBClassLoader run() {
-                            return new RBClassLoader();
-                        }
-                    });
-        private RBClassLoader() {
-        }
-        public Class<?> loadClass(String name) throws ClassNotFoundException {
-            ClassLoader loader = ClassLoader.getSystemClassLoader();
-            if (loader != null) {
-                return loader.loadClass(name);
-            }
-            return Class.forName(name);
-        }
-        public URL getResource(String name) {
-            ClassLoader loader = ClassLoader.getSystemClassLoader();
-            if (loader != null) {
-                return loader.getResource(name);
-            }
-            return ClassLoader.getSystemResource(name);
-        }
-        public InputStream getResourceAsStream(String name) {
-            ClassLoader loader = ClassLoader.getSystemClassLoader();
-            if (loader != null) {
-                return loader.getResourceAsStream(name);
-            }
-            return ClassLoader.getSystemResourceAsStream(name);
-        }
+    private static ClassLoader getLoaderForControl(Module module) {
+        ClassLoader loader = getLoader(module);
+        return loader == null ? ClassLoader.getSystemClassLoader() : loader;
     }
 
     /**
@@ -610,23 +567,23 @@
 
     /**
      * Key used for cached resource bundles.  The key checks the base
-     * name, the locale, the class loader, and the caller module
+     * name, the locale, the bundle module, and the caller module
      * to determine if the resource is a match to the requested one.
-     * The loader may be null, but the base name, the locale and
-     * module must have a non-null value.
+     * The base name, the locale and both modules must have a non-null value.
      */
-    private static class CacheKey implements Cloneable {
+    private static final class CacheKey {
         // These four are the actual keys for lookup in Map.
-        private String name;
-        private Locale locale;
-        private KeyElementReference<ClassLoader> loaderRef;
-        private KeyElementReference<Module> moduleRef;
-        private KeyElementReference<Module> callerRef;
-
+        private final String name;
+        private volatile Locale locale;
+        private final KeyElementReference<Module> moduleRef;
+        private final KeyElementReference<Module> callerRef;
+        // this is the part of hashCode that pertains to module and callerModule
+        // which can be GCed..
+        private final int modulesHash;
 
         // bundle format which is necessary for calling
         // Control.needsReload().
-        private String format;
+        private volatile String format;
 
         // These time values are in CacheKey so that NONEXISTENT_BUNDLE
         // doesn't need to be cloned for caching.
@@ -639,63 +596,55 @@
         private volatile long expirationTime;
 
         // Placeholder for an error report by a Throwable
-        private Throwable cause;
-
-        // Hash code value cache to avoid recalculating the hash code
-        // of this instance.
-        private int hashCodeCache;
+        private volatile Throwable cause;
 
         // ResourceBundleProviders for loading ResourceBundles
-        private ServiceLoader<ResourceBundleProvider> providers;
-        private boolean providersChecked;
+        private volatile ServiceLoader<ResourceBundleProvider> providers;
+        private volatile boolean providersChecked;
 
         // Boolean.TRUE if the factory method caller provides a ResourceBundleProvier.
-        private Boolean callerHasProvider;
+        private volatile Boolean callerHasProvider;
 
-        CacheKey(String baseName, Locale locale, ClassLoader loader, Module module, Module caller) {
+        CacheKey(String baseName, Locale locale, Module module, Module caller) {
             Objects.requireNonNull(module);
+            Objects.requireNonNull(caller);
 
             this.name = baseName;
             this.locale = locale;
-            if (loader == null) {
-                this.loaderRef = null;
-            } else {
-                this.loaderRef = new KeyElementReference<>(loader, referenceQueue, this);
-            }
             this.moduleRef = new KeyElementReference<>(module, referenceQueue, this);
             this.callerRef = new KeyElementReference<>(caller, referenceQueue, this);
+            this.modulesHash = module.hashCode() ^ caller.hashCode();
+        }
 
-            calculateHashCode();
+        CacheKey(CacheKey src) {
+            // Create References to src's modules
+            this.moduleRef = new KeyElementReference<>(
+                Objects.requireNonNull(src.getModule()), referenceQueue, this);
+            this.callerRef = new KeyElementReference<>(
+                Objects.requireNonNull(src.getCallerModule()), referenceQueue, this);
+            // Copy fields from src. ResourceBundleProviders related fields
+            // and "cause" should not be copied.
+            this.name = src.name;
+            this.locale = src.locale;
+            this.modulesHash = src.modulesHash;
+            this.format = src.format;
+            this.loadTime = src.loadTime;
+            this.expirationTime = src.expirationTime;
         }
 
         String getName() {
             return name;
         }
 
-        CacheKey setName(String baseName) {
-            if (!this.name.equals(baseName)) {
-                this.name = baseName;
-                calculateHashCode();
-            }
-            return this;
-        }
-
         Locale getLocale() {
             return locale;
         }
 
         CacheKey setLocale(Locale locale) {
-            if (!this.locale.equals(locale)) {
-                this.locale = locale;
-                calculateHashCode();
-            }
+            this.locale = locale;
             return this;
         }
 
-        ClassLoader getLoader() {
-            return (loaderRef != null) ? loaderRef.get() : null;
-        }
-
         Module getModule() {
             return moduleRef.get();
         }
@@ -728,7 +677,7 @@
             try {
                 final CacheKey otherEntry = (CacheKey)other;
                 //quick check to see if they are not equal
-                if (hashCodeCache != otherEntry.hashCodeCache) {
+                if (modulesHash != otherEntry.modulesHash) {
                     return false;
                 }
                 //are the names the same?
@@ -739,24 +688,11 @@
                 if (!locale.equals(otherEntry.locale)) {
                     return false;
                 }
-                //are refs (both non-null) or (both null)?
-                if (loaderRef == null) {
-                    return otherEntry.loaderRef == null;
-                }
-                ClassLoader loader = getLoader();
+                // are modules and callerModules the same and non-null?
                 Module module = getModule();
                 Module caller = getCallerModule();
-
-                return (otherEntry.loaderRef != null)
-                        // with a null reference we can no longer find
-                        // out which class loader or module was referenced; so
-                        // treat it as unequal
-                        && (loader != null)
-                        && (loader == otherEntry.getLoader())
-                        && (module != null)
-                        && (module.equals(otherEntry.getModule()))
-                        && (caller != null)
-                        && (caller.equals(otherEntry.getCallerModule()));
+                return ((module != null) && (module.equals(otherEntry.getModule())) &&
+                        (caller != null) && (caller.equals(otherEntry.getCallerModule())));
             } catch (NullPointerException | ClassCastException e) {
             }
             return false;
@@ -764,51 +700,7 @@
 
         @Override
         public int hashCode() {
-            return hashCodeCache;
-        }
-
-        private void calculateHashCode() {
-            hashCodeCache = name.hashCode() << 3;
-            hashCodeCache ^= locale.hashCode();
-            ClassLoader loader = getLoader();
-            if (loader != null) {
-                hashCodeCache ^= loader.hashCode();
-            }
-            Module module = getModule();
-            if (module != null) {
-                hashCodeCache ^= module.hashCode();
-            }
-            Module caller = getCallerModule();
-            if (caller != null) {
-                hashCodeCache ^= caller.hashCode();
-            }
-        }
-
-        @Override
-        public Object clone() {
-            try {
-                CacheKey clone = (CacheKey) super.clone();
-                if (loaderRef != null) {
-                    clone.loaderRef = new KeyElementReference<>(getLoader(),
-                                                                referenceQueue, clone);
-                }
-                clone.moduleRef = new KeyElementReference<>(getModule(),
-                                                            referenceQueue, clone);
-                clone.callerRef = new KeyElementReference<>(getCallerModule(),
-                                                            referenceQueue, clone);
-
-                // Clear the reference to ResourceBundleProviders and the flag
-                clone.providers = null;
-                clone.providersChecked = false;
-                // Clear the reference to a Throwable
-                clone.cause = null;
-                // Clear callerHasProvider
-                clone.callerHasProvider = null;
-                return clone;
-            } catch (CloneNotSupportedException e) {
-                //this should never happen
-                throw new InternalError(e);
-            }
+            return (name.hashCode() << 3) ^ locale.hashCode() ^ modulesHash;
         }
 
         String getFormat() {
@@ -845,8 +737,12 @@
                     l = "\"\"";
                 }
             }
-            return "CacheKey[" + name + ", lc=" + l + ", ldr=" + getLoader()
-                + "(format=" + format + ")]";
+            return "CacheKey[" + name +
+                   ", locale=" + l +
+                   ", module=" + getModule() +
+                   ", callerModule=" + getCallerModule() +
+                   ", format=" + format +
+                   "]";
         }
     }
 
@@ -1568,7 +1464,7 @@
                                                 Locale locale,
                                                 Class<?> caller,
                                                 Control control) {
-        return getBundleImpl(baseName, locale, caller, getLoader(caller), control);
+        return getBundleImpl(baseName, locale, caller, caller.getClassLoader(), control);
     }
 
     /**
@@ -1587,26 +1483,25 @@
                                                 Class<?> caller,
                                                 ClassLoader loader,
                                                 Control control) {
-        if (caller != null && caller.getModule().isNamed()) {
-            Module module = caller.getModule();
-            ClassLoader ml = getLoader(module);
-            // get resource bundles for a named module only
-            // if loader is the module's class loader
-            if (loader == ml || (ml == null && loader == RBClassLoader.INSTANCE)) {
-                return getBundleImpl(module, module, loader, baseName, locale, control);
-            }
-        }
-        // find resource bundles from unnamed module
-        Module unnamedModule = loader != null
-            ? loader.getUnnamedModule()
-            : ClassLoader.getSystemClassLoader().getUnnamedModule();
-
         if (caller == null) {
             throw new InternalError("null caller");
         }
+        Module callerModule = caller.getModule();
 
-        Module callerModule = caller.getModule();
-        return getBundleImpl(callerModule, unnamedModule, loader, baseName, locale, control);
+        // get resource bundles for a named module only if loader is the module's class loader
+        if (callerModule.isNamed() && loader == getLoader(callerModule)) {
+            return getBundleImpl(callerModule, callerModule, baseName, locale, control);
+        }
+
+        // find resource bundles from unnamed module of given class loader
+        // Java agent can add to the bootclasspath e.g. via
+        // java.lang.instrument.Instrumentation and load classes in unnamed module.
+        // It may call RB::getBundle that will end up here with loader == null.
+        Module unnamedModule = loader != null
+            ? loader.getUnnamedModule()
+            : BootLoader.getUnnamedModule();
+
+        return getBundleImpl(callerModule, unnamedModule, baseName, locale, control);
     }
 
     private static ResourceBundle getBundleFromModule(Class<?> caller,
@@ -1622,12 +1517,11 @@
                 sm.checkPermission(GET_CLASSLOADER_PERMISSION);
             }
         }
-        return getBundleImpl(callerModule, module, getLoader(module), baseName, locale, control);
+        return getBundleImpl(callerModule, module, baseName, locale, control);
     }
 
     private static ResourceBundle getBundleImpl(Module callerModule,
                                                 Module module,
-                                                ClassLoader loader,
                                                 String baseName,
                                                 Locale locale,
                                                 Control control) {
@@ -1636,10 +1530,10 @@
         }
 
         // We create a CacheKey here for use by this call. The base name
-        // loader, and module will never change during the bundle loading
+        // and modules will never change during the bundle loading
         // process. We have to make sure that the locale is set before
         // using it as a cache key.
-        CacheKey cacheKey = new CacheKey(baseName, locale, loader, module, callerModule);
+        CacheKey cacheKey = new CacheKey(baseName, locale, module, callerModule);
         ResourceBundle bundle = null;
 
         // Quick lookup of the cache.
@@ -1708,6 +1602,11 @@
             bundle = baseBundle;
         }
 
+        // keep callerModule and module reachable for as long as we are operating
+        // with WeakReference(s) to them (in CacheKey)...
+        Reference.reachabilityFence(callerModule);
+        Reference.reachabilityFence(module);
+
         return bundle;
     }
 
@@ -1745,7 +1644,7 @@
         }
 
         // Before we do the real loading work, see whether we need to
-        // do some housekeeping: If references to class loaders or
+        // do some housekeeping: If references to modules or
         // resource bundles have been nulled out, remove all related
         // information from the cache.
         Object ref;
@@ -1781,31 +1680,24 @@
         }
 
         if (bundle != NONEXISTENT_BUNDLE) {
-            CacheKey constKey = (CacheKey) cacheKey.clone();
             trace("findBundle: %d %s %s formats: %s%n", index, candidateLocales, cacheKey, formats);
-            try {
-                if (module.isNamed()) {
-                    bundle = loadBundle(cacheKey, formats, control, module, callerModule);
-                } else {
-                    bundle = loadBundle(cacheKey, formats, control, expiredBundle);
+            if (module.isNamed()) {
+                bundle = loadBundle(cacheKey, formats, control, module, callerModule);
+            } else {
+                bundle = loadBundle(cacheKey, formats, control, expiredBundle);
+            }
+            if (bundle != null) {
+                if (bundle.parent == null) {
+                    bundle.setParent(parent);
                 }
-                if (bundle != null) {
-                    if (bundle.parent == null) {
-                        bundle.setParent(parent);
-                    }
-                    bundle.locale = targetLocale;
-                    bundle = putBundleInCache(cacheKey, bundle, control);
-                    return bundle;
-                }
+                bundle.locale = targetLocale;
+                bundle = putBundleInCache(cacheKey, bundle, control);
+                return bundle;
+            }
 
-                // Put NONEXISTENT_BUNDLE in the cache as a mark that there's no bundle
-                // instance for the locale.
-                putBundleInCache(cacheKey, NONEXISTENT_BUNDLE, control);
-            } finally {
-                if (constKey.getCause() instanceof InterruptedException) {
-                    Thread.currentThread().interrupt();
-                }
-            }
+            // Put NONEXISTENT_BUNDLE in the cache as a mark that there's no bundle
+            // instance for the locale.
+            putBundleInCache(cacheKey, NONEXISTENT_BUNDLE, control);
         }
         return parent;
     }
@@ -1991,12 +1883,20 @@
         // specified by the getFormats() value.
         Locale targetLocale = cacheKey.getLocale();
 
+        Module module = cacheKey.getModule();
+        if (module == null) {
+            // should not happen
+            throw new InternalError(
+                "Module for cache key: " + cacheKey + " has been GCed.");
+        }
+        ClassLoader loader = getLoaderForControl(module);
+
         ResourceBundle bundle = null;
         for (String format : formats) {
             try {
                 // ResourceBundle.Control.newBundle may be overridden
                 bundle = control.newBundle(cacheKey.getName(), targetLocale, format,
-                                           cacheKey.getLoader(), reload);
+                                           loader, reload);
             } catch (LinkageError | Exception error) {
                 // We need to handle the LinkageError case due to
                 // inconsistent case-sensitivity in ClassLoader.
@@ -2138,12 +2038,15 @@
                         if (!bundle.expired && expirationTime >= 0 &&
                             expirationTime <= System.currentTimeMillis()) {
                             try {
-                                bundle.expired = control.needsReload(key.getName(),
-                                                                     key.getLocale(),
-                                                                     key.getFormat(),
-                                                                     key.getLoader(),
-                                                                     bundle,
-                                                                     key.loadTime);
+                                Module module = cacheKey.getModule();
+                                bundle.expired =
+                                    module == null || // already GCed
+                                    control.needsReload(key.getName(),
+                                                        key.getLocale(),
+                                                        key.getFormat(),
+                                                        getLoaderForControl(module),
+                                                        bundle,
+                                                        key.loadTime);
                             } catch (Exception e) {
                                 cacheKey.setCause(e);
                             }
@@ -2185,7 +2088,7 @@
                                                    Control control) {
         setExpirationTime(cacheKey, control);
         if (cacheKey.expirationTime != Control.TTL_DONT_CACHE) {
-            CacheKey key = (CacheKey) cacheKey.clone();
+            CacheKey key = new CacheKey(cacheKey);
             BundleReference bundleRef = new BundleReference(bundle, referenceQueue, key);
             bundle.cacheKey = key;
 
@@ -2231,7 +2134,7 @@
 
     /**
      * Removes all resource bundles from the cache that have been loaded
-     * by the caller's module using the caller's class loader.
+     * by the caller's module.
      *
      * @since 1.6
      * @see ResourceBundle.Control#getTimeToLive(String,Locale)
@@ -2239,47 +2142,29 @@
     @CallerSensitive
     public static final void clearCache() {
         Class<?> caller = Reflection.getCallerClass();
-        clearCache(getLoader(caller), caller.getModule());
+        cacheList.keySet().removeIf(
+            key -> key.getCallerModule() == caller.getModule()
+        );
     }
 
     /**
      * Removes all resource bundles from the cache that have been loaded
-     * by the caller's module using the given class loader.
+     * by the given class loader.
      *
      * @param loader the class loader
      * @exception NullPointerException if <code>loader</code> is null
      * @since 1.6
      * @see ResourceBundle.Control#getTimeToLive(String,Locale)
      */
-    @CallerSensitive
     public static final void clearCache(ClassLoader loader) {
         Objects.requireNonNull(loader);
-        clearCache(loader, Reflection.getCallerClass().getModule());
-    }
-
-    /**
-     * Removes all resource bundles from the cache that have been loaded by the
-     * given {@code module}.
-     *
-     * @param module the module
-     * @throws NullPointerException
-     *         if {@code module} is {@code null}
-     * @throws SecurityException
-     *         if the caller doesn't have the permission to
-     *         {@linkplain Module#getClassLoader() get the class loader}
-     *         of the given {@code module}
-     * @since 9
-     * @see ResourceBundle.Control#getTimeToLive(String,Locale)
-     */
-    public static final void clearCache(Module module) {
-        clearCache(module.getClassLoader(), module);
-    }
-
-    private static void clearCache(ClassLoader loader, Module module) {
-        Set<CacheKey> set = cacheList.keySet();
-        set.stream()
-           .filter((key) -> (key.getLoader() == loader && key.getModule() == module))
-           .forEach(set::remove);
+        cacheList.keySet().removeIf(
+            key -> {
+                Module m;
+                return (m = key.getModule()) != null &&
+                       getLoader(m) == loader;
+            }
+        );
     }
 
     /**
--- a/src/java.base/share/classes/java/util/concurrent/ForkJoinWorkerThread.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinWorkerThread.java	Fri Jan 20 08:53:42 2017 -0800
@@ -185,7 +185,14 @@
     static final class InnocuousForkJoinWorkerThread extends ForkJoinWorkerThread {
         /** The ThreadGroup for all InnocuousForkJoinWorkerThreads */
         private static final ThreadGroup innocuousThreadGroup =
-            ThreadLocalRandom.createThreadGroup("InnocuousForkJoinWorkerThreadGroup");
+                java.security.AccessController.doPrivileged(
+                    new java.security.PrivilegedAction<>() {
+                        public ThreadGroup run() {
+                            ThreadGroup group = Thread.currentThread().getThreadGroup();
+                            for (ThreadGroup p; (p = group.getParent()) != null; )
+                                group = p;
+                            return new ThreadGroup(group, "InnocuousForkJoinWorkerThreadGroup");
+                        }});
 
         /** An AccessControlContext supporting no privileges */
         private static final AccessControlContext INNOCUOUS_ACC =
@@ -215,6 +222,5 @@
         public void setContextClassLoader(ClassLoader cl) {
             throw new SecurityException("setContextClassLoader");
         }
-
     }
 }
--- a/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/java/util/concurrent/ThreadLocalRandom.java	Fri Jan 20 08:53:42 2017 -0800
@@ -985,34 +985,6 @@
         U.putObjectRelease(thread, INHERITEDACCESSCONTROLCONTEXT, acc);
     }
 
-    /**
-     * Returns a new group with the system ThreadGroup (the
-     * topmost, parent-less group) as parent.  Uses Unsafe to
-     * traverse Thread.group and ThreadGroup.parent fields.
-     */
-    static final ThreadGroup createThreadGroup(String name) {
-        if (name == null)
-            throw new NullPointerException();
-        try {
-            long tg = U.objectFieldOffset
-                (Thread.class.getDeclaredField("group"));
-            long gp = U.objectFieldOffset
-                (ThreadGroup.class.getDeclaredField("parent"));
-            ThreadGroup group = (ThreadGroup)
-                U.getObject(Thread.currentThread(), tg);
-            while (group != null) {
-                ThreadGroup parent = (ThreadGroup)U.getObject(group, gp);
-                if (parent == null)
-                    return new ThreadGroup(group, name);
-                group = parent;
-            }
-        } catch (ReflectiveOperationException e) {
-            throw new Error(e);
-        }
-        // fall through if null as cannot-happen safeguard
-        throw new Error("Cannot create ThreadGroup");
-    }
-
     // Serialization support
 
     private static final long serialVersionUID = -5851777807851030925L;
@@ -1087,17 +1059,17 @@
     static {
         try {
             SEED = U.objectFieldOffset
-                (Thread.class.getDeclaredField("threadLocalRandomSeed"));
+                    (Thread.class.getDeclaredField("threadLocalRandomSeed"));
             PROBE = U.objectFieldOffset
-                (Thread.class.getDeclaredField("threadLocalRandomProbe"));
+                    (Thread.class.getDeclaredField("threadLocalRandomProbe"));
             SECONDARY = U.objectFieldOffset
-                (Thread.class.getDeclaredField("threadLocalRandomSecondarySeed"));
+                    (Thread.class.getDeclaredField("threadLocalRandomSecondarySeed"));
             THREADLOCALS = U.objectFieldOffset
-                (Thread.class.getDeclaredField("threadLocals"));
+                    (Thread.class.getDeclaredField("threadLocals"));
             INHERITABLETHREADLOCALS = U.objectFieldOffset
-                (Thread.class.getDeclaredField("inheritableThreadLocals"));
+                    (Thread.class.getDeclaredField("inheritableThreadLocals"));
             INHERITEDACCESSCONTROLCONTEXT = U.objectFieldOffset
-                (Thread.class.getDeclaredField("inheritedAccessControlContext"));
+                    (Thread.class.getDeclaredField("inheritedAccessControlContext"));
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
@@ -1123,7 +1095,7 @@
     // at end of <clinit> to survive static initialization circularity
     static {
         if (java.security.AccessController.doPrivileged(
-            new java.security.PrivilegedAction<Boolean>() {
+            new java.security.PrivilegedAction<>() {
                 public Boolean run() {
                     return Boolean.getBoolean("java.util.secureRandomSeed");
                 }})) {
--- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java	Fri Jan 20 08:53:42 2017 -0800
@@ -40,6 +40,7 @@
 import java.security.AccessController;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
+import java.util.Objects;
 import java.util.function.IntBinaryOperator;
 import java.util.function.IntUnaryOperator;
 import jdk.internal.misc.Unsafe;
@@ -411,7 +412,17 @@
             if (!Modifier.isVolatile(modifiers))
                 throw new IllegalArgumentException("Must be volatile type");
 
-            this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass;
+            // Access to protected field members is restricted to receivers only
+            // of the accessing class, or one of its subclasses, and the
+            // accessing class must in turn be a subclass (or package sibling)
+            // of the protected member's defining class.
+            // If the updater refers to a protected field of a declaring class
+            // outside the current package, the receiver argument will be
+            // narrowed to the type of the accessing class.
+            this.cclass = (Modifier.isProtected(modifiers) &&
+                           tclass.isAssignableFrom(caller) &&
+                           !isSamePackage(tclass, caller))
+                          ? caller : tclass;
             this.tclass = tclass;
             this.offset = U.objectFieldOffset(field);
         }
@@ -433,6 +444,15 @@
         }
 
         /**
+         * Returns true if the two classes have the same class loader and
+         * package qualifier
+         */
+        private static boolean isSamePackage(Class<?> class1, Class<?> class2) {
+            return class1.getClassLoader() == class2.getClassLoader()
+                   && Objects.equals(class1.getPackageName(), class2.getPackageName());
+        }
+
+        /**
          * Checks that target argument is instance of cclass.  On
          * failure, throws cause.
          */
--- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java	Fri Jan 20 08:53:42 2017 -0800
@@ -40,6 +40,7 @@
 import java.security.AccessController;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
+import java.util.Objects;
 import java.util.function.LongBinaryOperator;
 import java.util.function.LongUnaryOperator;
 import jdk.internal.misc.Unsafe;
@@ -409,7 +410,17 @@
             if (!Modifier.isVolatile(modifiers))
                 throw new IllegalArgumentException("Must be volatile type");
 
-            this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass;
+            // Access to protected field members is restricted to receivers only
+            // of the accessing class, or one of its subclasses, and the
+            // accessing class must in turn be a subclass (or package sibling)
+            // of the protected member's defining class.
+            // If the updater refers to a protected field of a declaring class
+            // outside the current package, the receiver argument will be
+            // narrowed to the type of the accessing class.
+            this.cclass = (Modifier.isProtected(modifiers) &&
+                           tclass.isAssignableFrom(caller) &&
+                           !isSamePackage(tclass, caller))
+                          ? caller : tclass;
             this.tclass = tclass;
             this.offset = U.objectFieldOffset(field);
         }
@@ -540,7 +551,17 @@
             if (!Modifier.isVolatile(modifiers))
                 throw new IllegalArgumentException("Must be volatile type");
 
-            this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass;
+            // Access to protected field members is restricted to receivers only
+            // of the accessing class, or one of its subclasses, and the
+            // accessing class must in turn be a subclass (or package sibling)
+            // of the protected member's defining class.
+            // If the updater refers to a protected field of a declaring class
+            // outside the current package, the receiver argument will be
+            // narrowed to the type of the accessing class.
+            this.cclass = (Modifier.isProtected(modifiers) &&
+                           tclass.isAssignableFrom(caller) &&
+                           !isSamePackage(tclass, caller))
+                          ? caller : tclass;
             this.tclass = tclass;
             this.offset = U.objectFieldOffset(field);
         }
@@ -621,4 +642,13 @@
         } while (acl != null);
         return false;
     }
+
+    /**
+     * Returns true if the two classes have the same class loader and
+     * package qualifier
+     */
+    static boolean isSamePackage(Class<?> class1, Class<?> class2) {
+        return class1.getClassLoader() == class2.getClassLoader()
+               && Objects.equals(class1.getPackageName(), class2.getPackageName());
+    }
 }
--- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java	Fri Jan 20 08:53:42 2017 -0800
@@ -40,6 +40,7 @@
 import java.security.AccessController;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
+import java.util.Objects;
 import java.util.function.BinaryOperator;
 import java.util.function.UnaryOperator;
 import jdk.internal.misc.Unsafe;
@@ -351,7 +352,17 @@
             if (!Modifier.isVolatile(modifiers))
                 throw new IllegalArgumentException("Must be volatile type");
 
-            this.cclass = (Modifier.isProtected(modifiers)) ? caller : tclass;
+            // Access to protected field members is restricted to receivers only
+            // of the accessing class, or one of its subclasses, and the
+            // accessing class must in turn be a subclass (or package sibling)
+            // of the protected member's defining class.
+            // If the updater refers to a protected field of a declaring class
+            // outside the current package, the receiver argument will be
+            // narrowed to the type of the accessing class.
+            this.cclass = (Modifier.isProtected(modifiers) &&
+                           tclass.isAssignableFrom(caller) &&
+                           !isSamePackage(tclass, caller))
+                          ? caller : tclass;
             this.tclass = tclass;
             this.vclass = vclass;
             this.offset = U.objectFieldOffset(field);
@@ -374,6 +385,15 @@
         }
 
         /**
+         * Returns true if the two classes have the same class loader and
+         * package qualifier
+         */
+        private static boolean isSamePackage(Class<?> class1, Class<?> class2) {
+            return class1.getClassLoader() == class2.getClassLoader()
+                   && Objects.equals(class1.getPackageName(), class2.getPackageName());
+        }
+
+        /**
          * Checks that target argument is instance of cclass.  On
          * failure, throws cause.
          */
--- a/src/java.base/share/classes/java/util/concurrent/atomic/Striped64.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/java/util/concurrent/atomic/Striped64.java	Fri Jan 20 08:53:42 2017 -0800
@@ -41,7 +41,6 @@
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.function.DoubleBinaryOperator;
 import java.util.function.LongBinaryOperator;
-import jdk.internal.misc.Unsafe;
 
 /**
  * A package-local class holding common representation and mechanics
@@ -191,7 +190,7 @@
      * Duplicated from ThreadLocalRandom because of packaging restrictions.
      */
     static final int getProbe() {
-        return U.getInt(Thread.currentThread(), PROBE);
+        return (int) THREAD_PROBE.get(Thread.currentThread());
     }
 
     /**
@@ -203,7 +202,7 @@
         probe ^= probe << 13;   // xorshift
         probe ^= probe >>> 17;
         probe ^= probe << 5;
-        U.putInt(Thread.currentThread(), PROBE, probe);
+        THREAD_PROBE.set(Thread.currentThread(), probe);
         return probe;
     }
 
@@ -373,18 +372,28 @@
         }
     }
 
-    // Unsafe and VarHandle mechanics
-    private static final Unsafe U = Unsafe.getUnsafe();
+    // VarHandle mechanics
     private static final VarHandle BASE;
     private static final VarHandle CELLSBUSY;
-    private static final long PROBE;
+    private static final VarHandle THREAD_PROBE;
     static {
         try {
             MethodHandles.Lookup l = MethodHandles.lookup();
-            BASE = l.findVarHandle(Striped64.class, "base", long.class);
-            CELLSBUSY = l.findVarHandle(Striped64.class, "cellsBusy", int.class);
-            PROBE = U.objectFieldOffset
-                (Thread.class.getDeclaredField("threadLocalRandomProbe"));
+            BASE = l.findVarHandle(Striped64.class,
+                    "base", long.class);
+            CELLSBUSY = l.findVarHandle(Striped64.class,
+                    "cellsBusy", int.class);
+            l = java.security.AccessController.doPrivileged(
+                    new java.security.PrivilegedAction<>() {
+                        public MethodHandles.Lookup run() {
+                            try {
+                                return MethodHandles.privateLookupIn(Thread.class, MethodHandles.lookup());
+                            } catch (ReflectiveOperationException e) {
+                                throw new Error(e);
+                            }
+                        }});
+            THREAD_PROBE = l.findVarHandle(Thread.class,
+                    "threadLocalRandomProbe", int.class);
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
--- a/src/java.base/share/classes/java/util/concurrent/locks/LockSupport.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/java/util/concurrent/locks/LockSupport.java	Fri Jan 20 08:53:42 2017 -0800
@@ -425,11 +425,11 @@
     static {
         try {
             PARKBLOCKER = U.objectFieldOffset
-                (Thread.class.getDeclaredField("parkBlocker"));
+                    (Thread.class.getDeclaredField("parkBlocker"));
             SECONDARY = U.objectFieldOffset
-                (Thread.class.getDeclaredField("threadLocalRandomSecondarySeed"));
+                    (Thread.class.getDeclaredField("threadLocalRandomSecondarySeed"));
             TID = U.objectFieldOffset
-                (Thread.class.getDeclaredField("tid"));
+                    (Thread.class.getDeclaredField("tid"));
 
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
--- a/src/java.base/share/classes/javax/net/ssl/HandshakeCompletedEvent.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/javax/net/ssl/HandshakeCompletedEvent.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -120,6 +120,9 @@
      * Note: This method can be used only when using certificate-based
      * cipher suites; using it with non-certificate-based cipher suites,
      * such as Kerberos, will throw an SSLPeerUnverifiedException.
+     * <P>
+     * Note: The returned value may not be a valid certificate chain
+     * and should not be relied on for trust decisions.
      *
      * @return an ordered array of the peer certificates,
      *          with the peer's own certificate first followed by
@@ -140,6 +143,9 @@
      * Note: This method can be used only when using certificate-based
      * cipher suites; using it with non-certificate-based cipher suites,
      * such as Kerberos, will throw an SSLPeerUnverifiedException.
+     * <P>
+     * Note: The returned value may not be a valid certificate chain
+     * and should not be relied on for trust decisions.
      *
      * <p><em>Note: this method exists for compatibility with previous
      * releases. New applications should use
--- a/src/java.base/share/classes/javax/net/ssl/HttpsURLConnection.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/javax/net/ssl/HttpsURLConnection.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -104,6 +104,9 @@
      * Note: This method can be used only when using certificate-based
      * cipher suites; using it with non-certificate-based cipher suites,
      * such as Kerberos, will throw an SSLPeerUnverifiedException.
+     * <P>
+     * Note: The returned value may not be a valid certificate chain
+     * and should not be relied on for trust decisions.
      *
      * @return an ordered array of server certificates,
      *          with the peer's own certificate first followed by
--- a/src/java.base/share/classes/javax/net/ssl/SSLSession.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/javax/net/ssl/SSLSession.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -219,6 +219,9 @@
      * Note: This method can be used only when using certificate-based
      * cipher suites; using it with non-certificate-based cipher suites,
      * such as Kerberos, will throw an SSLPeerUnverifiedException.
+     * <P>
+     * Note: The returned value may not be a valid certificate chain
+     * and should not be relied on for trust decisions.
      *
      * @return an ordered array of peer certificates,
      *          with the peer's own certificate first followed by any
@@ -259,6 +262,9 @@
      * Note: This method can be used only when using certificate-based
      * cipher suites; using it with non-certificate-based cipher suites,
      * such as Kerberos, will throw an SSLPeerUnverifiedException.
+     * <P>
+     * Note: The returned value may not be a valid certificate chain
+     * and should not be relied on for trust decisions.
      *
      * <p><em>Note: this method exists for compatibility with previous
      * releases. New applications should use
--- a/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java	Fri Jan 20 08:53:42 2017 -0800
@@ -38,6 +38,7 @@
 import java.net.URLConnection;
 import java.net.URLStreamHandler;
 import java.net.URLStreamHandlerFactory;
+import java.security.AccessControlContext;
 import java.security.AccessControlException;
 import java.security.AccessController;
 import java.security.CodeSigner;
@@ -83,6 +84,7 @@
     private static final String JAVA_VERSION;
     private static final boolean DEBUG;
     private static final boolean DISABLE_JAR_CHECKING;
+    private static final boolean DISABLE_ACC_CHECKING;
 
     static {
         Properties props = GetPropertyAction.privilegedGetProperties();
@@ -90,6 +92,9 @@
         DEBUG = (props.getProperty("sun.misc.URLClassPath.debug") != null);
         String p = props.getProperty("sun.misc.URLClassPath.disableJarChecking");
         DISABLE_JAR_CHECKING = p != null ? p.equals("true") || p.equals("") : false;
+
+        p = props.getProperty("jdk.net.URLClassPath.disableRestrictedPermissions");
+        DISABLE_ACC_CHECKING = p != null ? p.equals("true") || p.equals("") : false;
     }
 
     /* The original search path of URLs. */
@@ -110,6 +115,11 @@
     /* Whether this URLClassLoader has been closed yet */
     private boolean closed = false;
 
+    /* The context to be used when loading classes and resources.  If non-null
+     * this is the context that was captured during the creation of the
+     * URLClassLoader. null implies no additional security restrictions. */
+    private final AccessControlContext acc;
+
     /**
      * Creates a new URLClassPath for the given URLs. The URLs will be
      * searched in the order specified for classes and resources. A URL
@@ -119,8 +129,12 @@
      * @param urls the directory and JAR file URLs to search for classes
      *        and resources
      * @param factory the URLStreamHandlerFactory to use when creating new URLs
+     * @param acc the context to be used when loading classes and resources, may
+     *            be null
      */
-    public URLClassPath(URL[] urls, URLStreamHandlerFactory factory) {
+    public URLClassPath(URL[] urls,
+                        URLStreamHandlerFactory factory,
+                        AccessControlContext acc) {
         for (int i = 0; i < urls.length; i++) {
             path.add(urls[i]);
         }
@@ -128,10 +142,22 @@
         if (factory != null) {
             jarHandler = factory.createURLStreamHandler("jar");
         }
+        if (DISABLE_ACC_CHECKING)
+            this.acc = null;
+        else
+            this.acc = acc;
     }
 
+    /**
+     * Constructs a URLClassPath with no additional security restrictions.
+     * Used by code that implements the class path.
+     */
     public URLClassPath(URL[] urls) {
-        this(urls, null);
+        this(urls, null, null);
+    }
+
+    public URLClassPath(URL[] urls, AccessControlContext acc) {
+        this(urls, null, acc);
     }
 
     public synchronized List<IOException> closeLoaders() {
@@ -356,6 +382,14 @@
             } catch (IOException e) {
                 // Silently ignore for now...
                 continue;
+            } catch (SecurityException se) {
+                // Always silently ignore. The context, if there is one, that
+                // this URLClassPath was given during construction will never
+                // have permission to access the URL.
+                if (DEBUG) {
+                    System.err.println("Failed to access " + url + ", " + se );
+                }
+                continue;
             }
             // Finally, add the Loader to the search path.
             loaders.add(loader);
@@ -378,7 +412,7 @@
                             && file != null && (file.indexOf("!/") == file.length() - 2)) {
                         // extract the nested URL
                         URL nestedUrl = new URL(file.substring(0, file.length() - 2));
-                        return new JarLoader(nestedUrl, jarHandler, lmap);
+                        return new JarLoader(nestedUrl, jarHandler, lmap, acc);
                     } else if (file != null && file.endsWith("/")) {
                         if ("file".equals(protocol)) {
                             return new FileLoader(url);
@@ -386,10 +420,10 @@
                             return new Loader(url);
                         }
                     } else {
-                        return new JarLoader(url, jarHandler, lmap);
+                        return new JarLoader(url, jarHandler, lmap, acc);
                     }
                 }
-            });
+            }, acc);
         } catch (java.security.PrivilegedActionException pae) {
             throw (IOException)pae.getException();
         }
@@ -585,10 +619,11 @@
      */
     static class JarLoader extends Loader {
         private JarFile jar;
-        private URL csu;
+        private final URL csu;
         private JarIndex index;
         private URLStreamHandler handler;
-        private HashMap<String, Loader> lmap;
+        private final HashMap<String, Loader> lmap;
+        private final AccessControlContext acc;
         private boolean closed = false;
         private static final JavaUtilZipFileAccess zipAccess =
                 SharedSecrets.getJavaUtilZipFileAccess();
@@ -598,13 +633,15 @@
          * a JAR file.
          */
         JarLoader(URL url, URLStreamHandler jarHandler,
-                  HashMap<String, Loader> loaderMap)
+                  HashMap<String, Loader> loaderMap,
+                  AccessControlContext acc)
             throws IOException
         {
             super(new URL("jar", "", -1, url + "!/", jarHandler));
             csu = url;
             handler = jarHandler;
             lmap = loaderMap;
+            this.acc = acc;
 
             ensureOpen();
         }
@@ -663,8 +700,7 @@
                                 }
                                 return null;
                             }
-                        }
-                    );
+                        }, acc);
                 } catch (java.security.PrivilegedActionException pae) {
                     throw (IOException)pae.getException();
                 }
@@ -859,9 +895,9 @@
                                 new PrivilegedExceptionAction<>() {
                                     public JarLoader run() throws IOException {
                                         return new JarLoader(url, handler,
-                                            lmap);
+                                            lmap, acc);
                                     }
-                                });
+                                }, acc);
 
                             /* this newly opened jar file has its own index,
                              * merge it into the parent's index, taking into
--- a/src/java.base/share/classes/jdk/internal/util/jar/JarIndex.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/jdk/internal/util/jar/JarIndex.java	Fri Jan 20 08:53:42 2017 -0800
@@ -29,6 +29,7 @@
 import java.util.*;
 import java.util.jar.*;
 import java.util.zip.*;
+import static sun.security.action.GetPropertyAction.privilegedGetProperty;
 
 /**
  * This class is used to maintain mappings from packages, classes
@@ -72,7 +73,7 @@
      * be added to the index. Otherwise, just the directory names are added.
      */
     private static final boolean metaInfFilenames =
-        "true".equals(System.getProperty("sun.misc.JarIndex.metaInfFilenames"));
+        "true".equals(privilegedGetProperty("sun.misc.JarIndex.metaInfFilenames"));
 
     /**
      * Constructs a new, empty jar index.
--- a/src/java.base/share/classes/module-info.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/module-info.java	Fri Jan 20 08:53:42 2017 -0800
@@ -249,7 +249,6 @@
         jdk.crypto.token;
     exports sun.security.jca to
         java.smartcardio,
-        java.xml.crypto,
         jdk.crypto.ec,
         jdk.crypto.token,
         jdk.naming.dns;
@@ -279,6 +278,7 @@
         java.security.jgss,
         java.security.sasl,
         java.smartcardio,
+        java.xml.crypto,
         jdk.crypto.ec,
         jdk.crypto.token,
         jdk.jartool,
@@ -290,6 +290,8 @@
         jdk.crypto.token,
         jdk.jartool,
         jdk.security.auth;
+    exports sun.security.validator to
+        jdk.jartool;
     exports sun.text.resources to
         jdk.localedata;
     exports sun.util.cldr to
--- a/src/java.base/share/classes/sun/reflect/misc/ReflectUtil.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/sun/reflect/misc/ReflectUtil.java	Fri Jan 20 08:53:42 2017 -0800
@@ -96,7 +96,7 @@
 
         final Class<?> declaringClass = m.getDeclaringClass();
 
-        checkPackageAccess(declaringClass);
+        privateCheckPackageAccess(sm, declaringClass);
 
         if (Modifier.isPublic(m.getModifiers()) &&
                 Modifier.isPublic(declaringClass.getModifiers()))
@@ -114,9 +114,27 @@
      * also check the package access on the proxy interfaces.
      */
     public static void checkPackageAccess(Class<?> clazz) {
-        checkPackageAccess(clazz.getName());
+        SecurityManager s = System.getSecurityManager();
+        if (s != null) {
+            privateCheckPackageAccess(s, clazz);
+        }
+    }
+
+    /**
+     * NOTE: should only be called if a SecurityManager is installed
+     */
+    private static void privateCheckPackageAccess(SecurityManager s, Class<?> clazz) {
+        while (clazz.isArray()) {
+            clazz = clazz.getComponentType();
+        }
+
+        String pkg = clazz.getPackageName();
+        if (pkg != null && !pkg.isEmpty()) {
+            s.checkPackageAccess(pkg);
+        }
+
         if (isNonPublicProxyClass(clazz)) {
-            checkProxyPackageAccess(clazz);
+            privateCheckProxyPackageAccess(s, clazz);
         }
     }
 
@@ -195,15 +213,21 @@
     public static void checkProxyPackageAccess(Class<?> clazz) {
         SecurityManager s = System.getSecurityManager();
         if (s != null) {
-            // check proxy interfaces if the given class is a proxy class
-            if (Proxy.isProxyClass(clazz)) {
-                for (Class<?> intf : clazz.getInterfaces()) {
-                    checkPackageAccess(intf);
-                }
+            privateCheckProxyPackageAccess(s, clazz);
+        }
+    }
+
+    /**
+     * NOTE: should only be called if a SecurityManager is installed
+     */
+    private static void privateCheckProxyPackageAccess(SecurityManager s, Class<?> clazz) {
+        // check proxy interfaces if the given class is a proxy class
+        if (Proxy.isProxyClass(clazz)) {
+            for (Class<?> intf : clazz.getInterfaces()) {
+                privateCheckPackageAccess(s, intf);
             }
         }
     }
-
     /**
      * Access check on the interfaces that a proxy class implements and throw
      * {@code SecurityException} if it accesses a restricted package from
@@ -220,7 +244,7 @@
             for (Class<?> intf : interfaces) {
                 ClassLoader cl = intf.getClassLoader();
                 if (needsPackageAccessCheck(ccl, cl)) {
-                    checkPackageAccess(intf);
+                    privateCheckPackageAccess(sm, intf);
                 }
             }
         }
@@ -236,10 +260,11 @@
      * package that bypasses checkPackageAccess.
      */
     public static boolean isNonPublicProxyClass(Class<?> cls) {
-        String name = cls.getName();
-        int i = name.lastIndexOf('.');
-        String pkg = (i != -1) ? name.substring(0, i) : "";
-        return Proxy.isProxyClass(cls) && !pkg.startsWith(PROXY_PACKAGE);
+        if (!Proxy.isProxyClass(cls)) {
+            return false;
+        }
+        String pkg = cls.getPackageName();
+        return pkg == null || !pkg.startsWith(PROXY_PACKAGE);
     }
 
     /**
@@ -255,7 +280,7 @@
         // check if it is a valid proxy instance
         if (proxy == null || !Proxy.isProxyClass(proxy.getClass())) {
             throw new IllegalArgumentException("Not a Proxy instance");
-}
+        }
         if (Modifier.isStatic(method.getModifiers())) {
             throw new IllegalArgumentException("Can't handle static method");
         }
--- a/src/java.base/share/classes/sun/security/provider/DSA.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/sun/security/provider/DSA.java	Fri Jan 20 08:53:42 2017 -0800
@@ -322,19 +322,20 @@
         } else {
             // first decode the signature.
             try {
-                DerInputStream in = new DerInputStream(signature, offset,
-                                                       length);
+                // Enforce strict DER checking for signatures
+                DerInputStream in =
+                    new DerInputStream(signature, offset, length, false);
                 DerValue[] values = in.getSequence(2);
 
+                // check number of components in the read sequence
+                // and trailing data
+                if ((values.length != 2) || (in.available() != 0)) {
+                    throw new IOException("Invalid encoding for signature");
+                }
                 r = values[0].getBigInteger();
                 s = values[1].getBigInteger();
-
-                // Check for trailing signature data
-                if (in.available() != 0) {
-                    throw new IOException("Incorrect signature length");
-                }
             } catch (IOException e) {
-                throw new SignatureException("invalid encoding for signature");
+                throw new SignatureException("Invalid encoding for signature", e);
             }
         }
 
@@ -427,13 +428,49 @@
         return t5.mod(q);
     }
 
-    // NOTE: This following impl is defined in FIPS 186-4 AppendixB.2.1.
     protected BigInteger generateK(BigInteger q) {
+        // Implementation defined in FIPS 186-4 AppendixB.2.1.
         SecureRandom random = getSigningRandom();
         byte[] kValue = new byte[(q.bitLength() + 7)/8 + 8];
 
         random.nextBytes(kValue);
-        return new BigInteger(1, kValue).mod(q.subtract(BigInteger.ONE)).add(BigInteger.ONE);
+        BigInteger k = new BigInteger(1, kValue).mod(
+                q.subtract(BigInteger.ONE)).add(BigInteger.ONE);
+
+        // Using an equivalent exponent of fixed length (same as q or 1 bit
+        // less than q) to keep the kG timing relatively constant.
+        //
+        // Note that this is an extra step on top of the approach defined in
+        // FIPS 186-4 AppendixB.2.1 so as to make a fixed length K.
+        k = k.add(q).divide(BigInteger.TWO);
+
+        // An alternative implementation based on FIPS 186-4 AppendixB2.2
+        // with fixed-length K.
+        //
+        // Please keep it here as we may need to switch to it in the future.
+        //
+        // SecureRandom random = getSigningRandom();
+        // byte[] kValue = new byte[(q.bitLength() + 7)/8];
+        // BigInteger d = q.subtract(BigInteger.TWO);
+        // BigInteger k;
+        // do {
+        //     random.nextBytes(kValue);
+        //     BigInteger c = new BigInteger(1, kValue);
+        //     if (c.compareTo(d) <= 0) {
+        //         k = c.add(BigInteger.ONE);
+        //         // Using an equivalent exponent of fixed length to keep
+        //         // the g^k timing relatively constant.
+        //         //
+        //         // Note that this is an extra step on top of the approach
+        //         // defined in FIPS 186-4 AppendixB.2.2 so as to make a
+        //         // fixed length K.
+        //         if (k.bitLength() >= q.bitLength()) {
+        //             break;
+        //         }
+        //     }
+        // } while (true);
+
+        return k;
     }
 
     // Use the application-specified SecureRandom Object if provided.
--- a/src/java.base/share/classes/sun/security/rsa/RSASignature.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/sun/security/rsa/RSASignature.java	Fri Jan 20 08:53:42 2017 -0800
@@ -226,9 +226,10 @@
      * Decode the signature data. Verify that the object identifier matches
      * and return the message digest.
      */
-    public static byte[] decodeSignature(ObjectIdentifier oid, byte[] signature)
+    public static byte[] decodeSignature(ObjectIdentifier oid, byte[] sig)
             throws IOException {
-        DerInputStream in = new DerInputStream(signature);
+        // Enforce strict DER checking for signatures
+        DerInputStream in = new DerInputStream(sig, 0, sig.length, false);
         DerValue[] values = in.getSequence(2);
         if ((values.length != 2) || (in.available() != 0)) {
             throw new IOException("SEQUENCE length error");
--- a/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java	Fri Jan 20 08:53:42 2017 -0800
@@ -673,8 +673,11 @@
             } else {
                 // we wanted to resume, but the server refused
                 //
-                // Invalidate the session in case of reusing next time.
-                session.invalidate();
+                // Invalidate the session for initial handshake in case
+                // of reusing next time.
+                if (isInitialHandshake) {
+                    session.invalidate();
+                }
                 session = null;
                 if (!enableNewSession) {
                     throw new SSLException("New session creation is disabled");
--- a/src/java.base/share/classes/sun/security/ssl/X509KeyManagerImpl.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/sun/security/ssl/X509KeyManagerImpl.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 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
@@ -818,6 +818,11 @@
             checker.init(false);
         } catch (CertPathValidatorException cpve) {
             // unlikely to happen
+            if (useDebug) {
+                debug.println(
+                    "Cannot initialize algorithm constraints checker: " + cpve);
+            }
+
             return false;
         }
 
@@ -828,6 +833,11 @@
                 // We don't care about the unresolved critical extensions.
                 checker.check(cert, Collections.<String>emptySet());
             } catch (CertPathValidatorException cpve) {
+                if (useDebug) {
+                    debug.println("Certificate (" + cert +
+                        ") does not conform to algorithm constraints: " + cpve);
+                }
+
                 return false;
             }
         }
--- a/src/java.base/share/classes/sun/security/util/DerInputBuffer.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/sun/security/util/DerInputBuffer.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -147,6 +147,11 @@
         System.arraycopy(buf, pos, bytes, 0, len);
         skip(len);
 
+        // check to make sure no extra leading 0s for DER
+        if (len >= 2 && (bytes[0] == 0) && (bytes[1] >= 0)) {
+            throw new IOException("Invalid encoding: redundant leading 0s");
+        }
+
         if (makePositive) {
             return new BigInteger(1, bytes);
         } else {
--- a/src/java.base/share/classes/sun/security/util/DerInputStream.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/sun/security/util/DerInputStream.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -77,7 +77,7 @@
      * @param data the buffer from which to create the string (CONSUMED)
      */
     public DerInputStream(byte[] data) throws IOException {
-        init(data, 0, data.length);
+        init(data, 0, data.length, true);
     }
 
     /**
@@ -92,23 +92,48 @@
      *          starting at "offset"
      */
     public DerInputStream(byte[] data, int offset, int len) throws IOException {
-        init(data, offset, len);
+        init(data, offset, len, true);
+    }
+
+    /**
+     * Create a DER input stream from part of a data buffer with
+     * additional arg to indicate whether to allow constructed
+     * indefinite-length encoding.
+     * The buffer is not copied, it is shared.  Accordingly, the
+     * buffer should be treated as read-only.
+     *
+     * @param data the buffer from which to create the string (CONSUMED)
+     * @param offset the first index of <em>data</em> which will
+     *          be read as DER input in the new stream
+     * @param len how long a chunk of the buffer to use,
+     *          starting at "offset"
+     * @param allowIndefiniteLength whether to allow constructed
+     *          indefinite-length encoding
+     */
+    public DerInputStream(byte[] data, int offset, int len,
+        boolean allowIndefiniteLength) throws IOException {
+        init(data, offset, len, allowIndefiniteLength);
     }
 
     /*
      * private helper routine
      */
-    private void init(byte[] data, int offset, int len) throws IOException {
+    private void init(byte[] data, int offset, int len,
+        boolean allowIndefiniteLength) throws IOException {
         if ((offset+2 > data.length) || (offset+len > data.length)) {
             throw new IOException("Encoding bytes too short");
         }
         // check for indefinite length encoding
         if (DerIndefLenConverter.isIndefinite(data[offset+1])) {
-            byte[] inData = new byte[len];
-            System.arraycopy(data, offset, inData, 0, len);
+            if (!allowIndefiniteLength) {
+                throw new IOException("Indefinite length BER encoding found");
+            } else {
+                byte[] inData = new byte[len];
+                System.arraycopy(data, offset, inData, 0, len);
 
-            DerIndefLenConverter derIn = new DerIndefLenConverter();
-            buffer = new DerInputBuffer(derIn.convert(inData));
+                DerIndefLenConverter derIn = new DerIndefLenConverter();
+                buffer = new DerInputBuffer(derIn.convert(inData));
+            }
         } else
             buffer = new DerInputBuffer(data, offset, len);
         buffer.mark(Integer.MAX_VALUE);
@@ -239,15 +264,19 @@
          * representation.
          */
         length--;
-        int validBits = length*8 - buffer.read();
+        int excessBits = buffer.read();
+        if (excessBits < 0) {
+            throw new IOException("Unused bits of bit string invalid");
+        }
+        int validBits = length*8 - excessBits;
         if (validBits < 0) {
-            throw new IOException("valid bits of bit string invalid");
+            throw new IOException("Valid bits of bit string invalid");
         }
 
         byte[] repn = new byte[length];
 
         if ((length != 0) && (buffer.read(repn) != length)) {
-            throw new IOException("short read of DER bit string");
+            throw new IOException("Short read of DER bit string");
         }
 
         return new BitArray(validBits, repn);
@@ -263,7 +292,7 @@
         int length = getDefiniteLength(buffer);
         byte[] retval = new byte[length];
         if ((length != 0) && (buffer.read(retval) != length))
-            throw new IOException("short read of DER octet string");
+            throw new IOException("Short read of DER octet string");
 
         return retval;
     }
@@ -273,7 +302,7 @@
      */
     public void getBytes(byte[] val) throws IOException {
         if ((val.length != 0) && (buffer.read(val) != val.length)) {
-            throw new IOException("short read of DER octet string");
+            throw new IOException("Short read of DER octet string");
         }
     }
 
@@ -357,7 +386,7 @@
         DerInputStream  newstr;
 
         byte lenByte = (byte)buffer.read();
-        int len = getLength((lenByte & 0xff), buffer);
+        int len = getLength(lenByte, buffer);
 
         if (len == -1) {
            // indefinite length encoding found
@@ -403,7 +432,7 @@
         } while (newstr.available() > 0);
 
         if (newstr.available() != 0)
-            throw new IOException("extra data at end of vector");
+            throw new IOException("Extra data at end of vector");
 
         /*
          * Now stick them into the array we're returning.
@@ -494,7 +523,7 @@
         int length = getDefiniteLength(buffer);
         byte[] retval = new byte[length];
         if ((length != 0) && (buffer.read(retval) != length))
-            throw new IOException("short read of DER " +
+            throw new IOException("Short read of DER " +
                                   stringName + " string");
 
         return new String(retval, enc);
@@ -555,7 +584,11 @@
      */
     static int getLength(int lenByte, InputStream in) throws IOException {
         int value, tmp;
+        if (lenByte == -1) {
+            throw new IOException("Short read of DER length");
+        }
 
+        String mdName = "DerInputStream.getLength(): ";
         tmp = lenByte;
         if ((tmp & 0x080) == 0x00) { // short form, 1 byte datum
             value = tmp;
@@ -569,17 +602,23 @@
             if (tmp == 0)
                 return -1;
             if (tmp < 0 || tmp > 4)
-                throw new IOException("DerInputStream.getLength(): lengthTag="
-                    + tmp + ", "
+                throw new IOException(mdName + "lengthTag=" + tmp + ", "
                     + ((tmp < 0) ? "incorrect DER encoding." : "too big."));
 
-            for (value = 0; tmp > 0; tmp --) {
+            value = 0x0ff & in.read();
+            tmp--;
+            if (value == 0) {
+                // DER requires length value be encoded in minimum number of bytes
+                throw new IOException(mdName + "Redundant length bytes found");
+            }
+            while (tmp-- > 0) {
                 value <<= 8;
                 value += 0x0ff & in.read();
             }
             if (value < 0) {
-                throw new IOException("DerInputStream.getLength(): "
-                        + "Invalid length bytes");
+                throw new IOException(mdName + "Invalid length bytes");
+            } else if (value <= 127) {
+                throw new IOException(mdName + "Should use short form for length");
             }
         }
         return value;
--- a/src/java.base/share/classes/sun/security/util/DerValue.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/sun/security/util/DerValue.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 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
@@ -248,7 +248,7 @@
 
         tag = (byte)in.read();
         byte lenByte = (byte)in.read();
-        length = DerInputStream.getLength((lenByte & 0xff), in);
+        length = DerInputStream.getLength(lenByte, in);
         if (length == -1) {  // indefinite length encoding found
             DerInputBuffer inbuf = in.dup();
             int readLen = inbuf.available();
@@ -361,7 +361,7 @@
 
         tag = (byte)in.read();
         byte lenByte = (byte)in.read();
-        length = DerInputStream.getLength((lenByte & 0xff), in);
+        length = DerInputStream.getLength(lenByte, in);
         if (length == -1) { // indefinite length encoding found
             int readLen = in.available();
             int offset = 2;     // for tag and length bytes
--- a/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java	Fri Jan 20 08:53:42 2017 -0800
@@ -255,7 +255,13 @@
                 + " (tag = " +  type_id + ")"
                 );
 
-        encoding = new byte[in.getDefiniteLength()];
+        int len = in.getDefiniteLength();
+        if (len > in.available()) {
+            throw new IOException("ObjectIdentifier() -- length exceeds" +
+                    "data available.  Length: " + len + ", Available: " +
+                    in.available());
+        }
+        encoding = new byte[len];
         in.getBytes(encoding);
         check(encoding);
     }
--- a/src/java.base/share/conf/security/java.security	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/conf/security/java.security	Fri Jan 20 08:53:42 2017 -0800
@@ -298,111 +298,24 @@
 
 #
 # List of comma-separated packages that start with or equal this string
-# will cause a security exception to be thrown when
-# passed to checkPackageAccess unless the
-# corresponding RuntimePermission ("accessClassInPackage."+package) has
-# been granted.
-package.access=sun.,\
-               com.sun.xml.internal.,\
-               com.sun.imageio.,\
-               com.sun.istack.internal.,\
-               com.sun.jmx.,\
-               com.sun.media.sound.,\
-               com.sun.naming.internal.,\
-               com.sun.proxy.,\
-               com.sun.corba.se.,\
-               com.sun.org.apache.bcel.internal.,\
-               com.sun.org.apache.regexp.internal.,\
-               com.sun.org.apache.xerces.internal.,\
-               com.sun.org.apache.xpath.internal.,\
-               com.sun.org.apache.xalan.internal.extensions.,\
-               com.sun.org.apache.xalan.internal.lib.,\
-               com.sun.org.apache.xalan.internal.res.,\
-               com.sun.org.apache.xalan.internal.templates.,\
-               com.sun.org.apache.xalan.internal.utils.,\
-               com.sun.org.apache.xalan.internal.xslt.,\
-               com.sun.org.apache.xalan.internal.xsltc.cmdline.,\
-               com.sun.org.apache.xalan.internal.xsltc.compiler.,\
-               com.sun.org.apache.xalan.internal.xsltc.trax.,\
-               com.sun.org.apache.xalan.internal.xsltc.util.,\
-               com.sun.org.apache.xml.internal.res.,\
-               com.sun.org.apache.xml.internal.security.,\
-               com.sun.org.apache.xml.internal.serializer.dom3.,\
-               com.sun.org.apache.xml.internal.serializer.utils.,\
-               com.sun.org.apache.xml.internal.utils.,\
-               com.sun.org.glassfish.,\
-               com.sun.tools.script.,\
-               com.oracle.xmlns.internal.,\
-               com.oracle.webservices.internal.,\
-               org.jcp.xml.dsig.internal.,\
-               jdk.internal.,\
-               jdk.nashorn.internal.,\
-               jdk.nashorn.tools.,\
-               jdk.tools.jimage.,\
-               com.sun.activation.registries.,\
-               com.sun.java.accessibility.util.internal.,\
-#ifdef windows
-               com.sun.java.accessibility.internal.,\
-#endif
-#ifdef macosx
-               apple.,\
-#endif
+# will cause a security exception to be thrown when passed to the
+# SecurityManager::checkPackageAccess method unless the corresponding
+# RuntimePermission("accessClassInPackage."+package) has been granted.
+#
+package.access=sun.misc.,\
+               sun.reflect.,\
 
 #
 # List of comma-separated packages that start with or equal this string
-# will cause a security exception to be thrown when
-# passed to checkPackageDefinition unless the
-# corresponding RuntimePermission ("defineClassInPackage."+package) has
-# been granted.
+# will cause a security exception to be thrown when passed to the
+# SecurityManager::checkPackageDefinition method unless the corresponding
+# RuntimePermission("defineClassInPackage."+package) has been granted.
 #
-# by default, none of the class loaders supplied with the JDK call
+# By default, none of the class loaders supplied with the JDK call
 # checkPackageDefinition.
 #
-package.definition=sun.,\
-                   com.sun.xml.internal.,\
-                   com.sun.imageio.,\
-                   com.sun.istack.internal.,\
-                   com.sun.jmx.,\
-                   com.sun.media.sound.,\
-                   com.sun.naming.internal.,\
-                   com.sun.proxy.,\
-                   com.sun.corba.se.,\
-                   com.sun.org.apache.bcel.internal.,\
-                   com.sun.org.apache.regexp.internal.,\
-                   com.sun.org.apache.xerces.internal.,\
-                   com.sun.org.apache.xpath.internal.,\
-                   com.sun.org.apache.xalan.internal.extensions.,\
-                   com.sun.org.apache.xalan.internal.lib.,\
-                   com.sun.org.apache.xalan.internal.res.,\
-                   com.sun.org.apache.xalan.internal.templates.,\
-                   com.sun.org.apache.xalan.internal.utils.,\
-                   com.sun.org.apache.xalan.internal.xslt.,\
-                   com.sun.org.apache.xalan.internal.xsltc.cmdline.,\
-                   com.sun.org.apache.xalan.internal.xsltc.compiler.,\
-                   com.sun.org.apache.xalan.internal.xsltc.trax.,\
-                   com.sun.org.apache.xalan.internal.xsltc.util.,\
-                   com.sun.org.apache.xml.internal.res.,\
-                   com.sun.org.apache.xml.internal.security.,\
-                   com.sun.org.apache.xml.internal.serializer.dom3.,\
-                   com.sun.org.apache.xml.internal.serializer.utils.,\
-                   com.sun.org.apache.xml.internal.utils.,\
-                   com.sun.org.glassfish.,\
-                   com.sun.tools.script.,\
-                   com.oracle.xmlns.internal.,\
-                   com.oracle.webservices.internal.,\
-                   org.jcp.xml.dsig.internal.,\
-                   jdk.internal.,\
-                   jdk.nashorn.internal.,\
-                   jdk.nashorn.tools.,\
-                   jdk.tools.jimage.,\
-                   com.sun.activation.registries.,\
-                   com.sun.java.accessibility.util.internal.,\
-#ifdef windows
-                   com.sun.java.accessibility.internal.,\
-#endif
-#ifdef macosx
-                   apple.,\
-#endif
+package.definition=sun.misc.,\
+                   sun.reflect.,\
 
 #
 # Determines whether this properties file can be appended to
@@ -658,6 +571,36 @@
 jdk.certpath.disabledAlgorithms=MD2, MD5, SHA1 jdkCA & denyAfter 2017-01-01, \
     RSA keySize < 1024, DSA keySize < 1024, EC keySize < 224
 
+#
+# RMI Registry Serial Filter
+#
+# The filter pattern uses the same format as jdk.serialFilter.
+# This filter can override the builtin filter if additional types need to be
+# allowed or rejected from the RMI Registry.
+#
+# Note: This property is currently used by the JDK Reference implementation.
+# It is not guaranteed to be examined and used by other implementations.
+#
+#sun.rmi.registry.registryFilter=pattern;pattern
+#
+# RMI Distributed Garbage Collector (DGC) Serial Filter
+#
+# The filter pattern uses the same format as jdk.serialFilter.
+# This filter can override the builtin filter if additional types need to be
+# allowed or rejected from the RMI DGC.
+#
+# Note: This property is currently used by the JDK Reference implementation.
+# It is not guaranteed to be examined and used by other implementations.
+#
+# The builtin DGC filter can approximately be represented as the filter pattern:
+#
+#sun.rmi.transport.dgcFilter=\
+#    java.rmi.server.ObjID;\
+#    java.rmi.server.UID;\
+#    java.rmi.dgc.VMID;\
+#    java.rmi.dgc.Lease;\
+#    maxdepth=5;maxarray=10000
+
 # Algorithm restrictions for signed JAR files
 #
 # In some environments, certain algorithms or key lengths may be undesirable
@@ -720,7 +663,7 @@
 # Note: The algorithm restrictions do not apply to trust anchors or
 # self-signed certificates.
 #
-# Note: This property is currently used by Oracle's JSSE implementation.
+# Note: This property is currently used by the JDK Reference implementation.
 # It is not guaranteed to be examined and used by other implementations.
 #
 # Example:
@@ -740,7 +683,7 @@
 # During SSL/TLS security parameters negotiation, legacy algorithms will
 # not be negotiated unless there are no other candidates.
 #
-# The syntax of the disabled algorithm string is described as this Java
+# The syntax of the legacy algorithms string is described as this Java
 # BNF-style:
 #   LegacyAlgorithms:
 #       " LegacyAlgorithm { , LegacyAlgorithm } "
@@ -776,7 +719,7 @@
 # javax.net.ssl.SSLParameters.setAlgorithmConstraints()),
 # then the algorithm is completely disabled and will not be negotiated.
 #
-# Note: This property is currently used by Oracle's JSSE implementation.
+# Note: This property is currently used by the JDK Reference implementation.
 # It is not guaranteed to be examined and used by other implementations.
 # There is no guarantee the property will continue to exist or be of the
 # same syntax in future releases.
@@ -789,7 +732,8 @@
         DHE_DSS_EXPORT, DHE_RSA_EXPORT, DH_anon_EXPORT, DH_DSS_EXPORT, \
         DH_RSA_EXPORT, RSA_EXPORT, \
         DH_anon, ECDH_anon, \
-        RC4_128, RC4_40, DES_CBC, DES40_CBC
+        RC4_128, RC4_40, DES_CBC, DES40_CBC, \
+        3DES_EDE_CBC
 
 # The pre-defined default finite field Diffie-Hellman ephemeral (DHE)
 # parameters for Transport Layer Security (SSL/TLS/DTLS) processing.
@@ -912,7 +856,7 @@
 #       Constraint {"," Constraint }
 #   Constraint:
 #       AlgConstraint | MaxTransformsConstraint | MaxReferencesConstraint |
-#       ReferenceUriSchemeConstraint | OtherConstraint
+#       ReferenceUriSchemeConstraint | KeySizeConstraint | OtherConstraint
 #   AlgConstraint
 #       "disallowAlg" Uri
 #   MaxTransformsConstraint:
@@ -921,12 +865,16 @@
 #       "maxReferences" Integer
 #   ReferenceUriSchemeConstraint:
 #       "disallowReferenceUriSchemes" String { String }
+#   KeySizeConstraint:
+#       "minKeySize" KeyAlg Integer
 #   OtherConstraint:
 #       "noDuplicateIds" | "noRetrievalMethodLoops"
 #
 # For AlgConstraint, Uri is the algorithm URI String that is not allowed.
 # See the XML Signature Recommendation for more information on algorithm
-# URI Identifiers. If the MaxTransformsConstraint or MaxReferencesConstraint is
+# URI Identifiers. For KeySizeConstraint, KeyAlg is the standard algorithm
+# name of the key type (ex: "RSA"). If the MaxTransformsConstraint,
+# MaxReferencesConstraint or KeySizeConstraint (for the same key type) is
 # specified more than once, only the last entry is enforced.
 #
 # Note: This property is currently used by the JDK Reference implementation. It
@@ -940,6 +888,8 @@
     maxTransforms 5,\
     maxReferences 30,\
     disallowReferenceUriSchemes file http https,\
+    minKeySize RSA 1024,\
+    minKeySize DSA 1024,\
     noDuplicateIds,\
     noRetrievalMethodLoops
 
--- a/src/java.base/share/lib/security/default.policy	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/share/lib/security/default.policy	Fri Jan 20 08:53:42 2017 -0800
@@ -81,6 +81,8 @@
 };
 
 grant codeBase "jrt:/java.xml.crypto" {
+    permission java.lang.RuntimePermission
+                   "accessClassInPackage.sun.security.util";
     permission java.util.PropertyPermission "*", "read";
     permission java.security.SecurityPermission "putProviderProperty.XMLDSig";
     permission java.security.SecurityPermission
@@ -91,10 +93,20 @@
                    "com.sun.org.apache.xml.internal.security.register";
     permission java.security.SecurityPermission
                    "getProperty.jdk.xml.dsig.secureValidationPolicy";
+    permission java.lang.RuntimePermission
+                   "accessClassInPackage.com.sun.org.apache.xml.internal.*";
+    permission java.lang.RuntimePermission
+                   "accessClassInPackage.com.sun.org.apache.xpath.internal";
+    permission java.lang.RuntimePermission
+                   "accessClassInPackage.com.sun.org.apache.xpath.internal.*";
 };
 
 grant codeBase "jrt:/java.xml.ws" {
     permission java.lang.RuntimePermission
+                   "accessClassInPackage.com.sun.org.apache.xml.internal.resolver";
+    permission java.lang.RuntimePermission
+                   "accessClassInPackage.com.sun.org.apache.xml.internal.resolver.tools";
+    permission java.lang.RuntimePermission
                    "accessClassInPackage.com.sun.xml.internal.*";
     permission java.lang.RuntimePermission
                    "accessClassInPackage.com.sun.istack.internal";
@@ -186,3 +198,10 @@
     permission java.util.PropertyPermission "os.name", "read";
 };
 
+grant codeBase "jrt:/jdk.accessibility" {
+    permission java.lang.RuntimePermission "accessClassInPackage.sun.awt";
+};
+
+grant codeBase "jrt:/jdk.desktop" {
+    permission java.lang.RuntimePermission "accessClassInPackage.com.sun.awt";
+};
--- a/src/java.base/unix/native/libnet/SocketOutputStream.c	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/unix/native/libnet/SocketOutputStream.c	Fri Jan 20 08:53:42 2017 -0800
@@ -98,27 +98,31 @@
         int llen = chunkLen;
         (*env)->GetByteArrayRegion(env, data, off, chunkLen, (jbyte *)bufP);
 
-        while(llen > 0) {
-            int n = NET_Send(fd, bufP + loff, llen, 0);
-            if (n > 0) {
-                llen -= n;
-                loff += n;
-                continue;
+        if ((*env)->ExceptionCheck(env)) {
+            break;
+        } else {
+            while(llen > 0) {
+                int n = NET_Send(fd, bufP + loff, llen, 0);
+                if (n > 0) {
+                    llen -= n;
+                    loff += n;
+                    continue;
+                }
+                if (errno == ECONNRESET) {
+                    JNU_ThrowByName(env, "sun/net/ConnectionResetException",
+                        "Connection reset");
+                } else {
+                    JNU_ThrowByNameWithMessageAndLastError
+                        (env, "java/net/SocketException", "Write failed");
+                }
+                if (bufP != BUF) {
+                    free(bufP);
+                }
+                return;
             }
-            if (errno == ECONNRESET) {
-                JNU_ThrowByName(env, "sun/net/ConnectionResetException",
-                    "Connection reset");
-            } else {
-                JNU_ThrowByNameWithMessageAndLastError
-                    (env, "java/net/SocketException", "Write failed");
-            }
-            if (bufP != BUF) {
-                free(bufP);
-            }
-            return;
+            len -= chunkLen;
+            off += chunkLen;
         }
-        len -= chunkLen;
-        off += chunkLen;
     }
 
     if (bufP != BUF) {
--- a/src/java.base/windows/native/libnet/SocketOutputStream.c	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/windows/native/libnet/SocketOutputStream.c	Fri Jan 20 08:53:42 2017 -0800
@@ -92,66 +92,69 @@
         int retry = 0;
 
         (*env)->GetByteArrayRegion(env, data, off, chunkLen, (jbyte *)bufP);
-
-        while(llen > 0) {
-            int n = send(fd, bufP + loff, llen, 0);
-            if (n > 0) {
-                llen -= n;
-                loff += n;
-                continue;
-            }
-
-            /*
-             * Due to a bug in Windows Sockets (observed on NT and Windows
-             * 2000) it may be necessary to retry the send. The issue is that
-             * on blocking sockets send/WSASend is supposed to block if there
-             * is insufficient buffer space available. If there are a large
-             * number of threads blocked on write due to congestion then it's
-             * possile to hit the NT/2000 bug whereby send returns WSAENOBUFS.
-             * The workaround we use is to retry the send. If we have a
-             * large buffer to send (>2k) then we retry with a maximum of
-             * 2k buffer. If we hit the issue with <=2k buffer then we backoff
-             * for 1 second and retry again. We repeat this up to a reasonable
-             * limit before bailing out and throwing an exception. In load
-             * conditions we've observed that the send will succeed after 2-3
-             * attempts but this depends on network buffers associated with
-             * other sockets draining.
-             */
-            if (WSAGetLastError() == WSAENOBUFS) {
-                if (llen > MAX_BUFFER_LEN) {
-                    buflen = MAX_BUFFER_LEN;
-                    chunkLen = MAX_BUFFER_LEN;
-                    llen = MAX_BUFFER_LEN;
+        if ((*env)->ExceptionCheck(env)) {
+            break;
+        } else {
+            while(llen > 0) {
+                int n = send(fd, bufP + loff, llen, 0);
+                if (n > 0) {
+                    llen -= n;
+                    loff += n;
                     continue;
                 }
-                if (retry >= 30) {
-                    JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
-                        "No buffer space available - exhausted attempts to queue buffer");
-                    if (bufP != BUF) {
-                        free(bufP);
+
+                /*
+                 * Due to a bug in Windows Sockets (observed on NT and Windows
+                 * 2000) it may be necessary to retry the send. The issue is that
+                 * on blocking sockets send/WSASend is supposed to block if there
+                 * is insufficient buffer space available. If there are a large
+                 * number of threads blocked on write due to congestion then it's
+                 * possile to hit the NT/2000 bug whereby send returns WSAENOBUFS.
+                 * The workaround we use is to retry the send. If we have a
+                 * large buffer to send (>2k) then we retry with a maximum of
+                 * 2k buffer. If we hit the issue with <=2k buffer then we backoff
+                 * for 1 second and retry again. We repeat this up to a reasonable
+                 * limit before bailing out and throwing an exception. In load
+                 * conditions we've observed that the send will succeed after 2-3
+                 * attempts but this depends on network buffers associated with
+                 * other sockets draining.
+                 */
+                if (WSAGetLastError() == WSAENOBUFS) {
+                    if (llen > MAX_BUFFER_LEN) {
+                        buflen = MAX_BUFFER_LEN;
+                        chunkLen = MAX_BUFFER_LEN;
+                        llen = MAX_BUFFER_LEN;
+                        continue;
                     }
-                    return;
+                    if (retry >= 30) {
+                        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+                            "No buffer space available - exhausted attempts to queue buffer");
+                        if (bufP != BUF) {
+                            free(bufP);
+                        }
+                        return;
+                    }
+                    Sleep(1000);
+                    retry++;
+                    continue;
                 }
-                Sleep(1000);
-                retry++;
-                continue;
+
+                /*
+                 * Send failed - can be caused by close or write error.
+                 */
+                if (WSAGetLastError() == WSAENOTSOCK) {
+                    JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
+                } else {
+                    NET_ThrowCurrent(env, "socket write error");
+                }
+                if (bufP != BUF) {
+                    free(bufP);
+                }
+                return;
             }
-
-            /*
-             * Send failed - can be caused by close or write error.
-             */
-            if (WSAGetLastError() == WSAENOTSOCK) {
-                JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
-            } else {
-                NET_ThrowCurrent(env, "socket write error");
-            }
-            if (bufP != BUF) {
-                free(bufP);
-            }
-            return;
+            len -= chunkLen;
+            off += chunkLen;
         }
-        len -= chunkLen;
-        off += chunkLen;
     }
 
     if (bufP != BUF) {
--- a/src/java.base/windows/native/libnio/ch/WindowsSelectorImpl.c	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.base/windows/native/libnio/ch/WindowsSelectorImpl.c	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,7 @@
 
 #define FD_SETSIZE 1024
 
+#include <limits.h>
 #include <stdlib.h>
 #include <winsock2.h>
 
@@ -75,8 +76,18 @@
         tv = NULL;
     } else {
         tv = &timevalue;
-        tv->tv_sec =  (long)(timeout / 1000);
-        tv->tv_usec = (long)((timeout % 1000) * 1000);
+        jlong sec = timeout / 1000;
+        //
+        // struct timeval members are signed 32-bit integers so the
+        // signed 64-bit jlong needs to be clamped
+        //
+        if (sec > INT_MAX) {
+            tv->tv_sec  = INT_MAX;
+            tv->tv_usec = 0;
+        } else {
+            tv->tv_sec  = (long)sec;
+            tv->tv_usec = (long)((timeout % 1000) * 1000);
+        }
     }
 
     /* Set FD_SET structures required for select */
--- a/src/java.desktop/macosx/classes/com/apple/eawt/_AppMenuBarHandler.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.desktop/macosx/classes/com/apple/eawt/_AppMenuBarHandler.java	Fri Jan 20 08:53:42 2017 -0800
@@ -123,7 +123,7 @@
         }
 
         // grab the pointer to the CMenuBar, and retain it in native
-        nativeSetDefaultMenuBar(((CMenuBar)peer).getModel());
+        ((CMenuBar) peer).execute(_AppMenuBarHandler::nativeSetDefaultMenuBar);
     }
 
     void setAboutMenuItemVisible(final boolean present) {
--- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CCheckboxMenuItem.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CCheckboxMenuItem.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,29 +26,28 @@
 package sun.lwawt.macosx;
 
 import java.awt.CheckboxMenuItem;
-import java.awt.EventQueue;
 import java.awt.event.ItemEvent;
 import java.awt.peer.CheckboxMenuItemPeer;
 
 import sun.awt.SunToolkit;
 
 public class CCheckboxMenuItem extends CMenuItem implements CheckboxMenuItemPeer {
-    boolean fAutoToggle = true;
-    boolean fIsIndeterminate = false;
+    volatile boolean fAutoToggle = true;
+    volatile boolean fIsIndeterminate = false;
 
     private native void nativeSetState(long modelPtr, boolean state);
     private native void nativeSetIsCheckbox(long modelPtr);
 
-    CCheckboxMenuItem(CheckboxMenuItem target) {
+    CCheckboxMenuItem(final CheckboxMenuItem target) {
         super(target);
-        nativeSetIsCheckbox(getModel());
+        execute(this::nativeSetIsCheckbox);
         setState(target.getState());
     }
 
     // MenuItemPeer implementation
     @Override
-    public void setState(boolean state) {
-        nativeSetState(getModel(), state);
+    public void setState(final boolean state) {
+        execute(ptr -> nativeSetState(ptr, state));
     }
 
     public void handleAction(final boolean state) {
--- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CFRetainedResource.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CFRetainedResource.java	Fri Jan 20 08:53:42 2017 -0800
@@ -23,7 +23,6 @@
  * questions.
  */
 
-
 package sun.lwawt.macosx;
 
 /**
@@ -34,6 +33,7 @@
     private static native void nativeCFRelease(final long ptr, final boolean disposeOnAppKitThread);
 
     private final boolean disposeOnAppKitThread;
+    // TODO this pointer should be private and accessed via CFNativeAction class
     protected volatile long ptr;
 
     /**
@@ -70,8 +70,72 @@
         nativeCFRelease(oldPtr, disposeOnAppKitThread); // perform outside of the synchronized block
     }
 
+    /**
+     * The interface which allows to execute some native operations with
+     * assumption that the native pointer will be valid till the end.
+     */
+    public interface CFNativeAction {
+
+        /**
+         * The native operation should be called from this method.
+         *
+         * @param  ptr the pointer to the native data
+         */
+        void run(long ptr);
+    }
+
+    /**
+     * The interface which allows to execute some native operations and get a
+     * result with assumption that the native pointer will be valid till the
+     * end.
+     */
+    interface CFNativeActionGet {
+
+        /**
+         * The native operation should be called from this method.
+         *
+         * @param  ptr the pointer to the native data
+         * @return result of the native operation
+         */
+        long run(long ptr);
+    }
+
+    /**
+     * This is utility method which should be used instead of the direct access
+     * to the {@link #ptr}, because this method guaranteed that the pointer will
+     * not be zero and will be valid till the end of the operation.It is highly
+     * recomended to not use any external lock in action. If the current
+     * {@link #ptr} is {@code 0} then action will be ignored.
+     *
+     * @param  action The native operation
+     */
+    public final synchronized void execute(final CFNativeAction action) {
+        if (ptr != 0) {
+            action.run(ptr);
+        }
+    }
+
+    /**
+     * This is utility method which should be used instead of the direct access
+     * to the {@link #ptr}, because this method guaranteed that the pointer will
+     * not be zero and will be valid till the end of the operation. It is highly
+     * recomended to not use any external lock in action. If the current
+     * {@link #ptr} is {@code 0} then action will be ignored and {@code} is
+     * returned.
+     *
+     * @param  action the native operation
+     * @return result of the native operation, usually the native pointer to
+     *         some other data
+     */
+    final synchronized long executeGet(final CFNativeActionGet action) {
+        if (ptr != 0) {
+            return action.run(ptr);
+        }
+        return 0;
+    }
+
     @Override
-    protected void finalize() throws Throwable {
+    protected final void finalize() throws Throwable {
         dispose();
     }
 }
--- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CMenu.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CMenu.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -25,7 +25,9 @@
 
 package sun.lwawt.macosx;
 
-import java.awt.*;
+import java.awt.Menu;
+import java.awt.MenuBar;
+import java.awt.MenuItem;
 import java.awt.peer.MenuItemPeer;
 import java.awt.peer.MenuPeer;
 
@@ -37,7 +39,7 @@
 
     // This way we avoiding invocation of the setters twice
     @Override
-    protected void initialize(MenuItem target) {
+    protected final void initialize(MenuItem target) {
         setLabel(target.getLabel());
         setEnabled(target.isEnabled());
     }
@@ -57,52 +59,50 @@
     }
 
     @Override
-    protected long createModel() {
+    long createModel() {
         CMenuComponent parent = (CMenuComponent)
             LWCToolkit.targetToPeer(getTarget().getParent());
 
-        if (parent instanceof CMenu ||
-            parent instanceof CPopupMenu)
-        {
-            return nativeCreateSubMenu(parent.getModel());
-        } else if (parent instanceof CMenuBar) {
+        if (parent instanceof CMenu) {
+            return parent.executeGet(this::nativeCreateSubMenu);
+        }
+        if (parent instanceof CMenuBar) {
             MenuBar parentContainer = (MenuBar)getTarget().getParent();
             boolean isHelpMenu = parentContainer.getHelpMenu() == getTarget();
             int insertionLocation = ((CMenuBar)parent).getNextInsertionIndex();
-            return nativeCreateMenu(parent.getModel(),
-                                    isHelpMenu, insertionLocation);
-        } else {
-            throw new InternalError("Parent must be CMenu or CMenuBar");
+            return parent.executeGet(ptr -> nativeCreateMenu(ptr, isHelpMenu,
+                                                             insertionLocation));
         }
+        throw new InternalError("Parent must be CMenu or CMenuBar");
     }
 
     @Override
-    public void addItem(MenuItem item) {
+    public final void addItem(MenuItem item) {
         // Nothing to do here -- we added it when we created the
         // menu item's peer.
     }
 
     @Override
-    public void delItem(int index) {
-        nativeDeleteItem(getModel(), index);
+    public final void delItem(final int index) {
+        execute(ptr -> nativeDeleteItem(ptr, index));
     }
 
     @Override
-    public void setLabel(String label) {
-        nativeSetMenuTitle(getModel(), label);
+    public final void setLabel(final String label) {
+        execute(ptr->nativeSetMenuTitle(ptr, label));
         super.setLabel(label);
     }
 
     // Note that addSeparator is never called directly from java.awt.Menu,
     // though it is required in the MenuPeer interface.
     @Override
-    public void addSeparator() {
-        nativeAddSeparator(getModel());
+    public final void addSeparator() {
+        execute(this::nativeAddSeparator);
     }
 
     // Used by ScreenMenuBar to get to the native menu for event handling.
-    public long getNativeMenu() {
-        return nativeGetNSMenu(getModel());
+    public final long getNativeMenu() {
+        return executeGet(this::nativeGetNSMenu);
     }
 
     private native long nativeCreateMenu(long parentMenuPtr,
--- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CMenuBar.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CMenuBar.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,7 @@
 
 import sun.awt.AWTAccessor;
 
-public class CMenuBar extends CMenuComponent implements MenuBarPeer {
+public final class CMenuBar extends CMenuComponent implements MenuBarPeer {
 
     private int nextInsertionIndex = -1;
 
@@ -40,14 +40,15 @@
     }
 
     @Override
-    protected long createModel() {
+    long createModel() {
         return nativeCreateMenuBar();
     }
 
     @Override
-    public void addHelpMenu(Menu m) {
-        CMenu cMenu = AWTAccessor.getMenuComponentAccessor().getPeer(m);
-        nativeSetHelpMenu(getModel(), cMenu.getModel());
+    public void addHelpMenu(final Menu m) {
+        final CMenu cMenu = AWTAccessor.getMenuComponentAccessor().getPeer(m);
+        execute(parentPtr -> cMenu.execute(
+                menuPtr -> nativeSetHelpMenu(parentPtr, menuPtr)));
     }
 
     public int getNextInsertionIndex() {
@@ -65,8 +66,8 @@
     }
 
     @Override
-    public void delMenu(int index) {
-        nativeDelMenu(getModel(), index);
+    public void delMenu(final int index) {
+        execute(ptr -> nativeDelMenu(ptr, index));
     }
 
     private native long nativeCreateMenuBar();
--- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CMenuComponent.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CMenuComponent.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -29,36 +29,32 @@
 import java.awt.MenuComponent;
 import java.awt.peer.MenuComponentPeer;
 
-public abstract class CMenuComponent implements MenuComponentPeer {
+abstract class CMenuComponent extends CFRetainedResource
+        implements MenuComponentPeer {
 
-    private MenuComponent target;
-    private long modelPtr;
+    private final MenuComponent target;
 
-    CMenuComponent(MenuComponent target) {
+    CMenuComponent(final MenuComponent target) {
+        super(0, true);
         this.target = target;
-        this.modelPtr = createModel();
+        setPtr(createModel());
     }
 
-    MenuComponent getTarget() {
+    final MenuComponent getTarget() {
         return target;
     }
 
-    public long getModel() {
-        return modelPtr;
+    abstract long createModel();
+
+    @Override
+    public final void dispose() {
+        super.dispose();
+        LWCToolkit.targetDisposedPeer(target, this);
     }
 
-    protected abstract long createModel();
-
-    public void dispose() {
-        LWCToolkit.targetDisposedPeer(target, this);
-        nativeDispose(modelPtr);
-        target = null;
-    }
-
-    private native void nativeDispose(long modelPtr);
-
     // 1.5 peer method
-    public void setFont(Font f) {
+    @Override
+    public final void setFont(final Font f) {
         // no-op, as we don't currently support menu fonts
         // c.f. radar 4032912
     }
--- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CMenuItem.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CMenuItem.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -25,16 +25,17 @@
 
 package sun.lwawt.macosx;
 
+import java.awt.MenuItem;
+import java.awt.MenuShortcut;
+import java.awt.event.ActionEvent;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.awt.peer.MenuItemPeer;
+import java.util.concurrent.atomic.AtomicBoolean;
+
 import sun.awt.SunToolkit;
 import sun.lwawt.LWToolkit;
 
-import java.awt.MenuContainer;
-import java.awt.MenuItem;
-import java.awt.MenuShortcut;
-import java.awt.event.*;
-import java.awt.peer.MenuItemPeer;
-import java.util.concurrent.atomic.AtomicBoolean;
-
 public class CMenuItem extends CMenuComponent implements MenuItemPeer {
 
     private final AtomicBoolean enabled = new AtomicBoolean(true);
@@ -58,9 +59,9 @@
     }
 
     @Override
-    protected long createModel() {
+    long createModel() {
         CMenuComponent parent = (CMenuComponent)LWToolkit.targetToPeer(getTarget().getParent());
-        return nativeCreate(parent.getModel(), isSeparator());
+        return parent.executeGet(ptr->nativeCreate(ptr, isSeparator()));
     }
 
     public void setLabel(String label, char keyChar, int keyCode, int modifiers) {
@@ -90,7 +91,12 @@
             keyChar = 0;
         }
 
-        nativeSetLabel(getModel(), label, keyChar, keyCode, keyMask);
+        final String finalLabel = label;
+        final char finalKeyChar = keyChar;
+        final int finalKeyCode = keyCode;
+        final int finalKeyMask = keyMask;
+        execute(ptr -> nativeSetLabel(ptr, finalLabel, finalKeyChar,
+                                      finalKeyCode, finalKeyMask));
     }
 
     @Override
@@ -105,16 +111,16 @@
      * There isn't a need to expose this except in a instanceof because
      * it isn't defined in the peer api.
      */
-    public void setImage(java.awt.Image img) {
+    public final void setImage(final java.awt.Image img) {
         CImage cimg = CImage.getCreator().createFromImage(img);
-        nativeSetImage(getModel(), cimg == null ? 0L : cimg.ptr);
+        execute(ptr -> nativeSetImage(ptr, cimg == null ? 0L : cimg.ptr));
     }
 
     /**
      * New API for tooltips
      */
-    public void setToolTipText(String text) {
-        nativeSetTooltip(getModel(), text);
+    public final void setToolTipText(final String text) {
+        execute(ptr -> nativeSetTooltip(ptr, text));
     }
 
 //    @Override
@@ -138,7 +144,8 @@
             b &= ((CMenuItem) parent).isEnabled();
         }
         if (enabled.compareAndSet(!b, b)) {
-            nativeSetEnabled(getModel(), b);
+            final boolean finalB = b;
+            execute(ptr->nativeSetEnabled(ptr, finalB));
         }
     }
 
--- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java	Fri Jan 20 08:53:42 2017 -0800
@@ -449,7 +449,7 @@
         final long nsWindowPtr = getNSWindowPtr();
         CMenuBar mbPeer = (CMenuBar)LWToolkit.targetToPeer(mb);
         if (mbPeer != null) {
-            nativeSetNSWindowMenuBar(nsWindowPtr, mbPeer.getModel());
+            mbPeer.execute(ptr -> nativeSetNSWindowMenuBar(nsWindowPtr, ptr));
         } else {
             nativeSetNSWindowMenuBar(nsWindowPtr, 0);
         }
--- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPopupMenu.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPopupMenu.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -25,18 +25,20 @@
 
 package sun.lwawt.macosx;
 
-import java.awt.*;
+import java.awt.Component;
+import java.awt.Event;
+import java.awt.Point;
+import java.awt.PopupMenu;
 import java.awt.peer.PopupMenuPeer;
 
-import sun.lwawt.LWWindowPeer;
+final class CPopupMenu extends CMenu implements PopupMenuPeer {
 
-public class CPopupMenu extends CMenu implements PopupMenuPeer {
     CPopupMenu(PopupMenu target) {
         super(target);
     }
 
     @Override
-    protected long createModel() {
+    long createModel() {
         return nativeCreatePopupMenu();
     }
 
@@ -50,7 +52,7 @@
             Point loc = origin.getLocationOnScreen();
             e.x += loc.x;
             e.y += loc.y;
-            nativeShowPopupMenu(getModel(), e.x, e.y);
+            execute(ptr -> nativeShowPopupMenu(ptr, e.x, e.y));
         }
     }
 }
--- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTrayIcon.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CTrayIcon.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -118,7 +118,10 @@
             }
         }
 
-        return checkAndCreatePopupPeer().getModel();
+        // This method is executed on Appkit, so if ptr is not zero means that,
+        // it is still not deallocated(even if we call NSApp postRunnableEvent)
+        // and sent CFRelease to the native queue
+        return checkAndCreatePopupPeer().ptr;
     }
 
     /**
--- a/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenu.m	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenu.m	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -38,7 +38,7 @@
 - (id)initWithPeer:(jobject)peer {
 AWT_ASSERT_APPKIT_THREAD;
     // Create the new NSMenu
-    self = [super initWithPeer:peer asSeparator:[NSNumber numberWithBool:NO]];
+    self = [super initWithPeer:peer asSeparator:NO];
     if (self) {
         fMenu = [NSMenu javaMenuWithTitle:@""];
         [fMenu retain];
@@ -133,14 +133,13 @@
 
 CMenu * createCMenu (jobject cPeerObjGlobal) {
 
-    CMenu *aCMenu = nil;
+    __block CMenu *aCMenu = nil;
 
-    // We use an array here only to be able to get a return value
-    NSMutableArray *args = [[NSMutableArray alloc] initWithObjects:[NSValue valueWithBytes:&cPeerObjGlobal objCType:@encode(jobject)], nil];
+    [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
 
-    [ThreadUtilities performOnMainThread:@selector(_create_OnAppKitThread:) on:[CMenu alloc] withObject:args waitUntilDone:YES];
-
-    aCMenu = (CMenu *)[args objectAtIndex: 0];
+        aCMenu = [[CMenu alloc] initWithPeer:cPeerObjGlobal];
+        // the aCMenu is released in CMenuComponent.dispose()
+    }];
 
     if (aCMenu == nil) {
         return 0L;
--- a/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuBar.m	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuBar.m	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -383,27 +383,20 @@
 Java_sun_lwawt_macosx_CMenuBar_nativeCreateMenuBar
     (JNIEnv *env, jobject peer)
 {
-    CMenuBar *aCMenuBar = nil;
+    __block CMenuBar *aCMenuBar = nil;
     JNF_COCOA_ENTER(env);
 
     jobject cPeerObjGlobal = (*env)->NewGlobalRef(env, peer);
 
-    // We use an array here only to be able to get a return value
-    NSMutableArray *args = [[NSMutableArray alloc] initWithObjects:[NSValue valueWithBytes:&cPeerObjGlobal objCType:@encode(jobject)], nil];
+    [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
 
-    [ThreadUtilities performOnMainThread:@selector(_create_OnAppKitThread:) on:[CMenuBar alloc] withObject:args waitUntilDone:YES];
-
-    aCMenuBar = (CMenuBar *)[args objectAtIndex: 0];
-
+        aCMenuBar = [[CMenuBar alloc] initWithPeer:cPeerObjGlobal];
+        // the aCMenuBar is released in CMenuComponent.dispose()
+    }];
     if (aCMenuBar == nil) {
         return 0L;
     }
 
-    // [args release];
-
-    // A strange memory managment after that.
-
-
     JNF_COCOA_EXIT(env);
     return ptr_to_jlong(aCMenuBar);
 }
--- a/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuComponent.m	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuComponent.m	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -41,45 +41,11 @@
     return self;
 }
 
--(void) cleanup {
-    // Used by subclasses
-}
-
--(void) disposer {
+- (void)dealloc {
     JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
     JNFDeleteGlobalRef(env, fPeer);
     fPeer = NULL;
 
-    [self cleanup];
-    [self release];
+    [super dealloc];
 }
-
-// The method is used by all subclasses, since the process of the creation
-// is the same. The only exception is the CMenuItem class.
-- (void) _create_OnAppKitThread: (NSMutableArray *)argValue {
-    jobject cPeerObjGlobal = (jobject)[[argValue objectAtIndex: 0] pointerValue];
-    CMenuItem *aCMenuItem = [self initWithPeer:cPeerObjGlobal];
-    [argValue removeAllObjects];
-    [argValue addObject: aCMenuItem];
-}
-
 @end
-
-/*
- * Class:     sun_lwawt_macosx_CMenuComponent
- * Method:    nativeDispose
- * Signature: (J)V
- */
-JNIEXPORT void JNICALL
-Java_sun_lwawt_macosx_CMenuComponent_nativeDispose
-(JNIEnv *env, jobject peer, jlong menuItemObj)
-{
-JNF_COCOA_ENTER(env);
-
-    [ThreadUtilities performOnMainThread:@selector(disposer)
-                                      on:((id)jlong_to_ptr(menuItemObj))
-                              withObject:nil
-                           waitUntilDone:NO];
-
-JNF_COCOA_EXIT(env);
-}
--- a/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuItem.h	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuItem.h	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -32,7 +32,7 @@
 }
 
 // Setup
-- (id) initWithPeer:(jobject)peer asSeparator: (NSNumber *) asSeparator;
+- (id) initWithPeer:(jobject)peer asSeparator: (BOOL) asSeparator;
 - (void) setIsCheckbox;
 
 // Events
--- a/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuItem.m	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/CMenuItem.m	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -39,11 +39,11 @@
 
 @implementation CMenuItem
 
-- (id) initWithPeer:(jobject)peer asSeparator: (NSNumber *) asSeparator{
+- (id) initWithPeer:(jobject)peer asSeparator: (BOOL) asSeparator{
     AWT_ASSERT_APPKIT_THREAD;
     self = [super initWithPeer:peer];
     if (self) {
-        if ([asSeparator boolValue]) {
+        if (asSeparator) {
             fMenuItem = (NSMenuItem*)[NSMenuItem separatorItem];
             [fMenuItem retain];
         } else {
@@ -204,12 +204,9 @@
     }];
 }
 
-- (void)cleanup {
+- (void)dealloc {
     [fMenuItem setAction:NULL];
     [fMenuItem setTarget:nil];
-}
-
-- (void)dealloc {
     [fMenuItem release];
     fMenuItem = nil;
     
@@ -228,14 +225,6 @@
     fIsCheckbox = YES;
 }
 
-- (void) _createMenuItem_OnAppKitThread: (NSMutableArray *)argValue {
-    jobject cPeerObjGlobal = (jobject)[[argValue objectAtIndex: 0] pointerValue];
-    NSNumber * asSeparator = (NSNumber *)[argValue objectAtIndex: 1];
-    CMenuItem *aCMenuItem = [self initWithPeer: cPeerObjGlobal asSeparator: asSeparator];
-    [argValue removeAllObjects];
-    [argValue addObject: aCMenuItem];
-}
-
 - (NSString *)description {
     return [NSString stringWithFormat:@"CMenuItem[ %@ ]", fMenuItem];
 }
@@ -397,24 +386,18 @@
 (JNIEnv *env, jobject peer, jlong parentCMenuObj, jboolean isSeparator)
 {
     
-    CMenuItem *aCMenuItem = nil;
+    __block CMenuItem *aCMenuItem = nil;
+    BOOL asSeparator = (isSeparator == JNI_TRUE) ? YES: NO;
     CMenu *parentCMenu = (CMenu *)jlong_to_ptr(parentCMenuObj);
     JNF_COCOA_ENTER(env);
     
     jobject cPeerObjGlobal = (*env)->NewGlobalRef(env, peer);
-    
-    NSMutableArray *args = nil;
-    
-    // Create a new item....
-    if (isSeparator == JNI_TRUE) {
-        args = [[NSMutableArray alloc] initWithObjects:[NSValue valueWithBytes:&cPeerObjGlobal objCType:@encode(jobject)], [NSNumber numberWithBool:YES],  nil];
-    } else {
-        args = [[NSMutableArray alloc] initWithObjects:[NSValue valueWithBytes:&cPeerObjGlobal objCType:@encode(jobject)], [NSNumber numberWithBool:NO],  nil];
-    }
-    
-    [ThreadUtilities performOnMainThread:@selector(_createMenuItem_OnAppKitThread:) on:[CMenuItem alloc] withObject:args waitUntilDone:YES];
-    
-    aCMenuItem = (CMenuItem *)[args objectAtIndex: 0];
+
+    [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
+        aCMenuItem = [[CMenuItem alloc] initWithPeer: cPeerObjGlobal
+                                         asSeparator: asSeparator];
+        // the CMenuItem is released in CMenuComponent.dispose()
+    }];
     
     if (aCMenuItem == nil) {
         return 0L;
--- a/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java	Fri Jan 20 08:53:42 2017 -0800
@@ -735,7 +735,11 @@
                     parse_iCCP_chunk(chunkLength);
                     break;
                 case iTXt_TYPE:
-                    parse_iTXt_chunk(chunkLength);
+                    if (ignoreMetadata) {
+                        stream.skipBytes(chunkLength);
+                    } else {
+                        parse_iTXt_chunk(chunkLength);
+                    }
                     break;
                 case pHYs_TYPE:
                     parse_pHYs_chunk();
@@ -759,7 +763,11 @@
                     parse_tRNS_chunk(chunkLength);
                     break;
                 case zTXt_TYPE:
-                    parse_zTXt_chunk(chunkLength);
+                    if (ignoreMetadata) {
+                        stream.skipBytes(chunkLength);
+                    } else {
+                        parse_zTXt_chunk(chunkLength);
+                    }
                     break;
                 default:
                     // Read an unknown chunk
--- a/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp	Fri Jan 20 08:53:42 2017 -0800
@@ -99,7 +99,6 @@
 HWND AwtComponent::sm_focusOwner = NULL;
 HWND AwtComponent::sm_focusedWindow = NULL;
 BOOL AwtComponent::sm_bMenuLoop = FALSE;
-AwtComponent* AwtComponent::sm_getComponentCache = NULL;
 BOOL AwtComponent::sm_inSynthesizeFocus = FALSE;
 
 /************************************************************************/
@@ -276,10 +275,6 @@
      * handle.
      */
     DestroyHWnd();
-
-    if (sm_getComponentCache == this) {
-        sm_getComponentCache = NULL;
-    }
 }
 
 void AwtComponent::Dispose()
@@ -352,9 +347,6 @@
     if (hWnd == AwtToolkit::GetInstance().GetHWnd()) {
         return NULL;
     }
-    if (sm_getComponentCache && sm_getComponentCache->GetHWnd() == hWnd) {
-        return sm_getComponentCache;
-    }
 
     // check that it's an AWT component from the same toolkit as the caller
     if (::IsWindow(hWnd) &&
@@ -362,7 +354,7 @@
     {
         DASSERT(WmAwtIsComponent != 0);
         if (::SendMessage(hWnd, WmAwtIsComponent, 0, 0L)) {
-            return sm_getComponentCache = GetComponentImpl(hWnd);
+            return GetComponentImpl(hWnd);
         }
     }
     return NULL;
--- a/src/java.logging/share/classes/java/util/logging/Level.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.logging/share/classes/java/util/logging/Level.java	Fri Jan 20 08:53:42 2017 -0800
@@ -692,11 +692,14 @@
                     Level levelObject = ref.get();
                     if (levelObject == null) continue;
                     Level other = ref.mirroredLevel;
+                    Class<? extends Level> type = levelObject.getClass();
                     if (l.value == other.value &&
                            (l.resourceBundleName == other.resourceBundleName ||
                                (l.resourceBundleName != null &&
                                 l.resourceBundleName.equals(other.resourceBundleName)))) {
-                        return Optional.of(levelObject);
+                        if (type == l.getClass()) {
+                            return Optional.of(levelObject);
+                        }
                     }
                 }
             }
--- a/src/java.logging/share/classes/java/util/logging/LogRecord.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.logging/share/classes/java/util/logging/LogRecord.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -619,13 +619,21 @@
             throw new IOException("LogRecord: bad version: " + major + "." + minor);
         }
         int len = in.readInt();
-        if (len == -1) {
+        if (len < -1) {
+            throw new NegativeArraySizeException();
+        } else if (len == -1) {
             parameters = null;
-        } else {
+        } else if (len < 255) {
             parameters = new Object[len];
             for (int i = 0; i < parameters.length; i++) {
                 parameters[i] = in.readObject();
             }
+        } else {
+            List<Object> params = new ArrayList<>(Math.min(len, 1024));
+            for (int i = 0; i < len; i++) {
+                params.add(in.readObject());
+            }
+            parameters = params.toArray(new Object[params.size()]);
         }
         // If necessary, try to regenerate the resource bundle.
         if (resourceBundleName != null) {
--- a/src/java.management/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.management/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 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
@@ -347,7 +347,7 @@
                   +", unwrapping parameters using classLoaderWithRepository.");
 
         values =
-            nullIsEmpty(unwrap(params, classLoaderWithRepository, Object[].class));
+            nullIsEmpty(unwrap(params, classLoaderWithRepository, Object[].class,delegationSubject));
 
         try {
             final Object params2[] =
@@ -411,7 +411,7 @@
         values = nullIsEmpty(unwrap(params,
                                     getClassLoader(loaderName),
                                     defaultClassLoader,
-                                    Object[].class));
+                                    Object[].class,delegationSubject));
 
         try {
             final Object params2[] =
@@ -522,7 +522,7 @@
                  "connectionId=" + connectionId
                  +" unwrapping query with defaultClassLoader.");
 
-        queryValue = unwrap(query, defaultContextClassLoader, QueryExp.class);
+        queryValue = unwrap(query, defaultContextClassLoader, QueryExp.class, delegationSubject);
 
         try {
             final Object params[] = new Object[] { name, queryValue };
@@ -557,7 +557,7 @@
                  "connectionId=" + connectionId
                  +" unwrapping query with defaultClassLoader.");
 
-        queryValue = unwrap(query, defaultContextClassLoader, QueryExp.class);
+        queryValue = unwrap(query, defaultContextClassLoader, QueryExp.class, delegationSubject);
 
         try {
             final Object params[] = new Object[] { name, queryValue };
@@ -707,7 +707,7 @@
         attr = unwrap(attribute,
                       getClassLoaderFor(name),
                       defaultClassLoader,
-                      Attribute.class);
+                      Attribute.class, delegationSubject);
 
         try {
             final Object params[] = new Object[] { name, attr };
@@ -758,7 +758,7 @@
             unwrap(attributes,
                    getClassLoaderFor(name),
                    defaultClassLoader,
-                   AttributeList.class);
+                   AttributeList.class, delegationSubject);
 
         try {
             final Object params[] = new Object[] { name, attrlist };
@@ -810,7 +810,7 @@
         values = nullIsEmpty(unwrap(params,
                                     getClassLoaderFor(name),
                                     defaultClassLoader,
-                                    Object[].class));
+                                    Object[].class, delegationSubject));
 
         try {
             final Object params2[] =
@@ -990,7 +990,7 @@
 
                 filterValues[i] =
                     unwrap(filters[i], targetCl, defaultClassLoader,
-                           NotificationFilter.class);
+                           NotificationFilter.class, sbjs[i]);
 
                 if (debug) logger.debug("addNotificationListener"+
                                         "(ObjectName,NotificationFilter)",
@@ -1058,7 +1058,7 @@
                  +" unwrapping filter with target extended ClassLoader.");
 
         filterValue =
-            unwrap(filter, targetCl, defaultClassLoader, NotificationFilter.class);
+            unwrap(filter, targetCl, defaultClassLoader, NotificationFilter.class, delegationSubject);
 
         if (debug) logger.debug("addNotificationListener"+
                  "(ObjectName,ObjectName,NotificationFilter,Object)",
@@ -1066,7 +1066,7 @@
                  +" unwrapping handback with target extended ClassLoader.");
 
         handbackValue =
-            unwrap(handback, targetCl, defaultClassLoader, Object.class);
+            unwrap(handback, targetCl, defaultClassLoader, Object.class, delegationSubject);
 
         try {
             final Object params[] =
@@ -1197,7 +1197,7 @@
                  +" unwrapping filter with target extended ClassLoader.");
 
         filterValue =
-            unwrap(filter, targetCl, defaultClassLoader, NotificationFilter.class);
+            unwrap(filter, targetCl, defaultClassLoader, NotificationFilter.class, delegationSubject);
 
         if (debug) logger.debug("removeNotificationListener"+
                  "(ObjectName,ObjectName,NotificationFilter,Object)",
@@ -1205,7 +1205,7 @@
                  +" unwrapping handback with target extended ClassLoader.");
 
         handbackValue =
-            unwrap(handback, targetCl, defaultClassLoader, Object.class);
+            unwrap(handback, targetCl, defaultClassLoader, Object.class, delegationSubject);
 
         try {
             final Object params[] =
@@ -1549,20 +1549,38 @@
         }
     }
 
-    private static <T> T unwrap(final MarshalledObject<?> mo,
+    private <T> T unwrap(final MarshalledObject<?> mo,
                                 final ClassLoader cl,
-                                final Class<T> wrappedClass)
+                                final Class<T> wrappedClass,
+                                Subject delegationSubject)
             throws IOException {
         if (mo == null) {
             return null;
         }
         try {
             final ClassLoader old = AccessController.doPrivileged(new SetCcl(cl));
-            try {
-                return wrappedClass.cast(mo.get());
-            } catch (ClassNotFoundException cnfe) {
-                throw new UnmarshalException(cnfe.toString(), cnfe);
-            } finally {
+            try{
+                final AccessControlContext reqACC;
+                if (delegationSubject == null)
+                    reqACC = acc;
+                else {
+                    if (subject == null) {
+                        final String msg =
+                            "Subject delegation cannot be enabled unless " +
+                            "an authenticated subject is put in place";
+                        throw new SecurityException(msg);
+                    }
+                    reqACC = subjectDelegator.delegatedContext(
+                        acc, delegationSubject, removeCallerContext);
+                }
+                if(reqACC != null){
+                    return AccessController.doPrivileged(
+                            (PrivilegedExceptionAction<T>) () ->
+                                    wrappedClass.cast(mo.get()), reqACC);
+                }else{
+                    return wrappedClass.cast(mo.get());
+                }
+            }finally{
                 AccessController.doPrivileged(new SetCcl(old));
             }
         } catch (PrivilegedActionException pe) {
@@ -1575,14 +1593,19 @@
             }
             logger.warning("unwrap", "Failed to unmarshall object: " + e);
             logger.debug("unwrap", e);
+        }catch (ClassNotFoundException ex) {
+            logger.warning("unwrap", "Failed to unmarshall object: " + ex);
+            logger.debug("unwrap", ex);
+            throw new UnmarshalException(ex.toString(), ex);
         }
         return null;
     }
 
-    private static <T> T unwrap(final MarshalledObject<?> mo,
+    private <T> T unwrap(final MarshalledObject<?> mo,
                                 final ClassLoader cl1,
                                 final ClassLoader cl2,
-                                final Class<T> wrappedClass)
+                                final Class<T> wrappedClass,
+                                Subject delegationSubject)
         throws IOException {
         if (mo == null) {
             return null;
@@ -1596,7 +1619,7 @@
                     }
                 }
             );
-            return unwrap(mo, orderCL, wrappedClass);
+            return unwrap(mo, orderCL, wrappedClass,delegationSubject);
         } catch (PrivilegedActionException pe) {
             Exception e = extractException(pe);
             if (e instanceof IOException) {
--- a/src/java.rmi/share/classes/java/rmi/MarshalledObject.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.rmi/share/classes/java/rmi/MarshalledObject.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -29,11 +29,15 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.ObjectInputFilter;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 import java.io.ObjectStreamConstants;
 import java.io.OutputStream;
 import java.io.Serializable;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
 import sun.rmi.server.MarshalInputStream;
 import sun.rmi.server.MarshalOutputStream;
 
@@ -90,6 +94,9 @@
      */
     private int hash;
 
+    /** Filter used when creating the instance from a stream; may be null. */
+    private transient ObjectInputFilter objectInputFilter = null;
+
     /** Indicate compatibility with 1.2 version of class. */
     private static final long serialVersionUID = 8988374069173025854L;
 
@@ -133,9 +140,25 @@
     }
 
     /**
+     * Reads in the state of the object and saves the stream's
+     * serialization filter to be used when the object is deserialized.
+     *
+     * @param stream the stream
+     * @throws IOException if an I/O error occurs
+     * @throws ClassNotFoundException if a class cannot be found
+     */
+    private void readObject(ObjectInputStream stream)
+        throws IOException, ClassNotFoundException {
+        stream.defaultReadObject();     // read in all fields
+        objectInputFilter = stream.getObjectInputFilter();
+    }
+
+    /**
      * Returns a new copy of the contained marshalledobject.  The internal
      * representation is deserialized with the semantics used for
      * unmarshaling parameters for RMI calls.
+     * If the MarshalledObject was read from an ObjectInputStream,
+     * the filter from that stream is used to deserialize the object.
      *
      * @return a copy of the contained object
      * @exception IOException if an <code>IOException</code> occurs while
@@ -155,7 +178,7 @@
         ByteArrayInputStream lin =
             (locBytes == null ? null : new ByteArrayInputStream(locBytes));
         MarshalledObjectInputStream in =
-            new MarshalledObjectInputStream(bin, lin);
+            new MarshalledObjectInputStream(bin, lin, objectInputFilter);
         @SuppressWarnings("unchecked")
         T obj = (T) in.readObject();
         in.close();
@@ -295,11 +318,21 @@
          * <code>null</code>, then all annotations will be
          * <code>null</code>.
          */
-        MarshalledObjectInputStream(InputStream objIn, InputStream locIn)
+        MarshalledObjectInputStream(InputStream objIn, InputStream locIn,
+                    ObjectInputFilter filter)
             throws IOException
         {
             super(objIn);
             this.locIn = (locIn == null ? null : new ObjectInputStream(locIn));
+            if (filter != null) {
+                AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
+                    MarshalledObjectInputStream.this.setObjectInputFilter(filter);
+                    if (MarshalledObjectInputStream.this.locIn != null) {
+                        MarshalledObjectInputStream.this.locIn.setObjectInputFilter(filter);
+                    }
+                    return null;
+                });
+            }
         }
 
         /**
--- a/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl.java	Fri Jan 20 08:53:42 2017 -0800
@@ -25,8 +25,12 @@
 
 package sun.rmi.registry;
 
+import java.io.ObjectInputFilter;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.rmi.server.LogStream;
+import java.security.PrivilegedAction;
+import java.security.Security;
 import java.util.ArrayList;
 import java.util.Enumeration;
 import java.util.Hashtable;
@@ -39,7 +43,6 @@
 import java.net.*;
 import java.rmi.*;
 import java.rmi.server.ObjID;
-import java.rmi.server.RemoteServer;
 import java.rmi.server.ServerNotActiveException;
 import java.rmi.registry.Registry;
 import java.rmi.server.RMIClientSocketFactory;
@@ -54,12 +57,12 @@
 import java.security.Permissions;
 import java.security.ProtectionDomain;
 import java.text.MessageFormat;
-import sun.rmi.server.LoaderHandler;
+
+import sun.rmi.runtime.Log;
+import sun.rmi.server.UnicastRef;
 import sun.rmi.server.UnicastServerRef;
 import sun.rmi.server.UnicastServerRef2;
 import sun.rmi.transport.LiveRef;
-import sun.rmi.transport.ObjectTable;
-import sun.rmi.transport.Target;
 
 /**
  * A "registry" exists on every node that allows RMI connections to
@@ -91,6 +94,48 @@
     private static ResourceBundle resources = null;
 
     /**
+     * Property name of the RMI Registry serial filter to augment
+     * the built-in list of allowed types.
+     * Setting the property in the {@code conf/security/java.security} file
+     * will enable the augmented filter.
+     */
+    private static final String REGISTRY_FILTER_PROPNAME = "sun.rmi.registry.registryFilter";
+
+    /** Registry max depth of remote invocations. **/
+    private static int REGISTRY_MAX_DEPTH = 5;
+
+    /** Registry maximum array size in remote invocations. **/
+    private static int REGISTRY_MAX_ARRAY_SIZE = 10000;
+
+    /**
+     * The registryFilter created from the value of the {@code "sun.rmi.registry.registryFilter"}
+     * property.
+     */
+    private static final ObjectInputFilter registryFilter =
+            AccessController.doPrivileged((PrivilegedAction<ObjectInputFilter>)RegistryImpl::initRegistryFilter);
+
+    /**
+     * Initialize the registryFilter from the security properties or system property; if any
+     * @return an ObjectInputFilter, or null
+     */
+    @SuppressWarnings("deprecation")
+    private static ObjectInputFilter initRegistryFilter() {
+        ObjectInputFilter filter = null;
+        String props = System.getProperty(REGISTRY_FILTER_PROPNAME);
+        if (props == null) {
+            props = Security.getProperty(REGISTRY_FILTER_PROPNAME);
+        }
+        if (props != null) {
+            filter = ObjectInputFilter.Config.createFilter(props);
+            Log regLog = Log.getLog("sun.rmi.registry", "registry", -1);
+            if (regLog.isLoggable(Log.BRIEF)) {
+                regLog.log(Log.BRIEF, "registryFilter = " + filter);
+            }
+        }
+        return filter;
+    }
+
+    /**
      * Construct a new RegistryImpl on the specified port with the
      * given custom socket factory pair.
      */
@@ -105,7 +150,7 @@
                 AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
                     public Void run() throws RemoteException {
                         LiveRef lref = new LiveRef(id, port, csf, ssf);
-                        setup(new UnicastServerRef2(lref));
+                        setup(new UnicastServerRef2(lref, RegistryImpl::registryFilter));
                         return null;
                     }
                 }, null, new SocketPermission("localhost:"+port, "listen,accept"));
@@ -114,7 +159,7 @@
             }
         } else {
             LiveRef lref = new LiveRef(id, port, csf, ssf);
-            setup(new UnicastServerRef2(lref));
+            setup(new UnicastServerRef2(lref, RegistryImpl::registryFilter));
         }
     }
 
@@ -130,7 +175,7 @@
                 AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
                     public Void run() throws RemoteException {
                         LiveRef lref = new LiveRef(id, port);
-                        setup(new UnicastServerRef(lref));
+                        setup(new UnicastServerRef(lref, RegistryImpl::registryFilter));
                         return null;
                     }
                 }, null, new SocketPermission("localhost:"+port, "listen,accept"));
@@ -139,7 +184,7 @@
             }
         } else {
             LiveRef lref = new LiveRef(id, port);
-            setup(new UnicastServerRef(lref));
+            setup(new UnicastServerRef(lref, RegistryImpl::registryFilter));
         }
     }
 
@@ -362,6 +407,60 @@
     }
 
     /**
+     * ObjectInputFilter to filter Registry input objects.
+     * The list of acceptable classes is limited to classes normally
+     * stored in a registry.
+     *
+     * @param filterInfo access to the class, array length, etc.
+     * @return  {@link ObjectInputFilter.Status#ALLOWED} if allowed,
+     *          {@link ObjectInputFilter.Status#REJECTED} if rejected,
+     *          otherwise {@link ObjectInputFilter.Status#UNDECIDED}
+     */
+    private static ObjectInputFilter.Status registryFilter(ObjectInputFilter.FilterInfo filterInfo) {
+        if (registryFilter != null) {
+            ObjectInputFilter.Status status = registryFilter.checkInput(filterInfo);
+            if (status != ObjectInputFilter.Status.UNDECIDED) {
+                // The Registry filter can override the built-in white-list
+                return status;
+            }
+        }
+
+        if (filterInfo.depth() > REGISTRY_MAX_DEPTH) {
+            return ObjectInputFilter.Status.REJECTED;
+        }
+        Class<?> clazz = filterInfo.serialClass();
+        if (clazz != null) {
+            if (clazz.isArray()) {
+                if (filterInfo.arrayLength() >= 0 && filterInfo.arrayLength() > REGISTRY_MAX_ARRAY_SIZE) {
+                    return ObjectInputFilter.Status.REJECTED;
+                }
+                do {
+                    // Arrays are allowed depending on the component type
+                    clazz = clazz.getComponentType();
+                } while (clazz.isArray());
+            }
+            if (clazz.isPrimitive()) {
+                // Arrays of primitives are allowed
+                return ObjectInputFilter.Status.ALLOWED;
+            }
+            if (String.class == clazz
+                    || java.lang.Number.class.isAssignableFrom(clazz)
+                    || Remote.class.isAssignableFrom(clazz)
+                    || java.lang.reflect.Proxy.class.isAssignableFrom(clazz)
+                    || UnicastRef.class.isAssignableFrom(clazz)
+                    || RMIClientSocketFactory.class.isAssignableFrom(clazz)
+                    || RMIServerSocketFactory.class.isAssignableFrom(clazz)
+                    || java.rmi.activation.ActivationID.class.isAssignableFrom(clazz)
+                    || java.rmi.server.UID.class.isAssignableFrom(clazz)) {
+                return ObjectInputFilter.Status.ALLOWED;
+            } else {
+                return ObjectInputFilter.Status.REJECTED;
+            }
+        }
+        return ObjectInputFilter.Status.UNDECIDED;
+    }
+
+    /**
      * Return a new RegistryImpl on the requested port and export it to serve
      * registry requests. A classloader is initialized from the system property
      * "env.class.path" and a security manager is set unless one is already set.
--- a/src/java.rmi/share/classes/sun/rmi/runtime/Log.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.rmi/share/classes/sun/rmi/runtime/Log.java	Fri Jan 20 08:53:42 2017 -0800
@@ -232,6 +232,11 @@
             }
         }
 
+        public String toString() {
+            return logger.toString() + ", level: " + logger.getLevel() +
+                    ", name: " + logger.getName();
+        }
+
         /**
          * Set the output stream associated with the RMI server call
          * logger.
--- a/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.rmi/share/classes/sun/rmi/transport/DGCImpl.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,7 @@
  */
 package sun.rmi.transport;
 
+import java.io.ObjectInputFilter;
 import java.net.SocketPermission;
 import java.rmi.Remote;
 import java.rmi.RemoteException;
@@ -34,11 +35,13 @@
 import java.rmi.server.ObjID;
 import java.rmi.server.RemoteServer;
 import java.rmi.server.ServerNotActiveException;
+import java.rmi.server.UID;
 import java.security.AccessControlContext;
 import java.security.AccessController;
 import java.security.Permissions;
 import java.security.PrivilegedAction;
 import java.security.ProtectionDomain;
+import java.security.Security;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.HashMap;
@@ -100,6 +103,46 @@
     }
 
     /**
+     * Property name of the DGC serial filter to augment
+     * the built-in list of allowed types.
+     * Setting the property in the {@code conf/security/java.security} file
+     * or system property will enable the augmented filter.
+     */
+    private static final String DGC_FILTER_PROPNAME = "sun.rmi.transport.dgcFilter";
+
+    /** Registry max depth of remote invocations. **/
+    private static int DGC_MAX_DEPTH = 5;
+
+    /** Registry maximum array size in remote invocations. **/
+    private static int DGC_MAX_ARRAY_SIZE = 10000;
+
+    /**
+     * The dgcFilter created from the value of the {@code  "sun.rmi.transport.dgcFilter"}
+     * property.
+     */
+    private static final ObjectInputFilter dgcFilter =
+            AccessController.doPrivileged((PrivilegedAction<ObjectInputFilter>)DGCImpl::initDgcFilter);
+
+    /**
+     * Initialize the dgcFilter from the security properties or system property; if any
+     * @return an ObjectInputFilter, or null
+     */
+    private static ObjectInputFilter initDgcFilter() {
+        ObjectInputFilter filter = null;
+        String props = System.getProperty(DGC_FILTER_PROPNAME);
+        if (props == null) {
+            props = Security.getProperty(DGC_FILTER_PROPNAME);
+        }
+        if (props != null) {
+            filter = ObjectInputFilter.Config.createFilter(props);
+            if (dgcLog.isLoggable(Log.BRIEF)) {
+                dgcLog.log(Log.BRIEF, "dgcFilter = " + filter);
+            }
+        }
+        return filter;
+    }
+
+    /**
      * Construct a new server-side remote object collector at
      * a particular port. Disallow construction from outside.
      */
@@ -293,7 +336,8 @@
                         dgc = new DGCImpl();
                         ObjID dgcID = new ObjID(ObjID.DGC_ID);
                         LiveRef ref = new LiveRef(dgcID, 0);
-                        UnicastServerRef disp = new UnicastServerRef(ref);
+                        UnicastServerRef disp = new UnicastServerRef(ref,
+                                DGCImpl::checkInput);
                         Remote stub =
                             Util.createProxy(DGCImpl.class,
                                              new UnicastRef(ref), true);
@@ -324,6 +368,53 @@
         });
     }
 
+    /**
+     * ObjectInputFilter to filter DGC input objects.
+     * The list of acceptable classes is very short and explicit.
+     * The depth and array sizes are limited.
+     *
+     * @param filterInfo access to class, arrayLength, etc.
+     * @return  {@link ObjectInputFilter.Status#ALLOWED} if allowed,
+     *          {@link ObjectInputFilter.Status#REJECTED} if rejected,
+     *          otherwise {@link ObjectInputFilter.Status#UNDECIDED}
+     */
+    private static ObjectInputFilter.Status checkInput(ObjectInputFilter.FilterInfo filterInfo) {
+        if (dgcFilter != null) {
+            ObjectInputFilter.Status status = dgcFilter.checkInput(filterInfo);
+            if (status != ObjectInputFilter.Status.UNDECIDED) {
+                // The DGC filter can override the built-in white-list
+                return status;
+            }
+        }
+
+        if (filterInfo.depth() > DGC_MAX_DEPTH) {
+            return ObjectInputFilter.Status.REJECTED;
+        }
+        Class<?> clazz = filterInfo.serialClass();
+        if (clazz != null) {
+            while (clazz.isArray()) {
+                if (filterInfo.arrayLength() >= 0 && filterInfo.arrayLength() > DGC_MAX_ARRAY_SIZE) {
+                    return ObjectInputFilter.Status.REJECTED;
+                }
+                // Arrays are allowed depending on the component type
+                clazz = clazz.getComponentType();
+            }
+            if (clazz.isPrimitive()) {
+                // Arrays of primitives are allowed
+                return ObjectInputFilter.Status.ALLOWED;
+            }
+            return (clazz == ObjID.class ||
+                    clazz == UID.class ||
+                    clazz == VMID.class ||
+                    clazz == Lease.class)
+                    ? ObjectInputFilter.Status.ALLOWED
+                    : ObjectInputFilter.Status.REJECTED;
+        }
+        // Not a class, not size limited
+        return ObjectInputFilter.Status.UNDECIDED;
+    }
+
+
     private static class LeaseInfo {
         VMID vmid;
         long expiration;
--- a/src/java.sql.rowset/share/classes/com/sun/rowset/CachedRowSetImpl.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.sql.rowset/share/classes/com/sun/rowset/CachedRowSetImpl.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,9 @@
 import java.math.*;
 import java.util.*;
 import java.text.*;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
 
 import javax.sql.rowset.*;
 import javax.sql.rowset.spi.*;
@@ -357,8 +360,16 @@
         }
 
         // set the Reader, this maybe overridden latter
-        provider =
-        SyncFactory.getInstance(DEFAULT_SYNC_PROVIDER);
+        try {
+            provider = AccessController.doPrivileged(new PrivilegedExceptionAction<>() {
+                @Override
+                public SyncProvider run() throws SyncFactoryException {
+                    return SyncFactory.getInstance(DEFAULT_SYNC_PROVIDER);
+                }
+            }, null, new RuntimePermission("accessClassInPackage.com.sun.rowset.providers"));
+        } catch (PrivilegedActionException pae) {
+            throw (SyncFactoryException) pae.getException();
+        }
 
         if (!(provider instanceof RIOptimisticProvider)) {
             throw new SQLException(resBundle.handleGetObject("cachedrowsetimpl.invalidp").toString());
--- a/src/java.sql/share/classes/java/sql/Timestamp.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.sql/share/classes/java/sql/Timestamp.java	Fri Jan 20 08:53:42 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
@@ -259,7 +259,7 @@
     /**
      * Formats a timestamp in JDBC timestamp escape format.
      *         {@code yyyy-mm-dd hh:mm:ss.fffffffff},
-     * where {@code ffffffffff} indicates nanoseconds.
+     * where {@code fffffffff} indicates nanoseconds.
      *
      * @return a {@code String} object in
      *           {@code yyyy-mm-dd hh:mm:ss.fffffffff} format
--- a/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignatureMethod.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignatureMethod.java	Fri Jan 20 08:53:42 2017 -0800
@@ -21,7 +21,7 @@
  * under the License.
  */
 /*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * $Id: DOMSignatureMethod.java 1333415 2012-05-03 12:03:51Z coheigea $
@@ -41,6 +41,7 @@
 import com.sun.org.apache.xml.internal.security.algorithms.implementations.SignatureECDSA;
 import com.sun.org.apache.xml.internal.security.utils.JavaUtils;
 import org.jcp.xml.dsig.internal.SignerOutputStream;
+import sun.security.util.KeyUtil;
 
 /**
  * DOM-based abstract implementation of SignatureMethod.
@@ -207,6 +208,7 @@
         if (!(key instanceof PublicKey)) {
             throw new InvalidKeyException("key must be PublicKey");
         }
+        checkKeySize(context, key);
         if (signature == null) {
             Provider p = (Provider)context.getProperty(
                     "org.jcp.xml.dsig.internal.dom.SignatureProvider");
@@ -234,6 +236,37 @@
         return signature.verify(s);
     }
 
+    /**
+     * If secure validation mode is enabled, checks that the key size is
+     * restricted.
+     *
+     * @param context the context
+     * @param key the key to check
+     * @throws XMLSignatureException if the key size is restricted
+     */
+    private static void checkKeySize(XMLCryptoContext context, Key key)
+        throws XMLSignatureException {
+        if (Utils.secureValidation(context)) {
+            int size = KeyUtil.getKeySize(key);
+            if (size == -1) {
+                // key size cannot be determined, so we cannot check against
+                // restrictions. Note that a DSA key w/o params will be
+                // rejected later if the certificate chain is validated.
+                if (log.isLoggable(java.util.logging.Level.FINE)) {
+                    log.log(java.util.logging.Level.FINE, "Size for " +
+                            key.getAlgorithm() + " key cannot be determined");
+                }
+                return;
+            }
+            if (Policy.restrictKey(key.getAlgorithm(), size)) {
+                throw new XMLSignatureException(key.getAlgorithm() +
+                    " keys less than " +
+                    Policy.minKeySize(key.getAlgorithm()) + " bits are" +
+                    " forbidden when secure validation is enabled");
+            }
+        }
+    }
+
     byte[] sign(Key key, SignedInfo si, XMLSignContext context)
         throws InvalidKeyException, XMLSignatureException
     {
@@ -244,6 +277,7 @@
         if (!(key instanceof PrivateKey)) {
             throw new InvalidKeyException("key must be PrivateKey");
         }
+        checkKeySize(context, key);
         if (signature == null) {
             Provider p = (Provider)context.getProperty(
                     "org.jcp.xml.dsig.internal.dom.SignatureProvider");
--- a/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/Policy.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/Policy.java	Fri Jan 20 08:53:42 2017 -0800
@@ -31,8 +31,10 @@
 import java.security.PrivilegedAction;
 import java.security.Security;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -46,6 +48,7 @@
     private static int maxTrans = Integer.MAX_VALUE;
     private static int maxRefs = Integer.MAX_VALUE;
     private static Set<String> disallowedRefUriSchemes = new HashSet<>();
+    private static Map<String, Integer> minKeyMap = new HashMap<>();
     private static boolean noDuplicateIds = false;
     private static boolean noRMLoops = false;
 
@@ -101,6 +104,13 @@
                             scheme.toLowerCase(Locale.ROOT));
                     }
                     break;
+                case "minKeySize":
+                    if (tokens.length != 3) {
+                        error(entry);
+                    }
+                    minKeyMap.put(tokens[1],
+                                  Integer.parseUnsignedInt(tokens[2]));
+                    break;
                 case "noDuplicateIds":
                     if (tokens.length != 1) {
                         error(entry);
@@ -147,6 +157,10 @@
         return false;
     }
 
+    public static boolean restrictKey(String type, int size) {
+        return (size < minKeyMap.getOrDefault(type, 0));
+    }
+
     public static boolean restrictDuplicateIds() {
         return noDuplicateIds;
     }
@@ -171,6 +185,10 @@
         return Collections.<String>unmodifiableSet(disallowedRefUriSchemes);
     }
 
+    public static int minKeySize(String type) {
+        return minKeyMap.getOrDefault(type, 0);
+    }
+
     private static void error(String entry) {
         throw new IllegalArgumentException(
             "Invalid jdk.xml.dsig.secureValidationPolicy entry: " + entry);
--- a/src/jdk.crypto.ec/share/classes/sun/security/ec/ECDSASignature.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/jdk.crypto.ec/share/classes/sun/security/ec/ECDSASignature.java	Fri Jan 20 08:53:42 2017 -0800
@@ -455,18 +455,22 @@
     }
 
     // Convert the DER encoding of R and S into a concatenation of R and S
-    private byte[] decodeSignature(byte[] signature) throws SignatureException {
+    private byte[] decodeSignature(byte[] sig) throws SignatureException {
 
         try {
-            DerInputStream in = new DerInputStream(signature);
+            // Enforce strict DER checking for signatures
+            DerInputStream in = new DerInputStream(sig, 0, sig.length, false);
             DerValue[] values = in.getSequence(2);
+
+            // check number of components in the read sequence
+            // and trailing data
+            if ((values.length != 2) || (in.available() != 0)) {
+                throw new IOException("Invalid encoding for signature");
+            }
+
             BigInteger r = values[0].getPositiveBigInteger();
             BigInteger s = values[1].getPositiveBigInteger();
 
-            // Check for trailing signature data
-            if (in.available() != 0) {
-                throw new IOException("Incorrect signature length");
-            }
             // trim leading zeroes
             byte[] rBytes = trimZeroes(r.toByteArray());
             byte[] sBytes = trimZeroes(s.toByteArray());
@@ -480,7 +484,7 @@
             return result;
 
         } catch (Exception e) {
-            throw new SignatureException("Could not decode signature", e);
+            throw new SignatureException("Invalid encoding for signature", e);
         }
     }
 
--- a/src/jdk.crypto.ec/share/native/libsunec/impl/ec.c	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/jdk.crypto.ec/share/native/libsunec/impl/ec.c	Fri Jan 20 08:53:42 2017 -0800
@@ -34,7 +34,7 @@
  *   Dr Vipul Gupta <vipul.gupta@sun.com> and
  *   Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories
  *
- * Last Modified Date from the Original Code: Nov 2016
+ * Last Modified Date from the Original Code: November 2016
  *********************************************************************** */
 
 #include "mplogic.h"
@@ -715,6 +715,16 @@
     }
 
     /*
+     * Using an equivalent exponent of fixed length (same as n or 1 bit less
+     * than n) to keep the kG timing relatively constant.
+     *
+     * Note that this is an extra step on top of the approach defined in
+     * ANSI X9.62 so as to make a fixed length K.
+     */
+    CHECK_MPI_OK( mp_add(&k, &n, &k) );
+    CHECK_MPI_OK( mp_div_2(&k, &k) );
+
+    /*
     ** ANSI X9.62, Section 5.3.2, Step 2
     **
     ** Compute kG
--- a/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11Signature.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/jdk.crypto.token/share/classes/sun/security/pkcs11/P11Signature.java	Fri Jan 20 08:53:42 2017 -0800
@@ -740,17 +740,21 @@
         }
     }
 
-    private static byte[] asn1ToDSA(byte[] signature) throws SignatureException {
+    private static byte[] asn1ToDSA(byte[] sig) throws SignatureException {
         try {
-            DerInputStream in = new DerInputStream(signature);
+            // Enforce strict DER checking for signatures
+            DerInputStream in = new DerInputStream(sig, 0, sig.length, false);
             DerValue[] values = in.getSequence(2);
+
+            // check number of components in the read sequence
+            // and trailing data
+            if ((values.length != 2) || (in.available() != 0)) {
+                throw new IOException("Invalid encoding for signature");
+            }
+
             BigInteger r = values[0].getPositiveBigInteger();
             BigInteger s = values[1].getPositiveBigInteger();
 
-            // Check for trailing signature data
-            if (in.available() != 0) {
-                throw new IOException("Incorrect signature length");
-            }
             byte[] br = toByteArray(r, 20);
             byte[] bs = toByteArray(s, 20);
             if ((br == null) || (bs == null)) {
@@ -760,21 +764,25 @@
         } catch (SignatureException e) {
             throw e;
         } catch (Exception e) {
-            throw new SignatureException("invalid encoding for signature", e);
+            throw new SignatureException("Invalid encoding for signature", e);
         }
     }
 
-    private byte[] asn1ToECDSA(byte[] signature) throws SignatureException {
+    private byte[] asn1ToECDSA(byte[] sig) throws SignatureException {
         try {
-            DerInputStream in = new DerInputStream(signature);
+            // Enforce strict DER checking for signatures
+            DerInputStream in = new DerInputStream(sig, 0, sig.length, false);
             DerValue[] values = in.getSequence(2);
+
+            // check number of components in the read sequence
+            // and trailing data
+            if ((values.length != 2) || (in.available() != 0)) {
+                throw new IOException("Invalid encoding for signature");
+            }
+
             BigInteger r = values[0].getPositiveBigInteger();
             BigInteger s = values[1].getPositiveBigInteger();
 
-            // Check for trailing signature data
-            if (in.available() != 0) {
-                throw new IOException("Incorrect signature length");
-            }
             // trim leading zeroes
             byte[] br = KeyUtil.trimZeroes(r.toByteArray());
             byte[] bs = KeyUtil.trimZeroes(s.toByteArray());
@@ -785,7 +793,7 @@
             System.arraycopy(bs, 0, res, res.length - bs.length, bs.length);
             return res;
         } catch (Exception e) {
-            throw new SignatureException("invalid encoding for signature", e);
+            throw new SignatureException("Invalid encoding for signature", e);
         }
     }
 
--- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java	Fri Jan 20 08:53:42 2017 -0800
@@ -26,6 +26,8 @@
 package sun.security.tools.jarsigner;
 
 import java.io.*;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.PKIXBuilderParameters;
 import java.util.*;
 import java.util.zip.*;
 import java.util.jar.*;
@@ -40,11 +42,9 @@
 import java.net.SocketTimeoutException;
 import java.net.URL;
 import java.security.cert.CertPath;
-import java.security.cert.CertPathValidator;
 import java.security.cert.CertificateExpiredException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.CertificateNotYetValidException;
-import java.security.cert.PKIXParameters;
 import java.security.cert.TrustAnchor;
 import java.util.Map.Entry;
 
@@ -54,6 +54,8 @@
 import sun.security.pkcs.SignerInfo;
 import sun.security.timestamp.TimestampToken;
 import sun.security.tools.KeyStoreUtil;
+import sun.security.validator.Validator;
+import sun.security.validator.ValidatorException;
 import sun.security.x509.*;
 import sun.security.util.*;
 
@@ -177,9 +179,7 @@
 
     private boolean seeWeak = false;
 
-    CertificateFactory certificateFactory;
-    CertPathValidator validator;
-    PKIXParameters pkixParameters;
+    PKIXBuilderParameters pkixParameters;
 
     public void run(String args[]) {
         try {
@@ -1623,19 +1623,10 @@
         try {
             validateCertChain(certs);
         } catch (Exception e) {
-            if (debug) {
-                e.printStackTrace();
-            }
-            if (e.getCause() != null &&
-                    (e.getCause() instanceof CertificateExpiredException ||
-                     e.getCause() instanceof CertificateNotYetValidException)) {
-                // No more warning, we alreay have hasExpiredCert or notYetValidCert
-            } else {
-                chainNotValidated = true;
-                chainNotValidatedReason = e;
-                sb.append(tab).append(rb.getString(".CertPath.not.validated."))
-                        .append(e.getLocalizedMessage()).append("]\n"); // TODO
-            }
+            chainNotValidated = true;
+            chainNotValidatedReason = e;
+            sb.append(tab).append(rb.getString(".CertPath.not.validated."))
+                    .append(e.getLocalizedMessage()).append("]\n"); // TODO
         }
         if (certs.size() == 1
                 && KeyStoreUtil.isSelfSigned((X509Certificate)certs.get(0))) {
@@ -1654,9 +1645,6 @@
         }
 
         try {
-
-            certificateFactory = CertificateFactory.getInstance("X.509");
-            validator = CertPathValidator.getInstance("PKIX");
             Set<TrustAnchor> tas = new HashSet<>();
             try {
                 KeyStore caks = KeyStoreUtil.getCacertsKeyStore();
@@ -1732,7 +1720,7 @@
                 }
             } finally {
                 try {
-                    pkixParameters = new PKIXParameters(tas);
+                    pkixParameters = new PKIXBuilderParameters(tas, null);
                     pkixParameters.setRevocationEnabled(false);
                 } catch (InvalidAlgorithmParameterException ex) {
                     // Only if tas is empty
@@ -1899,17 +1887,8 @@
             try {
                 validateCertChain(Arrays.asList(certChain));
             } catch (Exception e) {
-                if (debug) {
-                    e.printStackTrace();
-                }
-                if (e.getCause() != null &&
-                        (e.getCause() instanceof CertificateExpiredException ||
-                        e.getCause() instanceof CertificateNotYetValidException)) {
-                    // No more warning, we already have hasExpiredCert or notYetValidCert
-                } else {
-                    chainNotValidated = true;
-                    chainNotValidatedReason = e;
-                }
+                chainNotValidated = true;
+                chainNotValidatedReason = e;
             }
 
             if (KeyStoreUtil.isSelfSigned(certChain[0])) {
@@ -1966,18 +1945,40 @@
     }
 
     void validateCertChain(List<? extends Certificate> certs) throws Exception {
-        int cpLen = 0;
-        out: for (; cpLen<certs.size(); cpLen++) {
-            for (TrustAnchor ta: pkixParameters.getTrustAnchors()) {
-                if (ta.getTrustedCert().equals(certs.get(cpLen))) {
-                    break out;
+        try {
+            Validator.getInstance(Validator.TYPE_PKIX,
+                    Validator.VAR_CODE_SIGNING,
+                    pkixParameters)
+                    .validate(certs.toArray(new X509Certificate[certs.size()]));
+        } catch (Exception e) {
+            if (debug) {
+                e.printStackTrace();
+            }
+            if (e instanceof ValidatorException) {
+                // Throw cause if it's CertPathValidatorException,
+                if (e.getCause() != null &&
+                        e.getCause() instanceof CertPathValidatorException) {
+                    e = (Exception) e.getCause();
+                    Throwable t = e.getCause();
+                    if ((t instanceof CertificateExpiredException &&
+                                hasExpiredCert) ||
+                            (t instanceof CertificateNotYetValidException &&
+                                    notYetValidCert)) {
+                        // we already have hasExpiredCert and notYetValidCert
+                        return;
+                    }
+                }
+                if (e instanceof ValidatorException) {
+                    ValidatorException ve = (ValidatorException)e;
+                    if (ve.getErrorType() == ValidatorException.T_EE_EXTENSIONS &&
+                            (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType)) {
+                        // We already have badKeyUsage, badExtendedKeyUsage
+                        // and badNetscapeCertType
+                        return;
+                    }
                 }
             }
-        }
-        if (cpLen > 0) {
-            CertPath cp = certificateFactory.generateCertPath(
-                    (cpLen == certs.size())? certs: certs.subList(0, cpLen));
-            validator.validate(cp, pkixParameters);
+            throw e;
         }
     }
 
--- a/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java	Fri Jan 20 08:53:42 2017 -0800
@@ -162,22 +162,13 @@
             });
 
             if (this.targetOsName == null) {
-                throw new PluginException("TargetPlatform attribute is missing for java.base module");
+                throw new PluginException("ModuleTarget attribute is missing for java.base module");
             }
 
+            checkResourcePool(files);
+
             Path bin = root.resolve(BIN_DIRNAME);
 
-            // check any duplicated resource files
-            Map<Path, Set<String>> duplicates = new HashMap<>();
-            files.entries()
-                .filter(f -> f.type() != ResourcePoolEntry.Type.CLASS_OR_RESOURCE)
-                .collect(groupingBy(this::entryToImagePath,
-                         mapping(ResourcePoolEntry::moduleName, toSet())))
-                .entrySet()
-                .stream()
-                .filter(e -> e.getValue().size() > 1)
-                .forEach(e -> duplicates.put(e.getKey(), e.getValue()));
-
             // write non-classes resource files to the image
             files.entries()
                 .filter(f -> f.type() != ResourcePoolEntry.Type.CLASS_OR_RESOURCE)
@@ -185,13 +176,8 @@
                     try {
                         accept(f);
                     } catch (FileAlreadyExistsException e) {
-                        // error for duplicated entries
-                        Path path = entryToImagePath(f);
-                        UncheckedIOException x =
-                            new UncheckedIOException(path + " duplicated in " +
-                                    duplicates.get(path), e);
-                        x.addSuppressed(e);
-                        throw x;
+                        // Should not happen! Duplicates checking already done!
+                        throw new AssertionError("Duplicate entry!", e);
                     } catch (IOException ioExp) {
                         throw new UncheckedIOException(ioExp);
                     }
@@ -242,6 +228,27 @@
         }
     }
 
+    private void checkResourcePool(ResourcePool pool) {
+        // For now, only duplicate resources check. Add more checks here (if any)
+        checkDuplicateResources(pool);
+    }
+
+    private void checkDuplicateResources(ResourcePool pool) {
+        // check any duplicated resources
+        Map<Path, Set<String>> duplicates = new HashMap<>();
+        pool.entries()
+             .filter(f -> f.type() != ResourcePoolEntry.Type.CLASS_OR_RESOURCE)
+             .collect(groupingBy(this::entryToImagePath,
+                      mapping(ResourcePoolEntry::moduleName, toSet())))
+             .entrySet()
+             .stream()
+             .filter(e -> e.getValue().size() > 1)
+             .forEach(e -> duplicates.put(e.getKey(), e.getValue()));
+        if (!duplicates.isEmpty()) {
+            throw new PluginException("Duplicate resources: " + duplicates);
+        }
+    }
+
     /**
      * Generates launcher scripts.
      *
--- a/src/jdk.jlink/share/classes/module-info.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/jdk.jlink/share/classes/module-info.java	Fri Jan 20 08:53:42 2017 -0800
@@ -24,8 +24,6 @@
  */
 
 module jdk.jlink {
-    exports jdk.tools.jlink.plugin;
-
     requires jdk.internal.opt;
     requires jdk.jdeps;
 
--- a/src/jdk.naming.rmi/share/classes/com/sun/jndi/rmi/registry/RegistryContext.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/jdk.naming.rmi/share/classes/com/sun/jndi/rmi/registry/RegistryContext.java	Fri Jan 20 08:53:42 2017 -0800
@@ -32,6 +32,8 @@
 import java.rmi.server.*;
 import java.rmi.registry.Registry;
 import java.rmi.registry.LocateRegistry;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 
 import javax.naming.*;
 import javax.naming.spi.NamingManager;
@@ -52,6 +54,18 @@
     private int port;
     private static final NameParser nameParser = new AtomicNameParser();
     private static final String SOCKET_FACTORY = "com.sun.jndi.rmi.factory.socket";
+    /**
+     * Determines whether classes may be loaded from an arbitrary URL code base.
+     */
+    static final boolean trustURLCodebase;
+    static {
+        // System property to control whether classes may be loaded from an
+        // arbitrary URL codebase
+        PrivilegedAction<String> act = () -> System.getProperty(
+            "com.sun.jndi.rmi.object.trustURLCodebase", "false");
+        String trust = AccessController.doPrivileged(act);
+        trustURLCodebase = "true".equalsIgnoreCase(trust);
+    }
 
     Reference reference = null; // ref used to create this context, if any
 
@@ -460,6 +474,27 @@
             Object obj = (r instanceof RemoteReference)
                         ? ((RemoteReference)r).getReference()
                         : (Object)r;
+
+            /*
+             * Classes may only be loaded from an arbitrary URL codebase when
+             * the system property com.sun.jndi.rmi.object.trustURLCodebase
+             * has been set to "true".
+             */
+
+            // Use reference if possible
+            Reference ref = null;
+            if (obj instanceof Reference) {
+                ref = (Reference) obj;
+            } else if (obj instanceof Referenceable) {
+                ref = ((Referenceable)(obj)).getReference();
+            }
+
+            if (ref != null && ref.getFactoryClassLocation() != null &&
+                !trustURLCodebase) {
+                throw new ConfigurationException(
+                    "The object factory is untrusted. Set the system property" +
+                    " 'com.sun.jndi.rmi.object.trustURLCodebase' to 'true'.");
+            }
             return NamingManager.getObjectInstance(obj, name, this,
                                                    environment);
         } catch (NamingException e) {
--- a/src/jdk.security.auth/share/classes/com/sun/security/auth/module/LdapLoginModule.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/jdk.security.auth/share/classes/com/sun/security/auth/module/LdapLoginModule.java	Fri Jan 20 08:53:42 2017 -0800
@@ -418,7 +418,6 @@
             constraints = new SearchControls();
             constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
             constraints.setReturningAttributes(new String[0]); //return no attrs
-            constraints.setReturningObjFlag(true); // to get the full DN
         }
 
         authzIdentity = (String)options.get(AUTHZ_IDENTITY);
@@ -878,11 +877,7 @@
             // (Use the first entry if more than one is returned)
             if (results.hasMore()) {
                 SearchResult entry = results.next();
-
-                // %%% - use the SearchResult.getNameInNamespace method
-                //        available in JDK 1.5 and later.
-                //        (can remove call to constraints.setReturningObjFlag)
-                userDN = ((Context)entry.getObject()).getNameInNamespace();
+                userDN = entry.getNameInNamespace();
 
                 if (debug) {
                     System.out.println("\t\t[LdapLoginModule] found entry: " +
--- a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/JarFileSystem.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/JarFileSystem.java	Fri Jan 20 08:53:42 2017 -0800
@@ -135,7 +135,7 @@
         TreeMap<Integer,IndexNode> map = new TreeMap<>();
         IndexNode child = metaInfVersions.child;
         while (child != null) {
-            Integer key = getVersion(child.name, metaInfVersions.name.length);
+            Integer key = getVersion(child.name, metaInfVersions.name.length + 1);
             if (key != null && key <= version) {
                 map.put(key, child);
             }
@@ -149,7 +149,7 @@
      */
     private Integer getVersion(byte[] name, int offset) {
         try {
-            return Integer.parseInt(getString(Arrays.copyOfRange(name, offset, name.length-1)));
+            return Integer.parseInt(getString(Arrays.copyOfRange(name, offset, name.length)));
         } catch (NumberFormatException x) {
             // ignore this even though it might indicate issues with the JAR structure
             return null;
@@ -176,7 +176,7 @@
      *   returns foo/bar.class
      */
     private byte[] getRootName(IndexNode prefix, IndexNode inode) {
-        int offset = prefix.name.length - 1;
+        int offset = prefix.name.length;
         byte[] fullName = inode.name;
         return Arrays.copyOfRange(fullName, offset, fullName.length);
     }
--- a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipCoder.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipCoder.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, 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
@@ -34,21 +34,56 @@
 import java.nio.charset.CodingErrorAction;
 import java.util.Arrays;
 
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
+
 /**
  * Utility class for zipfile name and comment decoding and encoding
  *
  * @author  Xueming Shen
  */
 
-final class ZipCoder {
+class ZipCoder {
 
-    String toString(byte[] ba, int length) {
+    static class UTF8 extends ZipCoder {
+        UTF8() {
+            super(UTF_8);
+        }
+
+        @Override
+        byte[] getBytes(String s) {        // fast pass for ascii
+            for (int i = 0; i < s.length(); i++) {
+                if (s.charAt(i) > 0x7f) return super.getBytes(s);
+            }
+            return s.getBytes(ISO_8859_1);
+        }
+
+        @Override
+        String toString(byte[] ba) {
+            for (byte b : ba) {
+                if (b < 0) return super.toString(ba);
+            }
+            return new String(ba, ISO_8859_1);
+        }
+    }
+
+    private static final ZipCoder utf8 = new UTF8();
+
+    public static ZipCoder get(String csn) {
+        Charset cs = Charset.forName(csn);
+        if (cs.name().equals("UTF-8")) {
+            return utf8;
+        }
+        return new ZipCoder(cs);
+    }
+
+    String toString(byte[] ba) {
         CharsetDecoder cd = decoder().reset();
-        int len = (int)(length * cd.maxCharsPerByte());
-        char[] ca = new char[len];
-        if (len == 0)
+        int clen = (int)(ba.length * cd.maxCharsPerByte());
+        char[] ca = new char[clen];
+        if (clen == 0)
             return new String(ca);
-        ByteBuffer bb = ByteBuffer.wrap(ba, 0, length);
+        ByteBuffer bb = ByteBuffer.wrap(ba, 0, ba.length);
         CharBuffer cb = CharBuffer.wrap(ca);
         CoderResult cr = cd.decode(bb, cb, true);
         if (!cr.isUnderflow())
@@ -59,10 +94,6 @@
         return new String(ca, 0, cb.position());
     }
 
-    String toString(byte[] ba) {
-        return toString(ba, ba.length);
-    }
-
     byte[] getBytes(String s) {
         CharsetEncoder ce = encoder().reset();
         char[] ca = s.toCharArray();
@@ -84,47 +115,14 @@
             return Arrays.copyOf(ba, bb.position());
     }
 
-    // assume invoked only if "this" is not utf8
-    byte[] getBytesUTF8(String s) {
-        if (isutf8)
-            return getBytes(s);
-        if (utf8 == null)
-            utf8 = new ZipCoder(Charset.forName("UTF-8"));
-        return utf8.getBytes(s);
-    }
-
-    String toStringUTF8(byte[] ba, int len) {
-        if (isutf8)
-            return toString(ba, len);
-        if (utf8 == null)
-            utf8 = new ZipCoder(Charset.forName("UTF-8"));
-        return utf8.toString(ba, len);
-    }
-
     boolean isUTF8() {
-        return isutf8;
+        return cs == UTF_8;
     }
 
     private Charset cs;
-    private boolean isutf8;
-    private ZipCoder utf8;
 
     private ZipCoder(Charset cs) {
         this.cs = cs;
-        this.isutf8 = cs.name().equals("UTF-8");
-    }
-
-    static ZipCoder get(Charset charset) {
-        return new ZipCoder(charset);
-    }
-
-    static ZipCoder get(String csn) {
-        try {
-            return new ZipCoder(Charset.forName(csn));
-        } catch (Throwable t) {
-            t.printStackTrace();
-        }
-        return new ZipCoder(Charset.defaultCharset());
     }
 
     private final ThreadLocal<CharsetDecoder> decTL = new ThreadLocal<>();
@@ -133,10 +131,10 @@
     private CharsetDecoder decoder() {
         CharsetDecoder dec = decTL.get();
         if (dec == null) {
-            dec = cs.newDecoder()
-              .onMalformedInput(CodingErrorAction.REPORT)
-              .onUnmappableCharacter(CodingErrorAction.REPORT);
-            decTL.set(dec);
+        dec = cs.newDecoder()
+            .onMalformedInput(CodingErrorAction.REPORT)
+            .onUnmappableCharacter(CodingErrorAction.REPORT);
+        decTL.set(dec);
         }
         return dec;
     }
@@ -144,10 +142,10 @@
     private CharsetEncoder encoder() {
         CharsetEncoder enc = encTL.get();
         if (enc == null) {
-            enc = cs.newEncoder()
-              .onMalformedInput(CodingErrorAction.REPORT)
-              .onUnmappableCharacter(CodingErrorAction.REPORT);
-            encTL.set(enc);
+        enc = cs.newEncoder()
+            .onMalformedInput(CodingErrorAction.REPORT)
+            .onUnmappableCharacter(CodingErrorAction.REPORT);
+        encTL.set(enc);
         }
         return enc;
     }
--- a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -314,8 +314,8 @@
                 IndexNode inode = getInode(path);
                 if (inode == null)
                     return null;
-                e = new Entry(inode.name);       // pseudo directory
-                e.method = METHOD_STORED;        // STORED for dir
+                e = new Entry(inode.name, inode.isdir);  // pseudo directory
+                e.method = METHOD_STORED;         // STORED for dir
                 e.mtime = e.atime = e.ctime = zfsDefaultTimeStamp;
             }
         } finally {
@@ -400,7 +400,8 @@
             List<Path> list = new ArrayList<>();
             IndexNode child = inode.child;
             while (child != null) {
-                ZipPath zp = new ZipPath(this, child.name);
+                // assume all path from zip file itself is "normalized"
+                ZipPath zp = new ZipPath(this, child.name, true);
                 if (filter == null || filter.accept(zp))
                     list.add(zp);
                 child = child.sibling;
@@ -415,14 +416,14 @@
         throws IOException
     {
         checkWritable();
-        dir = toDirectoryPath(dir);
+        //  dir = toDirectoryPath(dir);
         beginWrite();
         try {
             ensureOpen();
             if (dir.length == 0 || exists(dir))  // root dir, or exiting dir
                 throw new FileAlreadyExistsException(getString(dir));
             checkParents(dir);
-            Entry e = new Entry(dir, Entry.NEW);
+            Entry e = new Entry(dir, Entry.NEW, true);
             e.method = METHOD_STORED;            // STORED for dir
             update(e);
         } finally {
@@ -463,7 +464,7 @@
             } else {
                 checkParents(dst);
             }
-            Entry u = new Entry(eSrc, Entry.COPY);    // copy eSrc entry
+            Entry u = new Entry(eSrc, Entry.COPY);  // copy eSrc entry
             u.name(dst);                              // change name
             if (eSrc.type == Entry.NEW || eSrc.type == Entry.FILECH)
             {
@@ -533,7 +534,7 @@
                 if (!hasCreate && !hasCreateNew)
                     throw new NoSuchFileException(getString(path));
                 checkParents(path);
-                return getOutputStream(new Entry(path, Entry.NEW));
+                return getOutputStream(new Entry(path, Entry.NEW, false));
             }
         } finally {
             endRead();
@@ -887,7 +888,7 @@
         int off = getParentOff(path);
         if (off <= 1)
             return ROOTPATH;
-        return Arrays.copyOf(path, off + 1);
+        return Arrays.copyOf(path, off);
     }
 
     private static int getParentOff(byte[] path) {
@@ -1075,11 +1076,9 @@
             if (pos + CENHDR + nlen > limit) {
                 zerror("invalid CEN header (bad header size)");
             }
-            byte[] name = new byte[nlen + 1];
-            System.arraycopy(cen, pos + CENHDR, name, 1, nlen);
-            name[0] = '/';
-            IndexNode inode = new IndexNode(name, pos);
+            IndexNode inode = new IndexNode(cen, pos + CENHDR, nlen, pos);
             inodes.put(inode, inode);
+
             // skip ext and comment
             pos += (CENHDR + nlen + elen + clen);
         }
@@ -1112,7 +1111,7 @@
     private boolean hasUpdate = false;
 
     // shared key. consumer guarantees the "writeLock" before use it.
-    private final IndexNode LOOKUPKEY = IndexNode.keyOf(null);
+    private final IndexNode LOOKUPKEY = new IndexNode(null, -1);
 
     private void updateDelete(IndexNode inode) {
         beginWrite();
@@ -1312,16 +1311,7 @@
     IndexNode getInode(byte[] path) {
         if (path == null)
             throw new NullPointerException("path");
-        IndexNode key = IndexNode.keyOf(path);
-        IndexNode inode = inodes.get(key);
-        if (inode == null &&
-            (path.length == 0 || path[path.length -1] != '/')) {
-            // if does not ends with a slash
-            path = Arrays.copyOf(path, path.length + 1);
-            path[path.length - 1] = '/';
-            inode = inodes.get(key.as(path));
-        }
-        return inode;
+        return inodes.get(IndexNode.keyOf(path));
     }
 
     Entry getEntry(byte[] path) throws IOException {
@@ -1782,8 +1772,11 @@
         int    hashcode;  // node is hashable/hashed by its name
         int    pos = -1;  // position in cen table, -1 menas the
                           // entry does not exists in zip file
-        IndexNode(byte[] name) {
+        boolean isdir;
+
+        IndexNode(byte[] name, boolean isdir) {
             name(name);
+            this.isdir = isdir;
             this.pos = -1;
         }
 
@@ -1792,8 +1785,28 @@
             this.pos = pos;
         }
 
+        // constructor for cenInit()
+        IndexNode(byte[] cen, int noff, int nlen, int pos) {
+            if (cen[noff + nlen - 1] == '/') {
+                isdir = true;
+                nlen--;
+            }
+            name = new byte[nlen + 1];
+            System.arraycopy(cen, pos + CENHDR, name, 1, nlen);
+            name[0] = '/';
+            name(name);
+            this.pos = pos;
+        }
+
+        private static final ThreadLocal<IndexNode> cachedKey = new ThreadLocal<>();
+
         final static IndexNode keyOf(byte[] name) { // get a lookup key;
-            return new IndexNode(name, -1);
+            IndexNode key = cachedKey.get();
+            if (key == null) {
+                key = new IndexNode(name, -1);
+                cachedKey.set(key);
+            }
+            return key.as(name);
         }
 
         final void name(byte[] name) {
@@ -1807,8 +1820,7 @@
         }
 
         boolean isDir() {
-            return name != null &&
-                   (name.length == 0 || name[name.length - 1] == '/');
+            return isdir;
         }
 
         public boolean equals(Object other) {
@@ -1865,8 +1877,9 @@
 
         Entry() {}
 
-        Entry(byte[] name) {
+        Entry(byte[] name, boolean isdir) {
             name(name);
+            this.isdir = isdir;
             this.mtime  = this.ctime = this.atime = System.currentTimeMillis();
             this.crc    = 0;
             this.size   = 0;
@@ -1874,13 +1887,14 @@
             this.method = METHOD_DEFLATED;
         }
 
-        Entry(byte[] name, int type) {
-            this(name);
+        Entry(byte[] name, int type, boolean isdir) {
+            this(name, isdir);
             this.type = type;
         }
 
         Entry (Entry e, int type) {
             name(e.name);
+            this.isdir     = e.isdir;
             this.version   = e.version;
             this.ctime     = e.ctime;
             this.atime     = e.atime;
@@ -1902,7 +1916,7 @@
         }
 
         Entry (byte[] name, Path file, int type) {
-            this(name, type);
+            this(name, type, false);
             this.file = file;
             this.method = METHOD_STORED;
         }
@@ -1948,6 +1962,7 @@
             locoff      = CENOFF(cen, pos);
             pos += CENHDR;
             this.name = inode.name;
+            this.isdir = inode.isdir;
             this.hashcode = inode.hashcode;
 
             pos += nlen;
@@ -1974,9 +1989,10 @@
             int elenEXTT = 0;                // extra for Extended Timestamp
             boolean foundExtraTime = false;  // if time stamp NTFS, EXTT present
 
+            byte[] zname = isdir ? toDirectoryPath(name) : name;
+
             // confirm size/length
-
-            int nlen = (name != null) ? name.length - 1 : 0;  // name has [0] as "slash"
+            int nlen = (zname != null) ? zname.length - 1 : 0;  // name has [0] as "slash"
             int elen = (extra != null) ? extra.length : 0;
             int eoff = 0;
             int clen = (comment != null) ? comment.length : 0;
@@ -2037,7 +2053,7 @@
             writeShort(os, 0);              // internal file attributes (unused)
             writeInt(os, 0);                // external file attributes (unused)
             writeInt(os, locoff0);          // relative offset of local header
-            writeBytes(os, name, 1, nlen);
+            writeBytes(os, zname, 1, nlen);
             if (elen64 != 0) {
                 writeShort(os, EXTID_ZIP64);// Zip64 extra
                 writeShort(os, elen64 - 4); // size of "this" extra block
@@ -2075,87 +2091,13 @@
         }
 
         ///////////////////// LOC //////////////////////
-        static Entry readLOC(ZipFileSystem zipfs, long pos)
-            throws IOException
-        {
-            return readLOC(zipfs, pos, new byte[1024]);
-        }
-
-        static Entry readLOC(ZipFileSystem zipfs, long pos, byte[] buf)
-            throws IOException
-        {
-            return new Entry().loc(zipfs, pos, buf);
-        }
-
-        Entry loc(ZipFileSystem zipfs, long pos, byte[] buf)
-            throws IOException
-        {
-            assert (buf.length >= LOCHDR);
-            if (zipfs.readFullyAt(buf, 0, LOCHDR , pos) != LOCHDR)
-                throw new ZipException("loc: reading failed");
-            if (!locSigAt(buf, 0))
-                throw new ZipException("loc: wrong sig ->"
-                                       + Long.toString(getSig(buf, 0), 16));
-            //startPos = pos;
-            version  = LOCVER(buf);
-            flag     = LOCFLG(buf);
-            method   = LOCHOW(buf);
-            mtime    = dosToJavaTime(LOCTIM(buf));
-            crc      = LOCCRC(buf);
-            csize    = LOCSIZ(buf);
-            size     = LOCLEN(buf);
-            int nlen = LOCNAM(buf);
-            int elen = LOCEXT(buf);
-
-            name = new byte[nlen + 1];
-            name[0] = '/';
-            if (zipfs.readFullyAt(name, 1, nlen, pos + LOCHDR) != nlen) {
-                throw new ZipException("loc: name reading failed");
-            }
-            if (elen > 0) {
-                extra = new byte[elen];
-                if (zipfs.readFullyAt(extra, 0, elen, pos + LOCHDR + nlen)
-                    != elen) {
-                    throw new ZipException("loc: ext reading failed");
-                }
-            }
-            pos += (LOCHDR + nlen + elen);
-            if ((flag & FLAG_DATADESCR) != 0) {
-                // Data Descriptor
-                Entry e = zipfs.getEntry(name);  // get the size/csize from cen
-                if (e == null)
-                    throw new ZipException("loc: name not found in cen");
-                size = e.size;
-                csize = e.csize;
-                pos += (method == METHOD_STORED ? size : csize);
-                if (size >= ZIP64_MINVAL || csize >= ZIP64_MINVAL)
-                    pos += 24;
-                else
-                    pos += 16;
-            } else {
-                if (extra != null &&
-                    (size == ZIP64_MINVAL || csize == ZIP64_MINVAL)) {
-                    // zip64 ext: must include both size and csize
-                    int off = 0;
-                    while (off + 20 < elen) {    // HeaderID+DataSize+Data
-                        int sz = SH(extra, off + 2);
-                        if (SH(extra, off) == EXTID_ZIP64 && sz == 16) {
-                            size = LL(extra, off + 4);
-                            csize = LL(extra, off + 12);
-                            break;
-                        }
-                        off += (sz + 4);
-                    }
-                }
-                pos += (method == METHOD_STORED ? size : csize);
-            }
-            return this;
-        }
 
         int writeLOC(OutputStream os) throws IOException {
             writeInt(os, LOCSIG);               // LOC header signature
             int version = version();
-            int nlen = (name != null) ? name.length - 1 : 0; // [0] is slash
+
+            byte[] zname = isdir ? toDirectoryPath(name) : name;
+            int nlen = (zname != null) ? zname.length - 1 : 0; // [0] is slash
             int elen = (extra != null) ? extra.length : 0;
             boolean foundExtraTime = false;     // if extra timestamp present
             int eoff = 0;
@@ -2214,7 +2156,7 @@
             }
             writeShort(os, nlen);
             writeShort(os, elen + elen64 + elenNTFS + elenEXTT);
-            writeBytes(os, name, 1, nlen);
+            writeBytes(os, zname, 1, nlen);
             if (elen64 != 0) {
                 writeShort(os, EXTID_ZIP64);
                 writeShort(os, 16);
@@ -2352,16 +2294,17 @@
                             locPos += locSZ;
                              continue;
                         }
+                        int end = locPos + locSZ - 4;
                         int flag = CH(buf, locPos++);
-                        if ((flag & 0x1) != 0) {
+                        if ((flag & 0x1) != 0 && locPos <= end) {
                             mtime = unixToJavaTime(LG(buf, locPos));
                             locPos += 4;
                         }
-                        if ((flag & 0x2) != 0) {
+                        if ((flag & 0x2) != 0 && locPos <= end) {
                             atime = unixToJavaTime(LG(buf, locPos));
                             locPos += 4;
                         }
-                        if ((flag & 0x4) != 0) {
+                        if ((flag & 0x4) != 0 && locPos <= end) {
                             ctime = unixToJavaTime(LG(buf, locPos));
                             locPos += 4;
                         }
@@ -2551,7 +2494,7 @@
     private void buildNodeTree() throws IOException {
         beginWrite();
         try {
-            IndexNode root = new IndexNode(ROOTPATH);
+            IndexNode root = new IndexNode(ROOTPATH, true);
             IndexNode[] nodes = inodes.keySet().toArray(new IndexNode[0]);
             inodes.put(root, root);
             ParentLookup lookup = new ParentLookup();
@@ -2564,7 +2507,7 @@
                         root.child = node;
                         break;
                     }
-                    lookup = lookup.as(node.name, off + 1);
+                    lookup = lookup.as(node.name, off);
                     if (inodes.containsKey(lookup)) {
                         parent = inodes.get(lookup);
                         node.sibling = parent.child;
@@ -2572,7 +2515,7 @@
                         break;
                     }
                     // add new pseudo directory entry
-                    parent = new IndexNode(Arrays.copyOf(node.name, off + 1));
+                    parent = new IndexNode(Arrays.copyOf(node.name, off), true);
                     inodes.put(parent, parent);
                     node.sibling = parent.child;
                     parent.child = node;
--- a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipPath.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipPath.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, 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
@@ -59,8 +59,7 @@
         } else {
             if (zfs.zc.isUTF8()) {
                 this.path = normalize(path);
-            } else {
-                // see normalize(String);
+            } else {    // see normalize(String);
                 this.path = normalize(zfs.getString(path));
             }
         }
@@ -68,12 +67,7 @@
 
     ZipPath(ZipFileSystem zfs, String path) {
         this.zfs = zfs;
-        if (zfs.zc.isUTF8()) {
-            this.path = normalize(zfs.getBytes(path));
-        } else {
-            // see normalize(String);
-            this.path = normalize(path);
-        }
+        this.path = normalize(path);
     }
 
     @Override
@@ -84,33 +78,31 @@
             return null;
     }
 
-    @Override
+   @Override
     public Path getFileName() {
-        initOffsets();
-        int count = offsets.length;
-        if (count == 0)
-            return null;  // no elements so no name
-        if (count == 1 && path[0] != '/')
+        int off = path.length;
+        if (off == 0 || off == 1 && path[0] == '/')
+            return null;
+        while (--off >= 0 && path[off] != '/') {}
+        if (off < 0)
             return this;
-        int lastOffset = offsets[count-1];
-        int len = path.length - lastOffset;
-        byte[] result = new byte[len];
-        System.arraycopy(path, lastOffset, result, 0, len);
-        return new ZipPath(zfs, result);
+        off++;
+        byte[] result = new byte[path.length - off];
+        System.arraycopy(path, off, result, 0, result.length);
+        return new ZipPath(getFileSystem(), result, true);
     }
 
     @Override
     public ZipPath getParent() {
-        initOffsets();
-        int count = offsets.length;
-        if (count == 0)    // no elements so no parent
+        int off = path.length;
+        if (off == 0 || off == 1 && path[0] == '/')
             return null;
-        int len = offsets[count-1] - 1;
-        if (len <= 0)      // parent is root only (may be null)
+        while (--off >= 0 && path[off] != '/') {}
+        if (off <= 0)
             return getRoot();
-        byte[] result = new byte[len];
-        System.arraycopy(path, 0, result, 0, len);
-        return new ZipPath(zfs, result);
+        byte[] result = new byte[off];
+        System.arraycopy(path, 0, result, 0, off);
+        return new ZipPath(getFileSystem(), result, true);
     }
 
     @Override
@@ -277,30 +269,36 @@
 
     @Override
     public boolean isAbsolute() {
-        return (this.path.length > 0 && path[0] == '/');
+        return path.length > 0 && path[0] == '/';
     }
 
     @Override
     public ZipPath resolve(Path other) {
-        final ZipPath o = checkPath(other);
-        int tlen = this.path.length;
-        if (tlen == 0 || o.isAbsolute())
+        ZipPath o = checkPath(other);
+        if (o.path.length == 0)
+            return this;
+        if (o.isAbsolute() || this.path.length == 0)
             return o;
-        int olen = o.path.length;
-        if (olen == 0)
-            return this;
+        return resolve(o.path);
+    }
+
+    // opath is normalized, just concat
+    private ZipPath resolve(byte[] opath) {
         byte[] resolved = null;
-        if (this.path[tlen - 1] == '/') {
+        byte[] tpath = this.path;
+        int tlen = tpath.length;
+        int olen = opath.length;
+        if (path[tlen - 1] == '/') {
             resolved = new byte[tlen + olen];
-            System.arraycopy(path, 0, resolved, 0, tlen);
-            System.arraycopy(o.path, 0, resolved, tlen, olen);
+            System.arraycopy(tpath, 0, resolved, 0, tlen);
+            System.arraycopy(opath, 0, resolved, tlen, olen);
         } else {
             resolved = new byte[tlen + 1 + olen];
-            System.arraycopy(path, 0, resolved, 0, tlen);
+            System.arraycopy(tpath, 0, resolved, 0, tlen);
             resolved[tlen] = '/';
-            System.arraycopy(o.path, 0, resolved, tlen + 1, olen);
+            System.arraycopy(opath, 0, resolved, tlen + 1, olen);
         }
-        return new ZipPath(zfs, resolved);
+        return new ZipPath(zfs, resolved, true);
     }
 
     @Override
@@ -351,7 +349,12 @@
 
     @Override
     public ZipPath resolve(String other) {
-        return resolve(zfs.getPath(other));
+        byte[] opath = normalize(other);
+        if (opath.length == 0)
+            return this;
+        if (opath[0] == '/' || this.path.length == 0)
+            return new ZipPath(zfs, opath, true);
+        return resolve(opath);
     }
 
     @Override
@@ -455,8 +458,9 @@
                 return normalize(path, i - 1);
             prevC = c;
         }
-        if (len > 1 && prevC == '/')
+        if (len > 1 && prevC == '/') {
             return Arrays.copyOf(path, len - 1);
+        }
         return path;
     }
 
@@ -490,6 +494,8 @@
     // to avoid incorrectly normalizing byte '0x5c' (as '\')
     // to '/'.
     private byte[] normalize(String path) {
+        if (zfs.zc.isUTF8())
+            return normalize(zfs.getBytes(path));
         int len = path.length();
         if (len == 0)
             return new byte[0];
@@ -533,7 +539,8 @@
     // Remove DotSlash(./) and resolve DotDot (..) components
     private byte[] getResolved() {
         for (int i = 0; i < path.length; i++) {
-            if (path[i] == (byte)'.') {
+            if (path[i] == (byte)'.' &&
+                (i + 1 == path.length || path[i + 1] == '/')) {
                 return resolve0();
             }
         }
@@ -976,5 +983,4 @@
         }
         return sb.toString();
     }
-
 }
--- a/test/ProblemList.txt	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/ProblemList.txt	Fri Jan 20 08:53:42 2017 -0800
@@ -258,6 +258,8 @@
 
 tools/jlink/multireleasejar/JLinkMultiReleaseJarTest.java       8169971 windows-x64
 
+tools/jlink/CustomPluginTest.java                               8172864 generic-all
+
 ############################################################################
 
 # jdk_jdi
--- a/test/TEST.ROOT	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/TEST.ROOT	Fri Jan 20 08:53:42 2017 -0800
@@ -26,8 +26,8 @@
 # Allow querying of various System properties in @requires clauses
 requires.properties=sun.arch.data.model java.runtime.name
 
-# Tests using jtreg 4.2 b04 features
-requiredVersion=4.2 b04
+# Tests using jtreg 4.2 b05 features
+requiredVersion=4.2 b05
 
 # Path to libraries in the topmost test directory. This is needed so @library
 # does not need ../../ notation to reach them
--- a/test/com/sun/crypto/provider/Cipher/AES/TestAESCiphers/testAES.policy	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/com/sun/crypto/provider/Cipher/AES/TestAESCiphers/testAES.policy	Fri Jan 20 08:53:42 2017 -0800
@@ -1,6 +1,6 @@
-grant 
-{
+grant codeBase "file:${test.classes}/*" {
     permission java.security.SecurityPermission "removeProvider.SunJCE";
     permission java.security.SecurityPermission "insertProvider.SunJCE";
-    permission java.security.SecurityPermission "putProviderProperty.SunJCE";
+    permission java.lang.RuntimePermission
+               "accessClassInPackage.com.sun.crypto.provider";
 };
--- a/test/com/sun/security/auth/module/LdapLoginModule/CheckConfigs.policy	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/com/sun/security/auth/module/LdapLoginModule/CheckConfigs.policy	Fri Jan 20 08:53:42 2017 -0800
@@ -1,9 +1,9 @@
-
-grant {
+grant codeBase "file:${test.classes}/*" {
     // The following permissions are not required because the test is
     // not expected to connect to an LDAP server
     //
     //permission java.net.SocketPermission "*:389", "connect";
     //permission java.net.SocketPermission "*:636", "connect";
     //permission javax.security.auth.AuthPermission "modifyPrincipals";
+    permission java.lang.RuntimePermission "accessClassInPackage.com.sun.jndi.ldap";
 };
--- a/test/java/lang/SecurityManager/CheckPackageAccess.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/java/lang/SecurityManager/CheckPackageAccess.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,87 +23,174 @@
 
 /*
  *  @test
- *  @bug 6741606 7146431 8000450 8019830 8022945 8027144 8041633 8078427
- *  @summary Make sure all restricted packages listed in the package.access
+ *  @bug 6741606 7146431 8000450 8019830 8022945 8027144 8041633 8078427 8055206
+ *  @summary Check that various restricted packages that are supposed to be
+ *           restricted by default or are listed in the package.access
  *           property in the java.security file are blocked
+ *  @modules java.xml.ws java.corba
  *  @run main/othervm CheckPackageAccess
  */
 
-import java.util.Collections;
-import java.util.ArrayList;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReference;
+import java.util.Arrays;
 import java.util.List;
+import java.util.Optional;
 
-/*
- * The main benefit of this test is to catch merge errors or other types
- * of issues where one or more of the packages are accidentally
- * removed. This is why the packages that are known to be restricted have to
- * be explicitly listed below.
- */
 public class CheckPackageAccess {
 
-    public static void main(String[] args) throws Exception {
-        // get expected list of restricted packages
-        List<String> pkgs = RestrictedPackages.expected();
+    private static final SecurityManager sm = new SecurityManager();
+    private static final ModuleFinder mf = ModuleFinder.ofSystem();
 
-        // get actual list of restricted packages
-        List<String> jspkgs = RestrictedPackages.actual();
+    /*
+     * The expected list of restricted packages of the package.access property.
+     *
+     * This array should be updated whenever new packages are added to the
+     * package.access property in the java.security file
+     * NOTE: it should be in the same order as the java.security file
+     */
+    private static final String[] EXPECTED = {
+        "sun.misc.",
+        "sun.reflect.",
+    };
 
-        if (!isOpenJDKOnly()) {
-            String lastPkg = pkgs.get(pkgs.size() - 1);
+    /**
+     * Tests access to various packages of a module.
+     */
+    private static class Test {
+        String moduleName;     // name of module
+        ModuleReference moduleRef;     // module reference
+        String exports;    // exported pkg
+        Optional<String> opens;      // opened pkg
+        String conceals;   // concealed pkg
+        Optional<String> qualExports; // qualified export pkg
+        Optional<String> qualOpens;   // qualified open pkg
+        // qual open and non-qualified export pkg
+        Optional<String> qualOpensAndExports;
+        Test(String module, String exports, String opens, String conceals,
+             String qualExports, String qualOpens, String qualOpensAndExports) {
+            this.moduleName = module;
+            this.moduleRef = mf.find(moduleName).get();
+            this.exports = exports;
+            this.opens = Optional.ofNullable(opens);
+            this.conceals = conceals;
+            this.qualExports = Optional.ofNullable(qualExports);
+            this.qualOpens = Optional.ofNullable(qualOpens);
+            this.qualOpensAndExports = Optional.ofNullable(qualOpensAndExports);
+        }
 
-            // Remove any closed packages from list before comparing
-            int index = jspkgs.indexOf(lastPkg);
-            if (index != -1 && index != jspkgs.size() - 1) {
-                jspkgs.subList(index + 1, jspkgs.size()).clear();
+        void test() {
+            System.out.println("Testing module " + moduleName);
+
+            // access to exported pkg should pass
+            testNonRestricted(exports);
+
+            // access to opened pkg should pass
+            opens.ifPresent(Test::testNonRestricted);
+
+            // access to concealed pkg should fail
+            testRestricted(conceals);
+
+            // access to qualified export pkg should fail
+            qualExports.ifPresent(Test::testRestricted);
+
+            // access to qualified open pkg should fail
+            qualOpens.ifPresent(Test::testRestricted);
+
+            // access to qualified opened pkg that is also exported should pass
+            qualOpensAndExports.ifPresent(Test::testNonRestricted);
+        }
+
+        private static void testRestricted(String pkg) {
+            try {
+                sm.checkPackageAccess(pkg);
+                throw new RuntimeException("Able to access restricted package: "
+                                           + pkg);
+            } catch (SecurityException se) {}
+            try {
+                sm.checkPackageDefinition(pkg);
+                throw new RuntimeException("Able to access restricted package: "
+                                           + pkg);
+            } catch (SecurityException se) {}
+        }
+
+        private static void testNonRestricted(String pkg) {
+            try {
+                sm.checkPackageAccess(pkg);
+            } catch (SecurityException se) {
+                throw new RuntimeException("Unable to access exported package: "
+                                           + pkg, se);
+            }
+            try {
+                sm.checkPackageDefinition(pkg);
+            } catch (SecurityException se) {
+                throw new RuntimeException("Unable to access exported package: "
+                                           + pkg, se);
             }
         }
+    }
 
-        // Sort to ensure lists are comparable
-        Collections.sort(pkgs);
-        Collections.sort(jspkgs);
+    private static final Test[] tests = new Test[] {
+        // java.base module loaded by boot loader
+        new Test("java.base", "java.security", null, "jdk.internal.jrtfs",
+                 "jdk.internal.loader", null, null),
+        // java.desktop module loaded by boot loader and has an openQual pkg
+        // that is exported
+        new Test("java.desktop", "java.applet", null, "sun.applet",
+                 "sun.awt", "com.sun.java.swing.plaf.windows",
+                 "javax.swing.plaf.basic"),
+        // java.security.jgss module loaded by platform loader
+        new Test("java.security.jgss", "org.ietf.jgss", null,
+                 "sun.security.krb5.internal.crypto", "sun.security.krb5",
+                 null, null),
+        // java.xml.ws module loaded by platform loader but needs to be added
+        // and has an openQual pkg that is exported
+        new Test("java.xml.ws", "javax.xml.soap", null,
+                 "com.sun.xml.internal.stream.buffer",
+                 "com.sun.xml.internal.ws.api", null,
+                 "javax.xml.ws.wsaddressing"),
+        // java.xml.ws module loaded by platform loader but needs to be added
+        // and has an openQual pkg
+        new Test("java.corba", "javax.rmi", null, "sun.corba",
+                 "com.sun.corba.se.impl.util", "com.sun.jndi.cosnaming", null),
+    };
 
-        if (!pkgs.equals(jspkgs)) {
-            for (String p : pkgs)
-                if (!jspkgs.contains(p))
-                    System.out.println("In golden set, but not in j.s file: " + p);
-            for (String p : jspkgs)
-                if (!pkgs.contains(p))
-                    System.out.println("In j.s file, but not in golden set: " + p);
+    public static void main(String[] args) throws Exception {
 
+        // check expected list of restricted packages in java.security file
+        checkPackages(Arrays.asList(EXPECTED));
 
-            throw new RuntimeException("restricted packages are not " +
-                                       "consistent with java.security file");
+        // check access to each module's packages
+        for (Test test : tests) {
+            test.test();
         }
-        System.setSecurityManager(new SecurityManager());
-        SecurityManager sm = System.getSecurityManager();
+
+        System.out.println("Test passed");
+    }
+
+    private static void checkPackages(List<String> pkgs) {
         for (String pkg : pkgs) {
-            String subpkg = pkg + "foo";
             try {
                 sm.checkPackageAccess(pkg);
                 throw new RuntimeException("Able to access " + pkg +
                                            " package");
             } catch (SecurityException se) { }
             try {
-                sm.checkPackageAccess(subpkg);
-                throw new RuntimeException("Able to access " + subpkg +
-                                           " package");
-            } catch (SecurityException se) { }
-            try {
                 sm.checkPackageDefinition(pkg);
                 throw new RuntimeException("Able to define class in " + pkg +
                                            " package");
             } catch (SecurityException se) { }
+            String subpkg = pkg + "foo";
+            try {
+                sm.checkPackageAccess(subpkg);
+                throw new RuntimeException("Able to access " + subpkg +
+                                           " package");
+            } catch (SecurityException se) { }
             try {
                 sm.checkPackageDefinition(subpkg);
-                throw new RuntimeException("Able to define class in " + subpkg +
-                                           " package");
+                throw new RuntimeException("Able to define class in " +
+                                           subpkg + " package");
             } catch (SecurityException se) { }
         }
-        System.out.println("Test passed");
-    }
-
-    private static boolean isOpenJDKOnly() {
-        String prop = System.getProperty("java.runtime.name");
-        return prop != null && prop.startsWith("OpenJDK");
     }
 }
--- a/test/java/lang/SecurityManager/CheckPackageMatching.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/java/lang/SecurityManager/CheckPackageMatching.java	Fri Jan 20 08:53:42 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
@@ -28,11 +28,13 @@
  * @run main/othervm CheckPackageMatching
  */
 
+import java.security.Security;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.StringTokenizer;
 
 /*
  * The purpose of this test is not to verify the content of the package
@@ -46,10 +48,23 @@
      * The restricted packages listed in the package.access property of the
      * java.security file.
      */
-    private static final String[] packages =
-        RestrictedPackages.actual().toArray(new String[0]);
+    private static final String[] packages = actual().toArray(new String[0]);
 
-    private static final boolean OPEN_JDK = isOpenJDKOnly();
+    /**
+     * Returns the list of restricted packages in the package.access property.
+     */
+    private static List<String> actual() {
+        String prop = Security.getProperty("package.access");
+        List<String> packages = new ArrayList<>();
+        if (prop != null && !prop.equals("")) {
+            StringTokenizer tok = new StringTokenizer(prop, ",");
+            while (tok.hasMoreElements()) {
+                String s = tok.nextToken().trim();
+                packages.add(s);
+            }
+        }
+        return packages;
+    }
 
     /**
      * PackageMatcher implements a state machine that matches package
@@ -326,13 +341,8 @@
         System.getSecurityManager().checkPackageAccess("com.sun.jmxa");
         System.getSecurityManager().checkPackageAccess("jmx");
         List<String> actual = Arrays.asList(packages);
-        for (String p : actual) {
-            if (!actual.contains(p)) {
-                System.err.println("Warning: '" + p + " not in package.access");
-            }
-        }
-        if (!actual.contains("sun.")) {
-            throw new Error("package.access does not contain 'sun.'");
+        if (!actual.contains("sun.misc.")) {
+            throw new Error("package.access does not contain 'sun.misc.'");
         }
     }
 
@@ -447,17 +457,15 @@
 
         // These should not match.
         for (String pkg : new String[] {"gloups.machin", "su",
-                                        "org.jcp.xml.dsig.interna",
+                                        "org.jcp.xml.dsig.inter",
                                         "com.sun.jm", "com.sun.jmxa"}) {
             testMatch(matcher, pkg, false, true);
         }
 
         // These should match.
         for (String pkg : Arrays.asList(
-                new String[] {"sun.gloups.machin", "sun", "sun.com",
-                              "com.sun.jmx", "com.sun.jmx.a",
-                              "org.jcp.xml.dsig.internal",
-                              "org.jcp.xml.dsig.internal.foo"})) {
+                new String[] {"sun.misc.gloups.machin", "sun.misc",
+                              "sun.reflect"})) {
             testMatch(matcher, pkg, true, true);
         }
 
@@ -486,12 +494,6 @@
         }
 
         for (String pkg : pkgs) {
-            if (!OPEN_JDK && pkg.equals("com.sun.media.sound.")) {
-                // don't test com.sun.media.sound since there is an entry
-                // for com.sun.media in non OpenJDK builds. Otherwise,
-                // the test for this package will fail unexpectedly.
-                continue;
-            }
             String candidate = pkg.substring(0, pkg.length() - 2);
             boolean expected = pkglist.contains(candidate + ".");
             testMatch(matcher, candidate, expected,
@@ -537,9 +539,4 @@
             }
         }
     }
-
-    private static boolean isOpenJDKOnly() {
-        String prop = System.getProperty("java.runtime.name");
-        return prop != null && prop.startsWith("OpenJDK");
-    }
 }
--- a/test/java/lang/SecurityManager/RestrictedPackages.java	Fri Jan 20 10:28:34 2017 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,155 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.security.Security;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.StringTokenizer;
-
-/**
- * A collection of utility methods and constants for testing the package
- * access and package definition security checks.
- */
-final class RestrictedPackages {
-
-    /*
-     * The expected list of restricted packages.
-     *
-     * This array should be updated whenever new packages are added to the
-     * package.access property in the java.security file
-     * NOTE: it should be in the same order as the java.security file
-     */
-    static final String[] EXPECTED = {
-        "sun.",
-        "com.sun.xml.internal.",
-        "com.sun.imageio.",
-        "com.sun.istack.internal.",
-        "com.sun.jmx.",
-        "com.sun.media.sound.",
-        "com.sun.naming.internal.",
-        "com.sun.proxy.",
-        "com.sun.corba.se.",
-        "com.sun.org.apache.bcel.internal.",
-        "com.sun.org.apache.regexp.internal.",
-        "com.sun.org.apache.xerces.internal.",
-        "com.sun.org.apache.xpath.internal.",
-        "com.sun.org.apache.xalan.internal.extensions.",
-        "com.sun.org.apache.xalan.internal.lib.",
-        "com.sun.org.apache.xalan.internal.res.",
-        "com.sun.org.apache.xalan.internal.templates.",
-        "com.sun.org.apache.xalan.internal.utils.",
-        "com.sun.org.apache.xalan.internal.xslt.",
-        "com.sun.org.apache.xalan.internal.xsltc.cmdline.",
-        "com.sun.org.apache.xalan.internal.xsltc.compiler.",
-        "com.sun.org.apache.xalan.internal.xsltc.trax.",
-        "com.sun.org.apache.xalan.internal.xsltc.util.",
-        "com.sun.org.apache.xml.internal.res.",
-        "com.sun.org.apache.xml.internal.security.",
-        "com.sun.org.apache.xml.internal.serializer.dom3.",
-        "com.sun.org.apache.xml.internal.serializer.utils.",
-        "com.sun.org.apache.xml.internal.utils.",
-        "com.sun.org.glassfish.",
-        "com.sun.tools.script.",
-        "com.oracle.xmlns.internal.",
-        "com.oracle.webservices.internal.",
-        "org.jcp.xml.dsig.internal.",
-        "jdk.internal.",
-        "jdk.nashorn.internal.",
-        "jdk.nashorn.tools.",
-        "jdk.tools.jimage.",
-        "com.sun.activation.registries.",
-        "com.sun.java.accessibility.util.internal."
-    };
-
-    /*
-     * A non-exhaustive list of restricted packages.
-     *
-     * Contrary to what is in the EXPECTED list, this list does not need
-     * to be exhaustive.
-     */
-    static final String[] EXPECTED_NONEXHAUSTIVE = {
-        "sun.",
-        "com.sun.xml.internal.",
-        "com.sun.imageio.",
-        "com.sun.istack.internal.",
-        "com.sun.jmx.",
-        "com.sun.proxy.",
-        "com.sun.org.apache.bcel.internal.",
-        "com.sun.org.apache.regexp.internal.",
-        "com.sun.org.apache.xerces.internal.",
-        "com.sun.org.apache.xpath.internal.",
-        "com.sun.org.apache.xalan.internal.extensions.",
-        "com.sun.org.apache.xalan.internal.lib.",
-        "com.sun.org.apache.xalan.internal.res.",
-        "com.sun.org.apache.xalan.internal.templates.",
-        "com.sun.org.apache.xalan.internal.utils.",
-        "com.sun.org.apache.xalan.internal.xslt.",
-        "com.sun.org.apache.xalan.internal.xsltc.cmdline.",
-        "com.sun.org.apache.xalan.internal.xsltc.compiler.",
-        "com.sun.org.apache.xalan.internal.xsltc.trax.",
-        "com.sun.org.apache.xalan.internal.xsltc.util.",
-        "com.sun.org.apache.xml.internal.res.",
-        "com.sun.org.apache.xml.internal.serializer.utils.",
-        "com.sun.org.apache.xml.internal.utils.",
-        "com.sun.org.apache.xml.internal.security.",
-        "com.sun.org.glassfish.",
-        "org.jcp.xml.dsig.internal."
-    };
-
-    private static final String OS_NAME = System.getProperty("os.name");
-
-    /**
-     * Returns a list of expected restricted packages, including any
-     * OS specific packages. The returned list is mutable.
-     */
-    static List<String> expected() {
-        List<String> pkgs = new ArrayList<>(Arrays.asList(EXPECTED));
-        if (OS_NAME.contains("OS X")) {
-            pkgs.add("apple.");  // add apple package for OS X
-        }
-        if (OS_NAME.contains("Win")) {
-            pkgs.add("com.sun.java.accessibility.internal.");  // add Win only package
-        }
-        return pkgs;
-    }
-
-    /**
-     * Returns a list of actual restricted packages. The returned list
-     * is mutable.
-     */
-    static List<String> actual() {
-        String prop = Security.getProperty("package.access");
-        List<String> packages = new ArrayList<>();
-        if (prop != null && !prop.equals("")) {
-            StringTokenizer tok = new StringTokenizer(prop, ",");
-            while (tok.hasMoreElements()) {
-                String s = tok.nextToken().trim();
-                packages.add(s);
-            }
-        }
-        return packages;
-    }
-
-    private RestrictedPackages() { }
-}
--- a/test/java/lang/invoke/lambda/LogGeneratedClassesTest.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/java/lang/invoke/lambda/LogGeneratedClassesTest.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -63,6 +63,7 @@
         scratch.add("        int foo();");
         scratch.add("    }");
         scratch.add("    public static void main(String[] args) {");
+        scratch.add("        System.setSecurityManager(new SecurityManager());");
         scratch.add("        I lam = () -> 10;");
         scratch.add("        Runnable r = () -> {");
         scratch.add("            System.out.println(\"Runnable\");");
@@ -114,7 +115,6 @@
     public void testNotLogging() {
         TestResult tr = doExec(JAVA_CMD.getAbsolutePath(),
                                "-cp", ".",
-                               "-Djava.security.manager",
                                "com.example.TestLambda");
         tr.assertZero("Should still return 0");
     }
@@ -125,7 +125,6 @@
         TestResult tr = doExec(JAVA_CMD.getAbsolutePath(),
                                "-cp", ".",
                                "-Djdk.internal.lambda.dumpProxyClasses=dump",
-                               "-Djava.security.manager",
                                "com.example.TestLambda");
         // 2 our own class files. We don't care about the others
         assertEquals(Files.find(
@@ -143,7 +142,6 @@
         TestResult tr = doExec(JAVA_CMD.getAbsolutePath(),
                                "-cp", ".",
                                "-Djdk.internal.lambda.dumpProxyClasses=notExist",
-                               "-Djava.security.manager",
                                "com.example.TestLambda");
         assertEquals(tr.testOutput.stream()
                                   .filter(s -> s.startsWith("WARNING"))
@@ -159,7 +157,6 @@
         TestResult tr = doExec(JAVA_CMD.getAbsolutePath(),
                                "-cp", ".",
                                "-Djdk.internal.lambda.dumpProxyClasses=file",
-                               "-Djava.security.manager",
                                "com.example.TestLambda");
         assertEquals(tr.testOutput.stream()
                                   .filter(s -> s.startsWith("WARNING"))
@@ -218,7 +215,6 @@
             TestResult tr = doExec(JAVA_CMD.getAbsolutePath(),
                                    "-cp", ".",
                                    "-Djdk.internal.lambda.dumpProxyClasses=readOnly",
-                                   "-Djava.security.manager",
                                    "com.example.TestLambda");
             assertEquals(tr.testOutput.stream()
                                       .filter(s -> s.startsWith("WARNING"))
@@ -237,7 +233,6 @@
         TestResult tr = doExec(JAVA_CMD.getAbsolutePath(),
                                "-cp", ".",
                                "-Djdk.internal.lambda.dumpProxyClasses=dumpLong",
-                               "-Djava.security.manager",
                                longFQCN);
         assertEquals(tr.testOutput.stream()
                                   .filter(s -> s.startsWith("WARNING: Exception"))
--- a/test/java/nio/channels/Selector/SelectTimeout.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/java/nio/channels/Selector/SelectTimeout.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,46 +1,50 @@
 /*
-* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
-* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-*
-* This code is free software; you can redistribute it and/or modify it
-* under the terms of the GNU General Public License version 2 only, as
-* published by the Free Software Foundation.
-*
-* This code is distributed in the hope that it will be useful, but WITHOUT
-* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-* version 2 for more details (a copy is included in the LICENSE file that
-* accompanied this code).
-*
-* You should have received a copy of the GNU General Public License version
-* 2 along with this work; if not, write to the Free Software Foundation,
-* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-*
-* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-* or visit www.oracle.com if you need additional information or have any
-* questions.
-*/
+ * 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 8165000
- * @summary Verify no IOException on OS X for large timeout value in select().
- * @requires (os.family == "mac")
+ * @bug 8165000 8172547
+ * @summary Verify no IOException on OS X for large timeout value in select()
+ * and that timeout does not occur too early on Windows.
+ * @requires (os.family == "mac" | os.family == "windows")
  */
 import java.io.IOException;
 import java.nio.channels.Selector;
 
 public class SelectTimeout {
-    private static final long HUGE_TIMEOUT = 100000001000L;
-    private static final long SLEEP_MILLIS = 10000;
+    private static final long BIG_TIMEOUT    = 100_000_001_000L; // 8165000
+    private static final long BIGGER_TIMEOUT = 850_000_000_000_000L; // 8172547
+    private static final long SLEEP_MILLIS   = 10000;
 
-    private static Exception theException;
+    private static volatile Exception theException;
+    private static volatile boolean isTimedOut;
 
     public static void main(String[] args)
         throws IOException, InterruptedException {
         int failures = 0;
         long[] timeouts =
-            new long[] {0, HUGE_TIMEOUT/2, HUGE_TIMEOUT - 1, HUGE_TIMEOUT};
+            new long[] {1, BIG_TIMEOUT/2, BIG_TIMEOUT - 1, BIG_TIMEOUT,
+                BIGGER_TIMEOUT};
         for (long t : timeouts) {
             if (!test(t)) {
                 failures++;
@@ -61,23 +65,35 @@
 
         Thread t = new Thread(() -> {
             try {
+                isTimedOut = false;
                 selector.select(timeout);
+                isTimedOut = true;
             } catch (IOException ioe) {
                 theException = ioe;
             }
         });
         t.start();
 
-        Thread.currentThread().sleep(SLEEP_MILLIS);
-        t.interrupt();
+        t.join(SLEEP_MILLIS);
 
+        boolean result;
         if (theException == null) {
-            System.out.printf("Test succeeded with timeout %d%n", timeout);
-            return true;
+            if (timeout > SLEEP_MILLIS && isTimedOut) {
+                System.err.printf("Test timed out early with timeout %d%n",
+                    timeout);
+                result = false;
+            } else {
+                System.out.printf("Test succeeded with timeout %d%n", timeout);
+                result = true;
+            }
         } else {
             System.err.printf("Test failed with timeout %d%n", timeout);
             theException.printStackTrace();
-            return false;
+            result = false;
         }
+
+        t.interrupt();
+
+        return result;
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/rmi/MarshalledObject/MOFilterTest.java	Fri Jan 20 08:53:42 2017 -0800
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InvalidClassException;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectInputFilter;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.rmi.MarshalledObject;
+import java.util.Objects;
+
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+
+/* @test
+ * @run testng/othervm  MOFilterTest
+ *
+ * @summary Test MarshalledObject applies ObjectInputFilter
+ */
+@Test
+public class MOFilterTest {
+
+    /**
+     * Two cases are tested.
+     * The filter = null and a filter set to verify the calls to the filter.
+     * @return array objects with test parameters for each test case
+     */
+    @DataProvider(name = "FilterCases")
+    public static Object[][] filterCases() {
+        return new Object[][] {
+                {true},     // run the test with the filter
+                {false},    // run the test without the filter
+
+        };
+    }
+
+    /**
+     * Test that MarshalledObject inherits the ObjectInputFilter from
+     * the stream it was deserialized from.
+     */
+    @Test(dataProvider="FilterCases")
+    static void delegatesToMO(boolean withFilter) {
+        try {
+            Serializable testobj = Integer.valueOf(5);
+            MarshalledObject<Serializable> mo = new MarshalledObject<>(testobj);
+            Assert.assertEquals(mo.get(), testobj, "MarshalledObject.get returned a non-equals test object");
+
+            byte[] bytes = writeObjects(mo);
+
+            try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+                 ObjectInputStream ois = new ObjectInputStream(bais)) {
+
+                CountingFilter filter1 = new CountingFilter();
+                ois.setObjectInputFilter(withFilter ? filter1 : null);
+                MarshalledObject<?> actualMO = (MarshalledObject<?>)ois.readObject();
+                int count = filter1.getCount();
+
+                actualMO.get();
+                int expectedCount = withFilter ? count + 2 : count;
+                int actualCount = filter1.getCount();
+                Assert.assertEquals(actualCount, expectedCount, "filter called wrong number of times during get()");
+            }
+        } catch (IOException ioe) {
+            Assert.fail("Unexpected IOException", ioe);
+        } catch (ClassNotFoundException cnf) {
+            Assert.fail("Deserializing", cnf);
+        }
+    }
+
+    /**
+     * Write objects and return a byte array with the bytes.
+     *
+     * @param objects zero or more objects to serialize
+     * @return the byte array of the serialized objects
+     * @throws IOException if an exception occurs
+     */
+    static byte[] writeObjects(Object... objects)  throws IOException {
+        byte[] bytes;
+        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
+             ObjectOutputStream oos = new ObjectOutputStream(baos)) {
+            for (Object o : objects) {
+                oos.writeObject(o);
+            }
+            bytes = baos.toByteArray();
+        }
+        return bytes;
+    }
+
+
+    static class CountingFilter implements ObjectInputFilter {
+
+        private int count;      // count of calls to the filter
+
+        CountingFilter() {
+            count = 0;
+        }
+
+        int getCount() {
+            return count;
+        }
+
+        /**
+         * Filter that rejects class Integer and allows others
+         *
+         * @param filterInfo access to the class, arrayLength, etc.
+         * @return {@code STATUS.REJECTED}
+         */
+        public ObjectInputFilter.Status checkInput(FilterInfo filterInfo) {
+            count++;
+            return ObjectInputFilter.Status.ALLOWED;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/rmi/registry/serialFilter/RegistryFilterTest.java	Fri Jan 20 08:53:42 2017 -0800
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.rmi.MarshalledObject;
+import java.rmi.NotBoundException;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.AlreadyBoundException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.util.Objects;
+import java.security.Security;
+
+import org.testng.Assert;
+import org.testng.TestNG;
+import org.testng.annotations.BeforeSuite;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @library /java/rmi/testlibrary
+ * @modules java.rmi/sun.rmi.registry
+ *          java.rmi/sun.rmi.server
+ *          java.rmi/sun.rmi.transport
+ *          java.rmi/sun.rmi.transport.tcp
+ * @build TestLibrary
+ * @summary Test filters for the RMI Registry
+ * @run testng/othervm RegistryFilterTest
+ * @run testng/othervm
+ *        -Dsun.rmi.registry.registryFilter=!java.lang.Long;!RegistryFilterTest$RejectableClass
+ *        RegistryFilterTest
+ * @run testng/othervm/policy=security.policy
+ *        -Djava.security.properties=${test.src}/java.security-extra1
+ *        RegistryFilterTest
+ */
+public class RegistryFilterTest {
+    private static Registry impl;
+    private static int port;
+    private static Registry registry;
+
+    static final int REGISTRY_MAX_ARRAY = 10000;
+
+    static final String registryFilter =
+            System.getProperty("sun.rmi.registry.registryFilter",
+                    Security.getProperty("sun.rmi.registry.registryFilter"));
+
+    @DataProvider(name = "bindAllowed")
+    static Object[][] bindAllowedObjects() {
+        Object[][] objects = {
+        };
+        return objects;
+    }
+
+    /**
+     * Data RMI Regiry bind test.
+     * - name
+     * - Object
+     * - true/false if object is blacklisted by a filter (implicit or explicit)
+     * @return array of test data
+     */
+    @DataProvider(name = "bindData")
+    static Object[][] bindObjects() {
+        Object[][] data = {
+                { "byte[max]", new XX(new byte[REGISTRY_MAX_ARRAY]), false },
+                { "String", new XX("now is the time"), false},
+                { "String[]", new XX(new String[3]), false},
+                { "Long[4]", new XX(new Long[4]), registryFilter != null },
+                { "rej-byte[toobig]", new XX(new byte[REGISTRY_MAX_ARRAY + 1]), true },
+                { "rej-MarshalledObject", createMarshalledObject(), true },
+                { "rej-RejectableClass", new RejectableClass(), registryFilter != null},
+        };
+        return data;
+    }
+
+    static XX createMarshalledObject() {
+        try {
+            return new XX(new MarshalledObject<>(null));
+        } catch (IOException ioe) {
+            return new XX(ioe);
+        }
+    }
+
+    @BeforeSuite
+    static void setupRegistry() {
+        try {
+            impl = TestLibrary.createRegistryOnEphemeralPort();
+            port = TestLibrary.getRegistryPort(impl);
+            registry = LocateRegistry.getRegistry("localhost", port);
+        } catch (RemoteException ex) {
+            Assert.fail("initialization of registry", ex);
+        }
+
+        System.out.printf("RMI Registry filter: %s%n", registryFilter);
+    }
+
+
+    /*
+     * Test registry rejects an object with the max array size  + 1.
+     */
+    @Test(dataProvider="bindData")
+    public void simpleBind(String name, Remote obj, boolean blacklisted) throws RemoteException, AlreadyBoundException, NotBoundException {
+        try {
+            registry.bind(name, obj);
+            Assert.assertFalse(blacklisted, "Registry filter did not reject (but should have) ");
+            registry.unbind(name);
+        } catch (Exception rex) {
+            Assert.assertTrue(blacklisted, "Registry filter should not have rejected");
+        }
+    }
+
+    /*
+    * Test registry rejects an object with a well known class
+    * if blacklisted in the security properties.
+    */
+    @Test
+    public void simpleRejectableClass() throws RemoteException, AlreadyBoundException, NotBoundException {
+        RejectableClass r1 = null;
+        try {
+            String name = "reject1";
+            r1 = new RejectableClass();
+            registry.bind(name, r1);
+            registry.unbind(name);
+            Assert.assertNull(registryFilter, "Registry filter should not have rejected");
+        } catch (Exception rex) {
+            Assert.assertNotNull(registryFilter, "Registry filter should have rejected");
+        }
+    }
+
+    /**
+     * A simple Serializable Remote object that is passed by value.
+     * It and its contents are checked by the Registry serial filter.
+     */
+    static class XX implements Serializable, Remote {
+        private static final long serialVersionUID = 362498820763181265L;
+
+        final Object obj;
+
+        XX(Object obj) {
+            this.obj = obj;
+        }
+
+        public String toString() {
+            return super.toString() + "//" + Objects.toString(obj);
+        }
+    }
+    /**
+     * A simple Serializable Remote object that is passed by value.
+     * It and its contents are checked by the Registry serial filter.
+     */
+    static class RejectableClass implements Serializable, Remote {
+        private static final long serialVersionUID = 362498820763181264L;
+
+        RejectableClass() {}
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/rmi/registry/serialFilter/java.security-extra1	Fri Jan 20 08:53:42 2017 -0800
@@ -0,0 +1,9 @@
+# RMI Registry Input Serial Filter
+#
+# The filter pattern uses the same format as java.io.ObjectInputStream.serialFilter.
+# This filter can override the builtin filter if additional types need to be
+# allowed or rejected from the RMI Registry.
+#
+#sun.rmi.registry.registryFilter=pattern,pattern
+sun.rmi.registry.registryFilter=!java.lang.Long;!RegistryFilterTest$RejectableClass
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/rmi/registry/serialFilter/security.policy	Fri Jan 20 08:53:42 2017 -0800
@@ -0,0 +1,4 @@
+grant {
+        permission java.security.AllPermission;
+};
+
--- a/test/java/security/KeyRep/SerialOld.policy	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/java/security/KeyRep/SerialOld.policy	Fri Jan 20 08:53:42 2017 -0800
@@ -1,4 +1,4 @@
-grant {
+grant codeBase "file:${test.classes}/*" {
 
     permission java.io.FilePermission "${test.src}${file.separator}*", "read";
     permission java.util.PropertyPermission "test.src", "read";
@@ -11,4 +11,6 @@
         "accessClassInPackage.sun.security.x509";
     permission java.lang.RuntimePermission
         "accessClassInPackage.sun.security.rsa";
+    permission java.lang.RuntimePermission
+        "accessClassInPackage.com.sun.crypto.provider";
 };
--- a/test/java/util/ResourceBundle/ResourceBundleTest.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/java/util/ResourceBundle/ResourceBundleTest.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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 4049325 4073127 4083270 4106034 4108126 8027930
+    @bug 4049325 4073127 4083270 4106034 4108126 8027930 8171139
     @summary test Resource Bundle
     @build TestResource TestResource_de TestResource_fr TestResource_fr_CH
     @build TestResource_it FakeTestResource
@@ -65,6 +65,7 @@
 import java.util.*;
 import java.util.ResourceBundle.Control;
 import java.io.*;
+import java.net.URL;
 
 public class ResourceBundleTest extends RBTestFmwk {
     public static void main(String[] args) throws Exception {
@@ -330,6 +331,44 @@
         }
     }
 
+    /*
+     * @bug 8171139
+     * @summary Make sure clearCache() clears cached ResourceBundle instances
+     */
+    public void TestClearCache() {
+        final String className = "TestResource";
+        Locale loc = Locale.getDefault();
+
+        // testing no-arg clearCache()
+        ResourceBundle rb1 = ResourceBundle.getBundle(className, loc);
+        ResourceBundle.clearCache();
+        ResourceBundle rb2 = ResourceBundle.getBundle(className, loc);
+        if (rb1 == rb2) {
+            errln("clearCache(no-arg) did not clear cache");
+        }
+
+        // clearCache() with a custom classloader
+        ClassLoader cl1 = new DummyClassLoader();
+        rb1 = ResourceBundle.getBundle(className, loc, cl1);
+        if (rb1 == rb2) {
+            errln("Same bundle was returned for different class loaders");
+        }
+        ResourceBundle.clearCache(cl1);
+        rb2= ResourceBundle.getBundle(className, loc, cl1);
+        if (rb1 == rb2) {
+            errln("clearCache(classLoader) did not clear cache");
+        }
+        ClassLoader cl2 = new DummyClassLoader();
+        rb1 = ResourceBundle.getBundle(className, loc, cl2);
+        if (rb1 == rb2) {
+            errln("Same bundle was returned for different class loaders");
+        }
+        ResourceBundle.clearCache(cl1);
+        rb2 = ResourceBundle.getBundle(className, loc, cl2);
+        if (rb1 != rb2) {
+            errln("clearCache(classLoader) incorrectly cleared cache");
+        }
+    }
 
     private void makePropertiesFile() {
         try {
@@ -393,4 +432,22 @@
             errln("Wrong number of elements in key list: expected " + expectedKeys.length +
                 " got " + elementCount);
     }
+
+    private static class DummyClassLoader extends ClassLoader {
+        public DummyClassLoader() {
+            super(DummyClassLoader.class.getClassLoader());
+        }
+
+        public Class<?> loadClass(String name) throws ClassNotFoundException {
+            return DummyClassLoader.class.getClassLoader().loadClass(name);
+        }
+
+        public URL getResource(String name) {
+            return DummyClassLoader.class.getClassLoader().getResource(name);
+        }
+
+        public InputStream getResourceAsStream(String name) {
+            return DummyClassLoader.class.getClassLoader().getResourceAsStream(name);
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/logging/modules/LogManagerInModule/LogManagerInModuleTest.java	Fri Jan 20 08:53:42 2017 -0800
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.nio.file.Paths;
+import java.util.logging.Handler;
+import java.util.logging.LogManager;
+import java.util.logging.Logger;
+
+/**
+ * @test
+ * @bug 8172886
+ * @summary Verifies that a custom LogManager or custom Handler can be
+ *          instantiated by the logging system if they are in a package
+ *          that is exported to java.logging by a module.
+ * @build test.logmanager/test.logmanager.TestLogManager
+ *        test.handlers/test.handlers.TestHandler
+ *        test.config/test.config.LogConfig
+ *        LogManagerInModuleTest
+ * @run main/othervm --add-modules test.logmanager,test.handlers
+ *          -Djava.util.logging.manager=test.logmanager.TestLogManager
+ *          LogManagerInModuleTest
+ * @run main/othervm --add-modules test.logmanager,test.handlers,test.config
+ *          -Djava.util.logging.manager=test.logmanager.TestLogManager
+ *          -Djava.util.logging.config.class=test.config.LogConfig
+ *          LogManagerInModuleTest
+ *
+ * @author danielfuchs
+ */
+public class LogManagerInModuleTest {
+
+    public static void main(String[] args) throws Exception {
+        if (System.getProperty("java.util.logging.config.class", null) == null) {
+            System.setProperty("java.util.logging.config.file",
+                Paths.get(System.getProperty("test.src", "src"),
+                          "logging.properties").toString());
+        }
+        // sanity check
+        if (LogManagerInModuleTest.class.getModule().isNamed()) {
+            throw new RuntimeException("Unexpected named module for "
+                  + LogManagerInModuleTest.class + ": "
+                  + LogManagerInModuleTest.class.getModule().getName());
+        }
+
+        // now check that the LogManager was correctly instantiated.
+        LogManager manager = LogManager.getLogManager();
+        System.out.println("LogManager: " + manager);
+        Class<?> logManagerClass = manager.getClass();
+        if (!"test.logmanager".equals(logManagerClass.getModule().getName())) {
+            throw new RuntimeException("Bad module for log manager: "
+                    + logManagerClass.getModule() + "; class is: "
+                    + logManagerClass.getName());
+        }
+
+        Logger logger = Logger.getLogger("com.xyz.foo");
+        Handler[] handlers = logger.getHandlers();
+        if (handlers.length != 1) {
+            throw new RuntimeException("Expected 1 handler, found " + handlers.length);
+        }
+        Class<?> handlerClass = handlers[0].getClass();
+        if (!"test.handlers".equals(handlerClass.getModule().getName())) {
+            throw new RuntimeException("Bad module for handler: "
+                    + handlerClass.getModule() + "; class is: "
+                    + handlerClass.getName());
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/logging/modules/LogManagerInModule/logging.properties	Fri Jan 20 08:53:42 2017 -0800
@@ -0,0 +1,56 @@
+############################################################
+#  	Global properties
+############################################################
+
+# "handlers" specifies a comma separated list of log Handler 
+# classes.  These handlers will be installed during VM startup.
+# Note that these classes must be on the system classpath.
+# By default we only configure a ConsoleHandler, which will only
+# show messages at the INFO and above levels.
+handlers= java.util.logging.ConsoleHandler
+
+# To also add the FileHandler, use the following line instead.
+#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler
+
+# Default global logging level.
+# This specifies which kinds of events are logged across
+# all loggers.  For any given facility this global level
+# can be overriden by a facility specific level
+# Note that the ConsoleHandler also has a separate level
+# setting to limit messages printed to the console.
+.level= INFO
+
+############################################################
+# Handler specific properties.
+# Describes specific configuration info for Handlers.
+############################################################
+
+# default file output is in user's home directory.
+java.util.logging.FileHandler.pattern = %h/java%u.log
+java.util.logging.FileHandler.limit = 50000
+java.util.logging.FileHandler.count = 1
+# Default number of locks FileHandler can obtain synchronously.
+# This specifies maximum number of attempts to obtain lock file by FileHandler
+# implemented by incrementing the unique field %u as per FileHandler API documentation.
+java.util.logging.FileHandler.maxLocks = 100
+java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter
+
+# Limit the message that are printed on the console to INFO and above.
+java.util.logging.ConsoleHandler.level = INFO
+java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
+
+# Example to customize the SimpleFormatter output format 
+# to print one-line log message like this:
+#     <level>: <log message> [<date/time>]
+#
+# java.util.logging.SimpleFormatter.format=%4$s: %5$s [%1$tc]%n
+
+############################################################
+# Facility specific properties.
+# Provides extra control for each logger.
+############################################################
+
+# For example, set the com.xyz.foo logger to only log SEVERE
+# messages:
+com.xyz.foo.level = SEVERE
+com.xyz.foo.handlers = test.handlers.TestHandler
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/logging/modules/LogManagerInModule/test.config/module-info.java	Fri Jan 20 08:53:42 2017 -0800
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+module test.config {
+    requires java.logging;
+    requires test.handlers;
+    // makes it possible for java.logging to instantiate test.config.LogConfig;
+    // this doesn't need to be a qualified export, but making it so will prevent
+    // any other module from being able to instantiate the provided classes.
+    exports test.config to java.logging;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/logging/modules/LogManagerInModule/test.config/test/config/LogConfig.java	Fri Jan 20 08:53:42 2017 -0800
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+package test.config;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.LogManager;
+import java.util.logging.Logger;
+import test.handlers.TestHandler;
+
+/**
+ * A dummy class that configures the logging system.
+ * @author danielfuchs
+ */
+public class LogConfig {
+    private static final List<Logger> LOGGERS = new ArrayList<>();
+    public LogConfig() {
+        LogManager manager = LogManager.getLogManager();
+        Logger logger = Logger.getLogger("com.xyz.foo");
+        if (logger.getHandlers().length > 0) {
+            System.err.println(this.getClass().getName() + ": "
+                    + "Unexpected handlers: "
+                    + List.of(logger.getHandlers()));
+            throw new RuntimeException("Unexpected handlers: "
+                    + List.of(logger.getHandlers()));
+        }
+        logger.addHandler(new TestHandler());
+        LOGGERS.add(logger);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/logging/modules/LogManagerInModule/test.handlers/module-info.java	Fri Jan 20 08:53:42 2017 -0800
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+module test.handlers {
+    requires transitive java.logging;
+    // makes it possible for java.logging and test.config to instantiate
+    // test.handlers.TestHandler;
+    // this doesn't need to be a qualified export, but making it so will prevent
+    // any other module from being able to instantiate the provided classes.
+    exports test.handlers to java.logging, test.config;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/logging/modules/LogManagerInModule/test.handlers/test/handlers/TestHandler.java	Fri Jan 20 08:53:42 2017 -0800
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+package test.handlers;
+
+import java.util.logging.Handler;
+import java.util.logging.LogRecord;
+
+/**
+ * A dummy Handler that does nothing.
+ * @author danielfuchs
+ */
+public class TestHandler extends Handler {
+
+    @Override
+    public void publish(LogRecord record) {
+    }
+
+    @Override
+    public void flush() {
+    }
+
+    @Override
+    public void close() throws SecurityException {
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/logging/modules/LogManagerInModule/test.logmanager/module-info.java	Fri Jan 20 08:53:42 2017 -0800
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+module test.logmanager {
+    requires java.logging;
+    // makes it possible for java.logging to instantiate
+    // test.logmanager.TestLogManager;
+    // this doesn't need to be a qualified export, but making it so will prevent
+    // any other module from being able to instantiate the provided classes.
+    exports test.logmanager to java.logging;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/util/logging/modules/LogManagerInModule/test.logmanager/test/logmanager/TestLogManager.java	Fri Jan 20 08:53:42 2017 -0800
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+package test.logmanager;
+
+import java.util.logging.LogManager;
+
+/**
+ * A dummy LogManager that simply extends the standard class.
+ * @author danielfuchs
+ */
+public class TestLogManager extends LogManager {
+
+}
--- a/test/javax/net/ssl/SSLParameters/UseCipherSuitesOrder.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/javax/net/ssl/SSLParameters/UseCipherSuitesOrder.java	Fri Jan 20 08:53:42 2017 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,7 @@
  * @bug 7188657
  * @summary There should be a way to reorder the JSSE ciphers
  * @run main/othervm UseCipherSuitesOrder
- *     TLS_RSA_WITH_AES_128_CBC_SHA,SSL_RSA_WITH_3DES_EDE_CBC_SHA
+ *     TLS_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_128_CBC_SHA
  */
 
 import java.io.*;
--- a/test/javax/rmi/PortableRemoteObject/8146975/jtreg.test.policy	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/javax/rmi/PortableRemoteObject/8146975/jtreg.test.policy	Fri Jan 20 08:53:42 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
@@ -21,25 +21,12 @@
  * questions.
  */
 
-grant codeBase "jrt:/java.corba" {
-        permission java.security.AllPermission;
+grant {
+  permission java.util.PropertyPermission "*", "read";
+  permission java.io.FilePermission "<<ALL FILES>>", "read, execute";
 };
 
-
-
-grant {
-  permission java.io.FilePermission "./-", "read,write,execute";
-  permission java.io.FilePermission "*", "read";
+grant codeBase "file:${test.classes}/*" {
   permission java.net.SocketPermission "*:*", "connect, accept, listen, resolve";
-  permission java.util.PropertyPermission "*", "read, write";
-  permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
-  permission java.io.SerializablePermission "enableSubclassImplementation";
-  permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
-  permission java.lang.RuntimePermission "accessClassInPackage.sun.corba";
-  permission java.lang.RuntimePermission "defineClassInPackage.sun.corba";
-  permission java.lang.RuntimePermission "reflectionFactoryAccess";
-  permission sun.corba.BridgePermission "getBridge";
-  permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.reflect";
-  permission java.util.PropertyPermission "*", "read, write";
-  permission java.io.FilePermission "<<ALL FILES>>", "read,write,execute";
+  permission java.lang.RuntimePermission "accessClassInPackage.com.sun.jndi.cosnaming";
 };
--- a/test/javax/rmi/PortableRemoteObject/jtreg.test.policy	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/javax/rmi/PortableRemoteObject/jtreg.test.policy	Fri Jan 20 08:53:42 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
@@ -21,23 +21,12 @@
  * questions.
  */
 
-grant codeBase "jrt:/java.corba" {
-        permission java.security.AllPermission;
+grant {
+  permission java.util.PropertyPermission "*", "read";
+  permission java.io.FilePermission "<<ALL FILES>>", "read, execute";
 };
 
-grant {
-  permission java.io.FilePermission "./-", "read,write,execute";
-  permission java.io.FilePermission "*", "read";
+grant codeBase "file:${test.classes}/*" {
   permission java.net.SocketPermission "*:*", "connect, accept, listen, resolve";
-  permission java.util.PropertyPermission "*", "read, write";
-  permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
-  permission java.io.SerializablePermission "enableSubclassImplementation";
-  permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
-  permission java.lang.RuntimePermission "accessClassInPackage.sun.corba";
-  permission java.lang.RuntimePermission "defineClassInPackage.sun.corba";
-  permission java.lang.RuntimePermission "reflectionFactoryAccess";
-  permission sun.corba.BridgePermission "getBridge";
-  permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.reflect";
-  permission java.util.PropertyPermission "*", "read, write";
-  permission java.io.FilePermission "<<ALL FILES>>", "read,write,execute";
+  permission java.lang.RuntimePermission "accessClassInPackage.com.sun.jndi.cosnaming";
 };
--- a/test/jdk/nio/zipfs/PathOps.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/jdk/nio/zipfs/PathOps.java	Fri Jan 20 08:53:42 2017 -0800
@@ -31,7 +31,7 @@
 /**
  *
  * @test
- * @bug 8038500 8040059 8139956 8146754
+ * @bug 8038500 8040059 8139956 8146754 8172921
  * @summary Tests path operations for zip provider.
  *
  * @run main PathOps
@@ -180,6 +180,13 @@
         return this;
     }
 
+    PathOps resolvePath(String other, String expected) {
+        out.format("test resolve %s\n", other);
+        checkPath();
+        check(path.resolve(fs.getPath(other)), expected);
+        return this;
+    }
+
     PathOps resolveSibling(String other, String expected) {
         out.format("test resolveSibling %s\n", other);
         checkPath();
@@ -384,6 +391,30 @@
             .resolve("", "")
             .resolve("foo", "foo")
             .resolve("/foo", "/foo");
+        test("/")
+            .resolve("", "/")
+            .resolve("foo", "/foo")
+            .resolve("/foo", "/foo")
+            .resolve("/foo/", "/foo");
+
+        // resolve(Path)
+        test("/tmp")
+            .resolvePath("foo", "/tmp/foo")
+            .resolvePath("/foo", "/foo")
+            .resolvePath("", "/tmp");
+        test("tmp")
+            .resolvePath("foo", "tmp/foo")
+            .resolvePath("/foo", "/foo")
+            .resolvePath("", "tmp");
+        test("")
+            .resolvePath("", "")
+            .resolvePath("foo", "foo")
+            .resolvePath("/foo", "/foo");
+        test("/")
+            .resolvePath("", "/")
+            .resolvePath("foo", "/foo")
+            .resolvePath("/foo", "/foo")
+            .resolvePath("/foo/", "/foo");
 
         // resolveSibling
         test("foo")
--- a/test/sun/security/tools/jarsigner/concise_jarsigner.sh	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/sun/security/tools/jarsigner/concise_jarsigner.sh	Fri Jan 20 08:53:42 2017 -0800
@@ -22,7 +22,7 @@
 #
 
 # @test
-# @bug 6802846
+# @bug 6802846 8172529
 # @summary jarsigner needs enhanced cert validation(options)
 #
 # @run shell/timeout=240 concise_jarsigner.sh
@@ -52,7 +52,7 @@
 KS=js.ks
 KT="$TESTJAVA${FS}bin${FS}keytool ${TESTTOOLVMOPTS} -storepass changeit -keypass changeit -keystore $KS -keyalg rsa -keysize 1024"
 JAR="$TESTJAVA${FS}bin${FS}jar ${TESTTOOLVMOPTS}"
-JARSIGNER="$TESTJAVA${FS}bin${FS}jarsigner ${TESTTOOLVMOPTS}"
+JARSIGNER="$TESTJAVA${FS}bin${FS}jarsigner ${TESTTOOLVMOPTS} -debug"
 JAVAC="$TESTJAVA${FS}bin${FS}javac ${TESTTOOLVMOPTS} ${TESTJAVACOPTS}"
 
 rm $KS
@@ -138,7 +138,7 @@
 [ $LINES = 4 ] || exit $LINENO
 
 # ==========================================================
-# Second part: exit code 2, 4, 8
+# Second part: exit code 2, 4, 8.
 # 16 and 32 already covered in the first part
 # ==========================================================
 
@@ -174,11 +174,14 @@
 $JARSIGNER -strict -keystore $KS -storepass changeit a.jar goodeku
 [ $? = 0 ] || exit $LINENO
 
-# badchain signed by ca, but ca is removed later
+# badchain signed by ca1, but ca1 is removed later
 $KT -genkeypair -alias badchain -dname CN=badchain -validity 365
-$KT -certreq -alias badchain | $KT -gencert -alias ca -validity 365 | \
+$KT -genkeypair -alias ca1 -dname CN=ca1 -ext bc -validity 365
+$KT -certreq -alias badchain | $KT -gencert -alias ca1 -validity 365 | \
         $KT -importcert -alias badchain
-$KT -delete -alias ca
+# save ca1.cert for easy replay
+$KT -exportcert -file ca1.cert -alias ca1
+$KT -delete -alias ca1
 
 $JARSIGNER -strict -keystore $KS -storepass changeit a.jar badchain
 [ $? = 4 ] || exit $LINENO
@@ -204,13 +207,41 @@
 $JARSIGNER -strict -keystore $KS -storepass changeit -certchain certchain a.jar altchain
 [ $? = 0 ] || exit $LINENO
 
-# but if ca2 is removed, -certchain does not work
+# if ca2 is removed, -certchain still work because altchain is a self-signed entry and
+# it is trusted by jarsigner
+# save ca2.cert for easy replay
+$KT -exportcert -file ca2.cert -alias ca2
 $KT -delete -alias ca2
 $JARSIGNER -strict -keystore $KS -storepass changeit -certchain certchain a.jar altchain
+[ $? = 0 ] || exit $LINENO
+
+# if cert is imported, -certchain won't work because this certificate entry is not trusted
+$KT -importcert -file certchain -alias altchain -noprompt
+$JARSIGNER -strict -keystore $KS -storepass changeit -certchain certchain a.jar altchain
 [ $? = 4 ] || exit $LINENO
 
 $JARSIGNER -verify a.jar
 [ $? = 0 ] || exit $LINENO
 
+# ==========================================================
+# 8172529
+# ==========================================================
+
+$KT -genkeypair -alias ee -dname CN=ee
+$KT -genkeypair -alias caone -dname CN=caone
+$KT -genkeypair -alias catwo -dname CN=catwo
+
+$KT -certreq -alias ee | $KT -gencert -alias catwo -rfc > ee.cert
+$KT -certreq -alias catwo | $KT -gencert -alias caone -sigalg MD5withRSA -rfc > catwo.cert
+
+# This certchain contains a cross-signed weak catwo.cert
+cat ee.cert catwo.cert | $KT -importcert -alias ee
+
+$JAR cvf a.jar A1.class
+$JARSIGNER -strict -keystore $KS -storepass changeit a.jar ee
+[ $? = 0 ] || exit $LINENO
+$JARSIGNER -strict -keystore $KS -storepass changeit -verify a.jar
+[ $? = 0 ] || exit $LINENO
+
 echo OK
 exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jar/multiRelease/ApiValidatorTest.java	Fri Jan 20 08:53:42 2017 -0800
@@ -0,0 +1,193 @@
+/*
+ * 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
+ * @summary Tests for API validator.
+ * @library /test/lib /lib/testlibrary
+ * @modules java.base/jdk.internal.misc
+ *          jdk.compiler
+ *          jdk.jartool
+ * @build jdk.test.lib.JDKToolFinder jdk.test.lib.Utils jdk.test.lib.process.*
+ * @build jdk.testlibrary.FileUtils
+ * @build MRTestBase
+ * @run testng ApiValidatorTest
+ */
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.testlibrary.FileUtils;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.lang.reflect.Method;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+public class ApiValidatorTest extends MRTestBase {
+
+    @Test(dataProvider = "signatureChange")
+    public void changeMethodSignature(String sigBase, String sigV10,
+                                      boolean isAcceptable,
+                                      Method method) throws Throwable {
+        Path root = Paths.get(method.getName());
+        Path classes = root.resolve("classes");
+
+        String METHOD_SIG = "#SIG";
+        String classTemplate =
+                "public class C { \n" +
+                        "    " + METHOD_SIG + "{ throw new RuntimeException(); };\n" +
+                        "}\n";
+        String base = classTemplate.replace(METHOD_SIG, sigBase);
+        String v10 = classTemplate.replace(METHOD_SIG, sigV10);
+
+        compileTemplate(classes.resolve("base"), base);
+        compileTemplate(classes.resolve("v10"), v10);
+
+        String jarfile = root.resolve("test.jar").toString();
+        OutputAnalyzer result = jar("cf", jarfile,
+                "-C", classes.resolve("base").toString(), ".",
+                "--release", "10", "-C", classes.resolve("v10").toString(),
+                ".");
+        if (isAcceptable) {
+            result.shouldHaveExitValue(SUCCESS)
+                    .shouldBeEmpty();
+        } else {
+            result.shouldNotHaveExitValue(SUCCESS)
+                    .shouldContain("contains a class with different api from earlier version");
+        }
+
+        FileUtils.deleteFileTreeWithRetry(root);
+    }
+
+    @DataProvider
+    Object[][] signatureChange() {
+        return new Object[][]{
+                {"public int m()", "protected int m()", false},
+                {"protected int m()", "public int m()", false},
+                {"public int m()", "int m()", false},
+                {"protected int m()", "private int m()", false},
+                {"private int m()", "int m()", true},
+                {"int m()", "private int m()", true},
+                {"int m()", "private int m(boolean b)", true},
+                {"public int m()", "public int m(int i)", false},
+                {"public int m()", "public int k()", false},
+                {"public int m()", "private int k()", false},
+// @ignore JDK-8172147   {"public int m()", "public boolean m()", false},
+// @ignore JDK-8172147   {"public boolean", "public Boolean", false},
+// @ignore JDK-8172147   {"public <T> T", "public <T extends String> T", false},
+        };
+    }
+
+    @Test(dataProvider = "publicAPI")
+    public void introducingPublicMembers(String publicAPI,
+                                         Method method) throws Throwable {
+        Path root = Paths.get(method.getName());
+        Path classes = root.resolve("classes");
+
+        String API = "#API";
+        String classTemplate =
+                "public class C { \n" +
+                        "    " + API + "\n" +
+                        "    public void method(){ };\n" +
+                        "}\n";
+        String base = classTemplate.replace(API, "");
+        String v10 = classTemplate.replace(API, publicAPI);
+
+        compileTemplate(classes.resolve("base"), base);
+        compileTemplate(classes.resolve("v10"), v10);
+
+        String jarfile = root.resolve("test.jar").toString();
+        jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
+                "--release", "10", "-C", classes.resolve("v10").toString(), ".")
+                .shouldNotHaveExitValue(SUCCESS)
+                .shouldContain("contains a class with different api from earlier version");
+
+        FileUtils.deleteFileTreeWithRetry(root);
+    }
+
+    @DataProvider
+    Object[][] publicAPI() {
+        return new Object[][]{
+// @ignore JDK-8172148  {"protected class Inner { public void m(){ } } "}, // protected inner class
+// @ignore JDK-8172148  {"public class Inner { public void m(){ } }"},  // public inner class
+// @ignore JDK-8172148  {"public enum E { A; }"},  // public enum
+                {"public void m(){ }"}, // public method
+                {"protected void m(){ }"}, // protected method
+        };
+    }
+
+    @Test(dataProvider = "privateAPI")
+    public void introducingPrivateMembers(String privateAPI,
+                                          Method method) throws Throwable {
+        Path root = Paths.get(method.getName());
+        Path classes = root.resolve("classes");
+
+        String API = "#API";
+        String classTemplate =
+                "public class C { \n" +
+                        "    " + API + "\n" +
+                        "    public void method(){ };\n" +
+                        "}\n";
+        String base = classTemplate.replace(API, "");
+        String v10 = classTemplate.replace(API, privateAPI);
+
+        compileTemplate(classes.resolve("base"), base);
+        compileTemplate(classes.resolve("v10"), v10);
+
+        String jarfile = root.resolve("test.jar").toString();
+        jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
+                "--release", "10", "-C", classes.resolve("v10").toString(), ".")
+                .shouldHaveExitValue(SUCCESS);
+        // add release
+        jar("uf", jarfile,
+                "--release", "11", "-C", classes.resolve("v10").toString(), ".")
+                .shouldHaveExitValue(SUCCESS);
+        // replace release
+        jar("uf", jarfile,
+                "--release", "11", "-C", classes.resolve("v10").toString(), ".")
+                .shouldHaveExitValue(SUCCESS);
+
+        FileUtils.deleteFileTreeWithRetry(root);
+    }
+
+    @DataProvider
+    Object[][] privateAPI() {
+        return new Object[][]{
+                {"private class Inner { public void m(){ } } "}, // private inner class
+                {"class Inner { public void m(){ } }"},  // package private inner class
+                {"enum E { A; }"},  // package private enum
+                // Local class and private method
+                {"private void m(){ class Inner { public void m(){} } Inner i = null; }"},
+                {"void m(){ }"}, // package private method
+        };
+    }
+
+    private void compileTemplate(Path classes, String template) throws Throwable {
+        Path classSourceFile = Files.createDirectories(
+                classes.getParent().resolve("src").resolve(classes.getFileName()))
+                .resolve("C.java");
+        Files.write(classSourceFile, template.getBytes());
+        javac(classes, classSourceFile);
+    }
+}
\ No newline at end of file
--- a/test/tools/jar/multiRelease/Basic.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/tools/jar/multiRelease/Basic.java	Fri Jan 20 08:53:42 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
@@ -23,69 +23,59 @@
 
 /*
  * @test
- * @library /test/lib
+ * @library /test/lib /lib/testlibrary
  * @modules java.base/jdk.internal.misc
  *          jdk.compiler
  *          jdk.jartool
- * @build jdk.test.lib.JDKToolFinder jdk.test.lib.Utils
+ * @build jdk.test.lib.JDKToolFinder jdk.test.lib.Utils jdk.test.lib.process.*
+ * @build jdk.testlibrary.FileUtils
+ * @build MRTestBase
  * @run testng Basic
  */
 
 import static org.testng.Assert.*;
 
+import jdk.testlibrary.FileUtils;
 import org.testng.annotations.*;
 
-import java.io.*;
+import java.io.File;
 import java.nio.file.*;
-import java.nio.file.attribute.*;
 import java.util.*;
-import java.util.function.Consumer;
-import java.util.jar.*;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import java.util.zip.*;
+import java.util.jar.JarFile;
+import java.util.zip.ZipFile;
 
-import jdk.test.lib.JDKToolFinder;
-import jdk.test.lib.Utils;
-
-
-import static java.lang.String.format;
-import static java.lang.System.out;
-
-public class Basic {
-    private final String src = System.getProperty("test.src", ".");
-    private final String usr = System.getProperty("user.dir", ".");
+public class Basic extends MRTestBase {
 
     @Test
     // create a regular, non-multi-release jar
-    public void test00() throws IOException {
+    public void test00() throws Throwable {
         String jarfile = "test.jar";
 
         compile("test01");  //use same data as test01
 
         Path classes = Paths.get("classes");
         jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".")
-                .assertSuccess();
+                .shouldHaveExitValue(SUCCESS);
 
         checkMultiRelease(jarfile, false);
 
-        Map<String,String[]> names = Map.of(
+        Map<String, String[]> names = Map.of(
                 "version/Main.class",
-                new String[] {"base", "version", "Main.class"},
+                new String[]{"base", "version", "Main.class"},
 
                 "version/Version.class",
-                new String[] {"base", "version", "Version.class"}
+                new String[]{"base", "version", "Version.class"}
         );
 
         compare(jarfile, names);
 
-        delete(jarfile);
-        deleteDir(Paths.get(usr, "classes"));
+        FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
+        FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
     }
 
     @Test
     // create a multi-release jar
-    public void test01() throws IOException {
+    public void test01() throws Throwable {
         String jarfile = "test.jar";
 
         compile("test01");
@@ -94,68 +84,96 @@
         jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
                 "--release", "9", "-C", classes.resolve("v9").toString(), ".",
                 "--release", "10", "-C", classes.resolve("v10").toString(), ".")
-                .assertSuccess();
+                .shouldHaveExitValue(SUCCESS);
 
         checkMultiRelease(jarfile, true);
 
-        Map<String,String[]> names = Map.of(
+        Map<String, String[]> names = Map.of(
                 "version/Main.class",
-                new String[] {"base", "version", "Main.class"},
+                new String[]{"base", "version", "Main.class"},
 
                 "version/Version.class",
-                new String[] {"base", "version", "Version.class"},
+                new String[]{"base", "version", "Version.class"},
 
                 "META-INF/versions/9/version/Version.class",
-                new String[] {"v9", "version", "Version.class"},
+                new String[]{"v9", "version", "Version.class"},
 
                 "META-INF/versions/10/version/Version.class",
-                new String[] {"v10", "version", "Version.class"}
+                new String[]{"v10", "version", "Version.class"}
         );
 
         compare(jarfile, names);
 
-        delete(jarfile);
-        deleteDir(Paths.get(usr, "classes"));
+        FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
+        FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
+    }
+
+    @Test
+    public void versionFormat() throws Throwable {
+        String jarfile = "test.jar";
+
+        compile("test01");
+
+        Path classes = Paths.get("classes");
+
+        // valid
+        for (String release : List.of("10000", "09", "00010", "10")) {
+            jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
+                    "--release", release, "-C", classes.resolve("v10").toString(), ".")
+                    .shouldHaveExitValue(SUCCESS)
+                    .shouldBeEmpty();
+        }
+        // invalid
+        for (String release : List.of("9.0", "8", "v9",
+                "9v", "0", "-10")) {
+            jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
+                    "--release", release, "-C", classes.resolve("v10").toString(), ".")
+                    .shouldNotHaveExitValue(SUCCESS)
+                    .shouldContain("release " + release + " not valid");
+        }
+        FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
+        FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
     }
 
     @Test
     // update a regular jar to a multi-release jar
-    public void test02() throws IOException {
+    public void test02() throws Throwable {
         String jarfile = "test.jar";
 
         compile("test01");  //use same data as test01
 
         Path classes = Paths.get("classes");
         jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".")
-                .assertSuccess();
+                .shouldHaveExitValue(SUCCESS);
 
         checkMultiRelease(jarfile, false);
 
-        jar("uf", jarfile, "--release", "9", "-C", classes.resolve("v9").toString(), ".")
-                .assertSuccess();
+        jar("uf", jarfile,
+                "--release", "9", "-C", classes.resolve("v9").toString(), ".")
+                .shouldHaveExitValue(SUCCESS);
 
         checkMultiRelease(jarfile, true);
 
-        Map<String,String[]> names = Map.of(
+        Map<String, String[]> names = Map.of(
                 "version/Main.class",
-                new String[] {"base", "version", "Main.class"},
+                new String[]{"base", "version", "Main.class"},
 
                 "version/Version.class",
-                new String[] {"base", "version", "Version.class"},
+                new String[]{"base", "version", "Version.class"},
 
                 "META-INF/versions/9/version/Version.class",
-                new String[] {"v9", "version", "Version.class"}
+                new String[]{"v9", "version", "Version.class"}
         );
 
         compare(jarfile, names);
 
-        delete(jarfile);
-        deleteDir(Paths.get(usr, "classes"));
+        FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
+        FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
     }
 
     @Test
     // replace a base entry and a versioned entry
-    public void test03() throws IOException {
+    public void test03() throws Throwable {
         String jarfile = "test.jar";
 
         compile("test01");  //use same data as test01
@@ -163,19 +181,19 @@
         Path classes = Paths.get("classes");
         jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
                 "--release", "9", "-C", classes.resolve("v9").toString(), ".")
-                .assertSuccess();
+                .shouldHaveExitValue(SUCCESS);
 
         checkMultiRelease(jarfile, true);
 
-        Map<String,String[]> names = Map.of(
+        Map<String, String[]> names = Map.of(
                 "version/Main.class",
-                new String[] {"base", "version", "Main.class"},
+                new String[]{"base", "version", "Main.class"},
 
                 "version/Version.class",
-                new String[] {"base", "version", "Version.class"},
+                new String[]{"base", "version", "Version.class"},
 
                 "META-INF/versions/9/version/Version.class",
-                new String[] {"v9", "version", "Version.class"}
+                new String[]{"v9", "version", "Version.class"}
         );
 
         compare(jarfile, names);
@@ -184,25 +202,25 @@
         // version/Version.class entry in versions/9 section
         jar("uf", jarfile, "-C", classes.resolve("v9").toString(), "version",
                 "--release", "9", "-C", classes.resolve("v10").toString(), ".")
-                .assertSuccess();
+                .shouldHaveExitValue(SUCCESS);
 
         checkMultiRelease(jarfile, true);
 
         names = Map.of(
                 "version/Main.class",
-                new String[] {"base", "version", "Main.class"},
+                new String[]{"base", "version", "Main.class"},
 
                 "version/Version.class",
-                new String[] {"v9", "version", "Version.class"},
+                new String[]{"v9", "version", "Version.class"},
 
                 "META-INF/versions/9/version/Version.class",
-                new String[] {"v10", "version", "Version.class"}
+                new String[]{"v10", "version", "Version.class"}
         );
 
         compare(jarfile, names);
 
-        delete(jarfile);
-        deleteDir(Paths.get(usr, "classes"));
+        FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
+        FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
     }
 
     /*
@@ -211,7 +229,7 @@
 
     @Test
     // META-INF/versions/9 class has different api than base class
-    public void test04() throws IOException {
+    public void test04() throws Throwable {
         String jarfile = "test.jar";
 
         compile("test01");  //use same data as test01
@@ -224,18 +242,16 @@
 
         jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
                 "--release", "9", "-C", classes.resolve("v9").toString(), ".")
-                .assertFailure()
-                .resultChecker(r ->
-                    assertTrue(r.output.contains("different api from earlier"), r.output)
-                );
+                .shouldNotHaveExitValue(SUCCESS)
+                .shouldContain("different api from earlier");
 
-        delete(jarfile);
-        deleteDir(Paths.get(usr, "classes"));
+        FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
+        FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
     }
 
     @Test
     // META-INF/versions/9 contains an extra public class
-    public void test05() throws IOException {
+    public void test05() throws Throwable {
         String jarfile = "test.jar";
 
         compile("test01");  //use same data as test01
@@ -248,18 +264,16 @@
 
         jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
                 "--release", "9", "-C", classes.resolve("v9").toString(), ".")
-                .assertFailure()
-                .resultChecker(r ->
-                        assertTrue(r.output.contains("contains a new public class"), r.output)
-                );
+                .shouldNotHaveExitValue(SUCCESS)
+                .shouldContain("contains a new public class");
 
-        delete(jarfile);
-        deleteDir(Paths.get(usr, "classes"));
+        FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
+        FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
     }
 
     @Test
     // META-INF/versions/9 contains an extra package private class -- this is okay
-    public void test06() throws IOException {
+    public void test06() throws Throwable {
         String jarfile = "test.jar";
 
         compile("test01");  //use same data as test01
@@ -272,16 +286,16 @@
 
         jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
                 "--release", "9", "-C", classes.resolve("v9").toString(), ".")
-                .assertSuccess();
+                .shouldHaveExitValue(SUCCESS);
 
-        delete(jarfile);
-        deleteDir(Paths.get(usr, "classes"));
+        FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
+        FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
     }
 
     @Test
     // META-INF/versions/9 contains an identical class to base entry class
     // this is okay but produces warning
-    public void test07() throws IOException {
+    public void test07() throws Throwable {
         String jarfile = "test.jar";
 
         compile("test01");  //use same data as test01
@@ -294,19 +308,42 @@
 
         jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
                 "--release", "9", "-C", classes.resolve("v9").toString(), ".")
-                .assertSuccess()
-                .resultChecker(r ->
-                        assertTrue(r.outputContains("contains a class that is identical"), r.output)
-                );
+                .shouldHaveExitValue(SUCCESS)
+                .shouldContain("contains a class that")
+                .shouldContain("is identical");
 
-        delete(jarfile);
-        deleteDir(Paths.get(usr, "classes"));
+        FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
+        FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
+    }
+
+    @Test
+    // META-INF/versions/9 contains an identical class to previous version entry class
+    // this is okay but produces warning
+    public void identicalClassToPreviousVersion() throws Throwable {
+        String jarfile = "test.jar";
+
+        compile("test01");  //use same data as test01
+
+        Path classes = Paths.get("classes");
+
+        jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
+                "--release", "9", "-C", classes.resolve("v9").toString(), ".")
+                .shouldHaveExitValue(SUCCESS)
+                .shouldBeEmpty();
+        jar("uf", jarfile,
+                "--release", "10", "-C", classes.resolve("v9").toString(), ".")
+                .shouldHaveExitValue(SUCCESS)
+                .shouldContain("contains a class that")
+                .shouldContain("is identical");
+
+        FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
+        FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
     }
 
     @Test
     // resources with same name in different versions
     // this is okay but produces warning
-    public void test08() throws IOException {
+    public void test08() throws Throwable {
         String jarfile = "test.jar";
 
         compile("test01");  //use same data as test01
@@ -320,10 +357,8 @@
 
         jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
                 "--release", "9", "-C", classes.resolve("v9").toString(), ".")
-                .assertSuccess()
-                .resultChecker(r ->
-                        assertTrue(r.output.isEmpty(), r.output)
-                );
+                .shouldHaveExitValue(SUCCESS)
+                .shouldBeEmpty();
 
         // now add a different resource with same name to META-INF/version/9
         Files.copy(source.resolve("Main.java"), classes.resolve("v9")
@@ -331,18 +366,16 @@
 
         jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
                 "--release", "9", "-C", classes.resolve("v9").toString(), ".")
-                .assertSuccess()
-                .resultChecker(r ->
-                        assertTrue(r.output.contains("multiple resources with same name"), r.output)
-                );
+                .shouldHaveExitValue(SUCCESS)
+                .shouldContain("multiple resources with same name");
 
-        delete(jarfile);
-        deleteDir(Paths.get(usr, "classes"));
+        FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
+        FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
     }
 
     @Test
     // a class with an internal name different from the external name
-    public void test09() throws IOException {
+    public void test09() throws Throwable {
         String jarfile = "test.jar";
 
         compile("test01");  //use same data as test01
@@ -355,18 +388,16 @@
 
         jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
                 "--release", "9", "-C", classes.resolve("v9").toString(), ".")
-                .assertFailure()
-                .resultChecker(r ->
-                        assertTrue(r.output.contains("names do not match"), r.output)
-                );
+                .shouldNotHaveExitValue(SUCCESS)
+                .shouldContain("names do not match");
 
-        delete(jarfile);
-        deleteDir(Paths.get(usr, "classes"));
+        FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
+        FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
     }
 
     @Test
     // assure that basic nested classes are acceptable
-    public void test10() throws IOException {
+    public void test10() throws Throwable {
         String jarfile = "test.jar";
 
         compile("test01");  //use same data as test01
@@ -383,15 +414,15 @@
 
         jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
                 "--release", "9", "-C", classes.resolve("v9").toString(), ".")
-                .assertSuccess();
+                .shouldHaveExitValue(SUCCESS);
 
-        delete(jarfile);
-        deleteDir(Paths.get(usr, "classes"));
+        FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
+        FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
     }
 
     @Test
     // a base entry contains a nested class that doesn't have a matching top level class
-    public void test11() throws IOException {
+    public void test11() throws Throwable {
         String jarfile = "test.jar";
 
         compile("test01");  //use same data as test01
@@ -409,30 +440,29 @@
         source = Paths.get(src, "data", "test10", "v9", "version");
         javac(classes.resolve("v9"), source.resolve("Nested.java"));
 
-        jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
+        List<String> output = jar("cf", jarfile,
+                "-C", classes.resolve("base").toString(), ".",
                 "--release", "9", "-C", classes.resolve("v9").toString(), ".")
-                .assertFailure()
-                .resultChecker(r -> {
-                    String[] msg = r.output.split("\\R");
-                    // There should be 3 error messages, cascading from the first.  Once we
-                    // remove the base top level class, the base nested class becomes isolated,
-                    // also the versioned top level class becomes a new public class, thus ignored
-                    // for subsequent checks, leading to the associated versioned nested class
-                    // becoming an isolated nested class
-                    assertTrue(msg.length == 4);
-                    assertTrue(msg[0].contains("an isolated nested class"), msg[0]);
-                    assertTrue(msg[1].contains("contains a new public class"), msg[1]);
-                    assertTrue(msg[2].contains("an isolated nested class"), msg[2]);
-                    assertTrue(msg[3].contains("invalid multi-release jar file"), msg[3]);
-                });
+                .shouldNotHaveExitValue(SUCCESS)
+                .asLines();
 
-        delete(jarfile);
-        deleteDir(Paths.get(usr, "classes"));
+        assertTrue(output.size() == 4);
+        assertTrue(output.get(0).contains("an isolated nested class"),
+                output.get(0));
+        assertTrue(output.get(1).contains("contains a new public class"),
+                output.get(1));
+        assertTrue(output.get(2).contains("an isolated nested class"),
+                output.get(2));
+        assertTrue(output.get(3).contains("invalid multi-release jar file"),
+                output.get(3));
+
+        FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
+        FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
     }
 
     @Test
     // a versioned entry contains a nested class that doesn't have a matching top level class
-    public void test12() throws IOException {
+    public void test12() throws Throwable {
         String jarfile = "test.jar";
 
         compile("test01");  //use same data as test01
@@ -452,178 +482,59 @@
 
         jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
                 "--release", "9", "-C", classes.resolve("v9").toString(), ".")
-                .assertFailure()
-                .resultChecker(r ->
-                        assertTrue(r.outputContains("an isolated nested class"), r.output)
-                );
+                .shouldNotHaveExitValue(SUCCESS)
+                .shouldContain("an isolated nested class");
 
-        delete(jarfile);
-        deleteDir(Paths.get(usr, "classes"));
+        FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
+        FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
     }
 
-    /*
-     *  Test Infrastructure
-     */
-    private void compile(String test) throws IOException {
-        Path classes = Paths.get(usr, "classes", "base");
-        Files.createDirectories(classes);
-        Path source = Paths.get(src, "data", test, "base", "version");
-        javac(classes, source.resolve("Main.java"), source.resolve("Version.java"));
+    @Test
+    public void testCustomManifest() throws Throwable {
+        String jarfile = "test.jar";
 
-        classes = Paths.get(usr, "classes", "v9");
-        Files.createDirectories(classes);
-        source = Paths.get(src, "data", test, "v9", "version");
-        javac(classes, source.resolve("Version.java"));
+        compile("test01");
 
-        classes = Paths.get(usr, "classes", "v10");
-        Files.createDirectories(classes);
-        source = Paths.get(src, "data", test, "v10", "version");
-        javac(classes, source.resolve("Version.java"));
-    }
+        Path classes = Paths.get("classes");
+        Path manifest = Paths.get("Manifest.txt");
 
-    private void checkMultiRelease(String jarFile, boolean expected) throws IOException {
-        try (JarFile jf = new JarFile(new File(jarFile), true, ZipFile.OPEN_READ,
-                JarFile.runtimeVersion())) {
-            assertEquals(jf.isMultiRelease(), expected);
-        }
-    }
+        // create
+        Files.write(manifest, "Class-Path: MyUtils.jar\n".getBytes());
 
-    // compares the bytes found in the jar entries with the bytes found in the
-    // corresponding data files used to create the entries
-    private void compare(String jarfile, Map<String,String[]> names) throws IOException {
-        try (JarFile jf = new JarFile(jarfile)) {
-            for (String name : names.keySet()) {
-                Path path = Paths.get("classes", names.get(name));
-                byte[] b1 = Files.readAllBytes(path);
-                byte[] b2;
-                JarEntry je = jf.getJarEntry(name);
-                try (InputStream is = jf.getInputStream(je)) {
-                    b2 = is.readAllBytes();
-                }
-                assertEquals(b1,b2);
-            }
-        }
-    }
+        jar("cfm", jarfile, manifest.toString(),
+                "-C", classes.resolve("base").toString(), ".",
+                "--release", "10", "-C", classes.resolve("v10").toString(), ".")
+                .shouldHaveExitValue(SUCCESS)
+                .shouldBeEmpty();
 
-    private void delete(String name) throws IOException {
-        Files.deleteIfExists(Paths.get(usr, name));
-    }
-
-    private void deleteDir(Path dir) throws IOException {
-        Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
-            @Override
-            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
-                Files.delete(file);
-                return FileVisitResult.CONTINUE;
-            }
-
-            @Override
-            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
-                Files.delete(dir);
-                return FileVisitResult.CONTINUE;
-            }
-        });
-    }
-
-    /*
-     * The following methods were taken from modular jar and other jar tests
-     */
-
-    void javac(Path dest, Path... sourceFiles) throws IOException {
-        String javac = JDKToolFinder.getJDKTool("javac");
-
-        List<String> commands = new ArrayList<>();
-        commands.add(javac);
-        String opts = System.getProperty("test.compiler.opts");
-        if (!opts.isEmpty()) {
-            commands.addAll(Arrays.asList(opts.split(" +")));
-        }
-        commands.add("-d");
-        commands.add(dest.toString());
-        Stream.of(sourceFiles).map(Object::toString).forEach(x -> commands.add(x));
-
-        quickFail(run(new ProcessBuilder(commands)));
-    }
-
-    Result jarWithStdin(File stdinSource, String... args) {
-        String jar = JDKToolFinder.getJDKTool("jar");
-        List<String> commands = new ArrayList<>();
-        commands.add(jar);
-        commands.addAll(Utils.getForwardVmOptions());
-        Stream.of(args).forEach(x -> commands.add(x));
-        ProcessBuilder p = new ProcessBuilder(commands);
-        if (stdinSource != null)
-            p.redirectInput(stdinSource);
-        return run(p);
-    }
-
-    Result jar(String... args) {
-        return jarWithStdin(null, args);
-    }
-
-    void quickFail(Result r) {
-        if (r.ec != 0)
-            throw new RuntimeException(r.output);
-    }
-
-    Result run(ProcessBuilder pb) {
-        Process p;
-        out.printf("Running: %s%n", pb.command());
-        try {
-            p = pb.start();
-        } catch (IOException e) {
-            throw new RuntimeException(
-                    format("Couldn't start process '%s'", pb.command()), e);
+        try (JarFile jf = new JarFile(new File(jarfile), true,
+                ZipFile.OPEN_READ, JarFile.runtimeVersion())) {
+            assertTrue(jf.isMultiRelease(), "Not multi-release jar");
+            assertEquals(jf.getManifest()
+                            .getMainAttributes()
+                            .getValue("Class-Path"),
+                    "MyUtils.jar");
         }
 
-        String output;
-        try {
-            output = toString(p.getInputStream(), p.getErrorStream());
-        } catch (IOException e) {
-            throw new RuntimeException(
-                    format("Couldn't read process output '%s'", pb.command()), e);
+        // update
+        Files.write(manifest, "Multi-release: false\n".getBytes());
+
+        jar("ufm", jarfile, manifest.toString(),
+                "-C", classes.resolve("base").toString(), ".",
+                "--release", "9", "-C", classes.resolve("v10").toString(), ".")
+                .shouldHaveExitValue(SUCCESS)
+                .shouldContain("WARNING: Duplicate name in Manifest: Multi-release.");
+
+        try (JarFile jf = new JarFile(new File(jarfile), true,
+                ZipFile.OPEN_READ, JarFile.runtimeVersion())) {
+            assertTrue(jf.isMultiRelease(), "Not multi-release jar");
+            assertEquals(jf.getManifest()
+                            .getMainAttributes()
+                            .getValue("Class-Path"),
+                    "MyUtils.jar");
         }
 
-        try {
-            p.waitFor();
-        } catch (InterruptedException e) {
-            throw new RuntimeException(
-                    format("Process hasn't finished '%s'", pb.command()), e);
-        }
-        return new Result(p.exitValue(), output);
-    }
-
-    String toString(InputStream in1, InputStream in2) throws IOException {
-        try (ByteArrayOutputStream dst = new ByteArrayOutputStream();
-             InputStream concatenated = new SequenceInputStream(in1, in2)) {
-            concatenated.transferTo(dst);
-            return new String(dst.toByteArray(), "UTF-8");
-        }
-    }
-
-    static class Result {
-        final int ec;
-        final String output;
-
-        private Result(int ec, String output) {
-            this.ec = ec;
-            this.output = output;
-        }
-
-        boolean outputContains(String msg) {
-            return Arrays.stream(output.split("\\R"))
-                         .collect(Collectors.joining(" "))
-                         .contains(msg);
-        }
-
-        Result assertSuccess() {
-            assertTrue(ec == 0, format("ec: %d, output: %s", ec, output));
-            return this;
-        }
-        Result assertFailure() {
-            assertTrue(ec != 0, format("ec: %d, output: %s", ec, output));
-            return this;
-        }
-        Result resultChecker(Consumer<Result> r) { r.accept(this); return this; }
+        FileUtils.deleteFileIfExistsWithRetry(Paths.get(jarfile));
+        FileUtils.deleteFileTreeWithRetry(Paths.get(usr, "classes"));
     }
 }
--- a/test/tools/jar/multiRelease/Basic1.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/tools/jar/multiRelease/Basic1.java	Fri Jan 20 08:53:42 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
@@ -28,76 +28,65 @@
  *          jdk.compiler
  *          jdk.jartool
  * @build jdk.test.lib.JDKToolFinder jdk.test.lib.Utils
+ * @build MRTestBase
  * @run testng Basic1
  */
 
-import static org.testng.Assert.*;
-
 import org.testng.annotations.*;
 
-import java.io.*;
 import java.nio.file.*;
 import java.util.*;
-import java.util.function.Consumer;
-import java.util.jar.*;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-import java.util.zip.*;
 
-import jdk.test.lib.JDKToolFinder;
-import jdk.test.lib.Utils;
-
-
-import static java.lang.String.format;
-import static java.lang.System.out;
-
-public class Basic1 {
-    private final String src = System.getProperty("test.src", ".");
+public class Basic1 extends MRTestBase {
 
     @BeforeTest
-    public void setup() throws IOException {
+    public void setup() throws Throwable {
         String test = "test01";
-        Path classes = Paths.get("classes", "base");
-        Files.createDirectories(classes);
+        Path classes = Paths.get("classes");
+
+        Path base = classes.resolve("base");
+        Files.createDirectories(base);
         Path source = Paths.get(src, "data", test, "base", "version");
-        javac(classes, source.resolve("Main.java"), source.resolve("Version.java"));
+        javac(base, source.resolve("Main.java"), source.resolve("Version.java"));
 
-        Path v9 = Paths.get("v9");
+        Path v9 = classes.resolve("v9");
         Files.createDirectories(v9);
         source = Paths.get(src, "data", test, "v9", "version");
         javac(v9, source.resolve("Version.java"));
 
-        Path v10 = Paths.get("v10");
+        Path v10 = classes.resolve("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");
+        Path v10_1 = classes.resolve("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
-    public void test() throws IOException {
+    public void test() throws Throwable {
         String jarfile = "test.jar";
         Path classes = Paths.get("classes");
-        Path v9 = Paths.get("v9");
-        Path v10 = Paths.get("v10");
 
-        jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
-            "--release", "9", "-C", v9.toString(), ".",
-            "--release", "10", "-C", v10.toString(), ".")
-            .assertSuccess();
+        Path base = classes.resolve("base");
+        Path v9 = classes.resolve("v9");
+        Path v10 = classes.resolve("v10");
+
+        jar("cf", jarfile, "-C", base.toString(), ".",
+                "--release", "9", "-C", v9.toString(), ".",
+                "--release", "10", "-C", v10.toString(), ".")
+                .shouldHaveExitValue(SUCCESS);
 
         checkMultiRelease(jarfile, true);
 
-        Map<String,String[]> names = Map.of(
-            "version/Main.class",
-            new String[] {"classes", "base", "version", "Main.class"},
+        Map<String, String[]> names = Map.of(
+                "version/Main.class",
+                new String[]{"base", "version", "Main.class"},
 
-            "version/Version.class",
-            new String[] {"classes", "base", "version", "Version.class"},
+                "version/Version.class",
+                new String[]{"base", "version", "Version.class"},
 
             "META-INF/versions/9/version/Version.class",
             new String[] {"v9", "version", "Version.class"},
@@ -109,144 +98,16 @@
         compare(jarfile, names);
     }
 
-
     @Test
-    public void testFail() throws IOException {
+    public void testFail() throws Throwable {
         String jarfile = "test.jar";
         Path classes = Paths.get("classes");
-        Path v10 = Paths.get("v10_1");
+        Path base = classes.resolve("base");
+        Path v10 = classes.resolve("v10_1");
 
-        jar("cf", jarfile, "-C", classes.resolve("base").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())) {
-            assertEquals(jf.isMultiRelease(), expected);
-        }
-    }
-
-    // compares the bytes found in the jar entries with the bytes found in the
-    // corresponding data files used to create the entries
-    private void compare(String jarfile, Map<String,String[]> names) throws IOException {
-        try (JarFile jf = new JarFile(jarfile)) {
-            for (String name : names.keySet()) {
-                Path path = Paths.get("", names.get(name));
-                byte[] b1 = Files.readAllBytes(path);
-                byte[] b2;
-                JarEntry je = jf.getJarEntry(name);
-                try (InputStream is = jf.getInputStream(je)) {
-                    b2 = is.readAllBytes();
-                }
-                assertEquals(b1,b2);
-            }
-        }
-    }
-
-    /*
-     * The following methods were taken from modular jar and other jar tests
-     */
-
-    void javac(Path dest, Path... sourceFiles) throws IOException {
-        String javac = JDKToolFinder.getJDKTool("javac");
-
-        List<String> commands = new ArrayList<>();
-        commands.add(javac);
-        String opts = System.getProperty("test.compiler.opts");
-        if (!opts.isEmpty()) {
-            commands.addAll(Arrays.asList(opts.split(" +")));
-        }
-        commands.add("-d");
-        commands.add(dest.toString());
-        Stream.of(sourceFiles).map(Object::toString).forEach(x -> commands.add(x));
-
-        quickFail(run(new ProcessBuilder(commands)));
-    }
-
-    Result jarWithStdin(File stdinSource, String... args) {
-        String jar = JDKToolFinder.getJDKTool("jar");
-        List<String> commands = new ArrayList<>();
-        commands.add(jar);
-        commands.addAll(Utils.getForwardVmOptions());
-        Stream.of(args).forEach(x -> commands.add(x));
-        ProcessBuilder p = new ProcessBuilder(commands);
-        if (stdinSource != null)
-            p.redirectInput(stdinSource);
-        return run(p);
-    }
-
-    Result jar(String... args) {
-        return jarWithStdin(null, args);
-    }
-
-    void quickFail(Result r) {
-        if (r.ec != 0)
-            throw new RuntimeException(r.output);
-    }
-
-    Result run(ProcessBuilder pb) {
-        Process p;
-        out.printf("Running: %s%n", pb.command());
-        try {
-            p = pb.start();
-        } catch (IOException e) {
-            throw new RuntimeException(
-                    format("Couldn't start process '%s'", pb.command()), e);
-        }
-
-        String output;
-        try {
-            output = toString(p.getInputStream(), p.getErrorStream());
-        } catch (IOException e) {
-            throw new RuntimeException(
-                    format("Couldn't read process output '%s'", pb.command()), e);
-        }
-
-        try {
-            p.waitFor();
-        } catch (InterruptedException e) {
-            throw new RuntimeException(
-                    format("Process hasn't finished '%s'", pb.command()), e);
-        }
-        return new Result(p.exitValue(), output);
-    }
-
-    String toString(InputStream in1, InputStream in2) throws IOException {
-        try (ByteArrayOutputStream dst = new ByteArrayOutputStream();
-             InputStream concatenated = new SequenceInputStream(in1, in2)) {
-            concatenated.transferTo(dst);
-            return new String(dst.toByteArray(), "UTF-8");
-        }
-    }
-
-    static class Result {
-        final int ec;
-        final String output;
-
-        private Result(int ec, String output) {
-            this.ec = ec;
-            this.output = output;
-        }
-
-        boolean outputContains(String msg) {
-            return Arrays.stream(output.split("\\R"))
-                         .collect(Collectors.joining(" "))
-                         .contains(msg);
-        }
-
-        Result assertSuccess() {
-            assertTrue(ec == 0, format("ec: %d, output: %s", ec, output));
-            return this;
-        }
-        Result assertFailure() {
-            assertTrue(ec != 0, format("ec: %d, output: %s", ec, output));
-            return this;
-        }
-        Result resultChecker(Consumer<Result> r) { r.accept(this); return this; }
+        jar("cf", jarfile, "-C", base.toString(), ".",
+                "--release", "10", "-C", v10.toString(), ".")
+                .shouldNotHaveExitValue(SUCCESS)
+                .shouldContain("unexpected versioned entry META-INF/versions/");
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jar/multiRelease/MRTestBase.java	Fri Jan 20 08:53:42 2017 -0800
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import jdk.test.lib.JDKToolFinder;
+import jdk.test.lib.Utils;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+import java.io.*;
+import java.nio.file.*;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.stream.Stream;
+import java.util.zip.ZipFile;
+
+import static org.testng.Assert.assertEquals;
+
+public class MRTestBase {
+
+    public static final int SUCCESS = 0;
+
+    protected final String src = System.getProperty("test.src", ".");
+    protected final String usr = System.getProperty("user.dir", ".");
+
+    protected void compile(String test) throws Throwable {
+        Path classes = Paths.get(usr, "classes", "base");
+        Files.createDirectories(classes);
+        Path source = Paths.get(src, "data", test, "base", "version");
+        javac(classes, source.resolve("Main.java"), source.resolve("Version.java"));
+
+        classes = Paths.get(usr, "classes", "v9");
+        Files.createDirectories(classes);
+        source = Paths.get(src, "data", test, "v9", "version");
+        javac(classes, source.resolve("Version.java"));
+
+        classes = Paths.get(usr, "classes", "v10");
+        Files.createDirectories(classes);
+        source = Paths.get(src, "data", test, "v10", "version");
+        javac(classes, source.resolve("Version.java"));
+    }
+
+    protected void checkMultiRelease(String jarFile,
+                                     boolean expected) throws IOException {
+        try (JarFile jf = new JarFile(new File(jarFile), true,
+                ZipFile.OPEN_READ, JarFile.runtimeVersion())) {
+            assertEquals(jf.isMultiRelease(), expected);
+        }
+    }
+
+    // compares the bytes found in the jar entries with the bytes found in the
+    // corresponding data files used to create the entries
+    protected void compare(String jarfile,
+                           Map<String, String[]> names) throws IOException {
+        try (JarFile jf = new JarFile(jarfile)) {
+            for (String name : names.keySet()) {
+                Path path = Paths.get("classes", names.get(name));
+                byte[] b1 = Files.readAllBytes(path);
+                byte[] b2;
+                JarEntry je = jf.getJarEntry(name);
+                try (InputStream is = jf.getInputStream(je)) {
+                    b2 = is.readAllBytes();
+                }
+                assertEquals(b1, b2);
+            }
+        }
+    }
+
+    void javac(Path dest, Path... sourceFiles) throws Throwable {
+        String javac = JDKToolFinder.getJDKTool("javac");
+
+        List<String> commands = new ArrayList<>();
+        commands.add(javac);
+        String opts = System.getProperty("test.compiler.opts");
+        if (!opts.isEmpty()) {
+            commands.addAll(Arrays.asList(opts.split(" +")));
+        }
+        commands.addAll(Utils.getForwardVmOptions());
+        commands.add("-d");
+        commands.add(dest.toString());
+        Stream.of(sourceFiles)
+                .map(Object::toString)
+                .forEach(x -> commands.add(x));
+
+        ProcessTools.executeCommand(new ProcessBuilder(commands))
+                .shouldHaveExitValue(SUCCESS);
+    }
+
+    OutputAnalyzer jarWithStdin(File stdinSource,
+                                String... args) throws Throwable {
+
+        String jar = JDKToolFinder.getJDKTool("jar");
+        List<String> commands = new ArrayList<>();
+        commands.add(jar);
+        commands.addAll(Utils.getForwardVmOptions());
+        Stream.of(args).forEach(x -> commands.add(x));
+        ProcessBuilder p = new ProcessBuilder(commands);
+        if (stdinSource != null)
+            p.redirectInput(stdinSource);
+        return ProcessTools.executeCommand(p);
+    }
+
+    OutputAnalyzer jar(String... args) throws Throwable {
+        return jarWithStdin(null, args);
+    }
+}
\ No newline at end of file
--- a/test/tools/jar/multiRelease/data/test04/v9/version/Version.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/tools/jar/multiRelease/data/test04/v9/version/Version.java	Fri Jan 20 08:53:42 2017 -0800
@@ -8,7 +8,7 @@
     protected void doNothing() {
     }
 
-    // extra publc method
+    // extra public method
     public void anyName() {
     }
 }
--- a/test/tools/jlink/DefaultProviderTest.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/tools/jlink/DefaultProviderTest.java	Fri Jan 20 08:53:42 2017 -0800
@@ -44,6 +44,7 @@
  * @modules java.base/jdk.internal.jimage
  *          jdk.jdeps/com.sun.tools.classfile
  *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink.plugin
  *          jdk.jlink/jdk.tools.jmod
  *          jdk.jlink/jdk.tools.jimage
  *          jdk.compiler
--- a/test/tools/jlink/ImageFileCreatorTest.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/tools/jlink/ImageFileCreatorTest.java	Fri Jan 20 08:53:42 2017 -0800
@@ -48,6 +48,7 @@
  * @author Jean-Francois Denise
  * @modules jdk.jlink/jdk.tools.jlink.internal
  *          jdk.jlink/jdk.tools.jlink.builder
+ *          jdk.jlink/jdk.tools.jlink.plugin
  *          java.base/jdk.internal.jimage
  * @run main/othervm -verbose:gc -Xmx1g ImageFileCreatorTest
  */
--- a/test/tools/jlink/ImageFilePoolTest.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/tools/jlink/ImageFilePoolTest.java	Fri Jan 20 08:53:42 2017 -0800
@@ -26,6 +26,7 @@
  * @summary Test a pool containing external files.
  * @author Andrei Eremeev
  * @modules jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink.plugin
  * @run build ImageFilePoolTest
  * @run main ImageFilePoolTest
  */
--- a/test/tools/jlink/IntegrationTest.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/tools/jlink/IntegrationTest.java	Fri Jan 20 08:53:42 2017 -0800
@@ -62,6 +62,7 @@
  *          jdk.jlink/jdk.tools.jlink.builder
  *          jdk.jlink/jdk.tools.jlink.internal
  *          jdk.jlink/jdk.tools.jlink.internal.plugins
+ *          jdk.jlink/jdk.tools.jlink.plugin
  *          jdk.jlink/jdk.tools.jmod
  *          jdk.jlink/jdk.tools.jimage
  *          jdk.compiler
--- a/test/tools/jlink/JLink2Test.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/tools/jlink/JLink2Test.java	Fri Jan 20 08:53:42 2017 -0800
@@ -29,6 +29,7 @@
  * @modules java.base/jdk.internal.jimage
  *          jdk.jdeps/com.sun.tools.classfile
  *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink.plugin
  *          jdk.jlink/jdk.tools.jmod
  *          jdk.jlink/jdk.tools.jimage
  *          jdk.compiler
--- a/test/tools/jlink/JLinkOptionsTest.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/tools/jlink/JLinkOptionsTest.java	Fri Jan 20 08:53:42 2017 -0800
@@ -39,6 +39,7 @@
  * @modules java.base/jdk.internal.jimage
  *          jdk.jdeps/com.sun.tools.classfile
  *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink.plugin
  *          jdk.jlink/jdk.tools.jmod
  *          jdk.jlink/jdk.tools.jimage
  *          jdk.compiler
--- a/test/tools/jlink/JLinkPostProcessingTest.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/tools/jlink/JLinkPostProcessingTest.java	Fri Jan 20 08:53:42 2017 -0800
@@ -46,6 +46,7 @@
  * @modules java.base/jdk.internal.jimage
  *          jdk.jdeps/com.sun.tools.classfile
  *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink.plugin
  *          jdk.jlink/jdk.tools.jmod
  *          jdk.jlink/jdk.tools.jimage
  *          jdk.compiler
--- a/test/tools/jlink/JLinkTest.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/tools/jlink/JLinkTest.java	Fri Jan 20 08:53:42 2017 -0800
@@ -48,6 +48,7 @@
  * @modules java.base/jdk.internal.jimage
  *          jdk.jdeps/com.sun.tools.classfile
  *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink.plugin
  *          jdk.jlink/jdk.tools.jimage
  *          jdk.compiler
  * @build tests.*
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/jlink/ResourceDuplicateCheckTest.java	Fri Jan 20 08:53:42 2017 -0800
@@ -0,0 +1,85 @@
+/*
+ * 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 8168254
+ * @summary Detect duplicated resources in packaged modules
+ * @modules jdk.jlink/jdk.tools.jlink.builder
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink.plugin
+ * @run build ResourceDuplicateCheckTest
+ * @run main ResourceDuplicateCheckTest
+ */
+
+import java.net.URI;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+import jdk.tools.jlink.builder.DefaultImageBuilder;
+import jdk.tools.jlink.internal.ResourcePoolEntryFactory;
+import jdk.tools.jlink.internal.ResourcePoolManager;
+import jdk.tools.jlink.plugin.PluginException;
+import jdk.tools.jlink.plugin.ResourcePoolEntry;
+
+public class ResourceDuplicateCheckTest {
+    public static void main(String[] args) throws Exception {
+        new ResourceDuplicateCheckTest().test();
+    }
+
+    public void test() throws Exception {
+        ResourcePoolManager input = new ResourcePoolManager();
+        // need java.base module info because OS name is retrieved from it from storeFiles
+        input.add(ResourcePoolEntryFactory.create("/java.base/module-info.class",
+                    ResourcePoolEntry.Type.CLASS_OR_RESOURCE, getJavaBaseModuleInfo()));
+
+        // same NATIVE_CMD from two different modules
+        input.add(newInMemoryImageFile("/com.acme/bin/myexec",
+                    ResourcePoolEntry.Type.NATIVE_CMD, "mylib"));
+        input.add(newInMemoryImageFile("/com.foo/bin/myexec",
+                    ResourcePoolEntry.Type.NATIVE_CMD, "mylib"));
+        Path root = Paths.get(System.getProperty("test.classes"));
+        DefaultImageBuilder writer = new DefaultImageBuilder(root, Collections.emptyMap());
+        try {
+            writer.storeFiles(input.resourcePool());
+        } catch (PluginException pe) {
+            if (! pe.getMessage().contains("Duplicate resources:")) {
+                throw new AssertionError("expected duplicate resources message");
+            }
+        }
+    }
+
+    private byte[] getJavaBaseModuleInfo() throws Exception {
+        Path path = FileSystems.
+                getFileSystem(URI.create("jrt:/")).
+                getPath("/modules/java.base/module-info.class");
+        return Files.readAllBytes(path);
+    }
+
+    private static ResourcePoolEntry newInMemoryImageFile(String path,
+            ResourcePoolEntry.Type type, String content) {
+        return ResourcePoolEntryFactory.create(path, type, content.getBytes());
+    }
+}
--- a/test/tools/jlink/ResourcePoolTest.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/tools/jlink/ResourcePoolTest.java	Fri Jan 20 08:53:42 2017 -0800
@@ -26,6 +26,7 @@
  * @summary Test a pool containing jimage resources and classes.
  * @author Jean-Francois Denise
  * @modules jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink.plugin
  * @run build ResourcePoolTest
  * @run main ResourcePoolTest
  */
--- a/test/tools/jlink/plugins/CompressorPluginTest.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/tools/jlink/plugins/CompressorPluginTest.java	Fri Jan 20 08:53:42 2017 -0800
@@ -28,6 +28,7 @@
  * @modules java.base/jdk.internal.jimage.decompressor
  *          jdk.jlink/jdk.tools.jlink.internal
  *          jdk.jlink/jdk.tools.jlink.internal.plugins
+ *          jdk.jlink/jdk.tools.jlink.plugin
  * @run main CompressorPluginTest
  */
 import java.net.URI;
--- a/test/tools/jlink/plugins/ExcludeFilesPluginTest.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/tools/jlink/plugins/ExcludeFilesPluginTest.java	Fri Jan 20 08:53:42 2017 -0800
@@ -27,6 +27,7 @@
  * @author Jean-Francois Denise
  * @modules jdk.jlink/jdk.tools.jlink.internal
  *          jdk.jlink/jdk.tools.jlink.internal.plugins
+ *          jdk.jlink/jdk.tools.jlink.plugin
  * @run main ExcludeFilesPluginTest
  */
 
--- a/test/tools/jlink/plugins/ExcludePluginTest.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/tools/jlink/plugins/ExcludePluginTest.java	Fri Jan 20 08:53:42 2017 -0800
@@ -27,6 +27,7 @@
  * @author Jean-Francois Denise
  * @modules jdk.jlink/jdk.tools.jlink.internal
  *          jdk.jlink/jdk.tools.jlink.internal.plugins
+ *          jdk.jlink/jdk.tools.jlink.plugin
  * @run main ExcludePluginTest
  */
 
--- a/test/tools/jlink/plugins/ExcludeVMPluginTest.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/tools/jlink/plugins/ExcludeVMPluginTest.java	Fri Jan 20 08:53:42 2017 -0800
@@ -27,6 +27,7 @@
  * @author Jean-Francois Denise
  * @modules jdk.jlink/jdk.tools.jlink.internal
  *          jdk.jlink/jdk.tools.jlink.internal.plugins
+ *          jdk.jlink/jdk.tools.jlink.plugin
  * @run main ExcludeVMPluginTest
  */
 import java.io.ByteArrayInputStream;
--- a/test/tools/jlink/plugins/IncludeLocalesPluginTest.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/tools/jlink/plugins/IncludeLocalesPluginTest.java	Fri Jan 20 08:53:42 2017 -0800
@@ -48,6 +48,7 @@
  *          jdk.jdeps/com.sun.tools.classfile
  *          jdk.jlink/jdk.tools.jlink.internal
  *          jdk.jlink/jdk.tools.jlink.internal.plugins
+ *          jdk.jlink/jdk.tools.jlink.plugin
  *          jdk.jlink/jdk.tools.jmod
  *          jdk.jlink/jdk.tools.jimage
  *          jdk.compiler
--- a/test/tools/jlink/plugins/LastSorterTest.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/tools/jlink/plugins/LastSorterTest.java	Fri Jan 20 08:53:42 2017 -0800
@@ -25,8 +25,9 @@
  * @test
  * @summary Test last sorter property
  * @author Jean-Francois Denise
- * @modules jdk.jlink/jdk.tools.jlink.internal
- *          jdk.jlink/jdk.tools.jlink
+ * @modules jdk.jlink/jdk.tools.jlink
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jlink.plugin
  * @run main/othervm LastSorterTest
  */
 
--- a/test/tools/jlink/plugins/PluginsNegativeTest.java	Fri Jan 20 10:28:34 2017 -0800
+++ b/test/tools/jlink/plugins/PluginsNegativeTest.java	Fri Jan 20 08:53:42 2017 -0800
@@ -25,8 +25,9 @@
  * @test
  * @summary Negative test for ImagePluginStack.
  * @author Andrei Eremeev
- * @modules jdk.jlink/jdk.tools.jlink.internal
- *          jdk.jlink/jdk.tools.jlink
+ * @modules jdk.jlink/jdk.tools.jlink