Merge
authorduke
Wed, 05 Jul 2017 19:11:53 +0200
changeset 19878 fe0f0d3c2cce
parent 19877 78407de2df2f (current diff)
parent 19873 21656ecbe8bc (diff)
child 19900 00601f164a6f
Merge
jdk/src/share/classes/java/util/stream/CloseableStream.java
jdk/src/share/classes/java/util/stream/DelegatingStream.java
jdk/test/java/util/Collection/ListDefaults.java
jdk/test/java/util/Map/CheckRandomHashSeed.java
jdk/test/java/util/Map/TreeBinSplitBackToEntries.java
jdk/test/java/util/concurrent/ConcurrentHashMap/toArray.java
jdk/test/sun/tools/jconsole/ImmutableResourceTest.java
jdk/test/sun/tools/jconsole/ImmutableResourceTest.sh
--- a/.hgtags-top-repo	Tue Sep 17 08:08:07 2013 -0700
+++ b/.hgtags-top-repo	Wed Jul 05 19:11:53 2017 +0200
@@ -228,3 +228,4 @@
 96c1b9b7524b52c3fcefc90ffad4c767396727c8 jdk8-b104
 5166118c59178b5d31001bc4058e92486ee07d9b jdk8-b105
 8e7b4d9fb00fdf1334376aeac050c9bca6d1b383 jdk8-b106
+0874bb4707b723d5bb108d379c557cf41529d1a7 jdk8-b107
--- a/Makefile	Tue Sep 17 08:08:07 2013 -0700
+++ b/Makefile	Wed Jul 05 19:11:53 2017 +0200
@@ -404,7 +404,6 @@
 CACERTS_FILE.desc          = Location of certificates file
 DEVTOOLS_PATH.desc         = Directory containing zip and gnumake
 CUPS_HEADERS_PATH.desc     = Include directory location for CUPS header files
-DXSDK_PATH.desc            = Root directory of DirectX SDK
 
 # Make variables to print out (description and value)
 VARIABLE_PRINTVAL_LIST +=       \
@@ -429,17 +428,6 @@
 VARIABLE_CHECKFIL_LIST +=       \
     CACERTS_FILE
 
-# Some are windows specific
-ifeq ($(PLATFORM), windows)
-
-VARIABLE_PRINTVAL_LIST +=       \
-    DXSDK_PATH
-
-VARIABLE_CHECKDIR_LIST +=       \
-    DXSDK_PATH
-
-endif
-
 # For pattern rules below, so all are treated the same
 DO_PRINTVAL_LIST=$(VARIABLE_PRINTVAL_LIST:%=%.printval)
 DO_CHECKDIR_LIST=$(VARIABLE_CHECKDIR_LIST:%=%.checkdir)
--- a/README-builds.html	Tue Sep 17 08:08:07 2013 -0700
+++ b/README-builds.html	Wed Jul 05 19:11:53 2017 +0200
@@ -444,10 +444,6 @@
                                         Install
                                         <a href="#vs2010">Visual Studio 2010</a>
                                     </li>
-                                    <li>
-                                        Install the
-                                        <a href="#dxsdk">Microsoft DirectX SDK</a>
-                                    </li>
                                 </ul>
                             </td>
                             <td>
@@ -972,25 +968,6 @@
                                 </td>
                             </tr>       
                             <tr>
-                                <td><b><code>--with-dxsdk=</code></b><i>path</i></td>
-                                <td>
-                                    select location of the Windows Direct X SDK install
-                                    <br>
-                                    The <a name="dxsdk">Microsoft DirectX 9.0 SDK</a>
-                                    header files and libraries
-                                    from the Summer 2004 edition
-                                    are required for building OpenJDK.
-                                    This SDK can be downloaded from 
-                                    <a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=FD044A42-9912-42A3-9A9E-D857199F888E&amp;displaylang=en" target="_blank">
-                                        Microsoft DirectX 9.0 SDK (Summer 2004)</a>.
-                                    If the link above becomes obsolete, the SDK can be found from 
-                                    <a href="http://download.microsoft.com" target="_blank">the Microsoft Download Site</a>
-                                    (search with "DirectX 9.0 SDK Update Summer 2004"). 
-                                    Installation usually will set the environment variable
-                                    <code>DXSDK_DIR</code> to it's install location.
-                                </td>
-                            </tr>       
-                            <tr>
                                 <td><b><code>--with-freetype=</code></b><i>path</i></td>
                                 <td>
                                     select the freetype files to use.
--- a/common/autoconf/basics.m4	Tue Sep 17 08:08:07 2013 -0700
+++ b/common/autoconf/basics.m4	Wed Jul 05 19:11:53 2017 +0200
@@ -203,6 +203,15 @@
     fi
 ])
 
+# Register a --with argument but mark it as deprecated
+# $1: The name of the with argument to deprecate, not including --with-
+AC_DEFUN([BASIC_DEPRECATED_ARG_WITH],
+[
+  AC_ARG_WITH($1, [AS_HELP_STRING([--with-$1],
+      [Deprecated. Option is kept for backwards compatibility and is ignored])],
+      [AC_MSG_WARN([Option --with-$1 is deprecated and will be ignored.])])
+])
+
 AC_DEFUN_ONCE([BASIC_INIT],
 [
 # Save the original command line. This is passed to us by the wrapper configure script.
--- a/common/autoconf/basics_windows.m4	Tue Sep 17 08:08:07 2013 -0700
+++ b/common/autoconf/basics_windows.m4	Wed Jul 05 19:11:53 2017 +0200
@@ -211,7 +211,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
--- a/common/autoconf/build-aux/autoconf-config.guess	Tue Sep 17 08:08:07 2013 -0700
+++ b/common/autoconf/build-aux/autoconf-config.guess	Wed Jul 05 19:11:53 2017 +0200
@@ -26,10 +26,10 @@
 
 # Attempt to guess a canonical system name.
 #   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
-#   Free Software Foundation, Inc.
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+#   2011, 2012 Free Software Foundation, Inc.
 
-timestamp='2008-01-23'
+timestamp='2012-02-10'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -42,9 +42,7 @@
 # General Public License for more details.
 #
 # You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
-# 02110-1301, USA.
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
 #
 # As a special exception to the GNU General Public License, if you
 # distribute this file as part of a program that contains a
@@ -52,16 +50,16 @@
 # the same distribution terms that you use for the rest of that program.
 
 
-# Originally written by Per Bothner <per@bothner.com>.
-# Please send patches to <config-patches@gnu.org>.  Submit a context
-# diff and a properly formatted ChangeLog entry.
+# Originally written by Per Bothner.  Please send patches (context
+# diff format) to <config-patches@gnu.org> and include a ChangeLog
+# entry.
 #
 # This script attempts to guess a canonical system name similar to
 # config.sub.  If it succeeds, it prints the system name on stdout, and
 # exits with 0.  Otherwise, it exits with 1.
 #
-# The plan is that this can be called by configure scripts if you
-# don't specify an explicit build system type.
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
 
 me=`echo "$0" | sed -e 's,.*/,,'`
 
@@ -81,8 +79,9 @@
 GNU config.guess ($timestamp)
 
 Originally written by Per Bothner.
-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
+Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -169,7 +168,7 @@
 case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
     *:NetBSD:*:*)
 	# NetBSD (nbsd) targets should (where applicable) match one or
-	# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+	# more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
 	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
 	# switched to ELF, *-*-netbsd* would select the old
 	# object file format.  This provides both forward
@@ -195,7 +194,7 @@
 	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
 		eval $set_cc_for_build
 		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
-			| grep __ELF__ >/dev/null
+			| grep -q __ELF__
 		then
 		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
 		    # Return netbsd for either.  FIX?
@@ -205,7 +204,7 @@
 		fi
 		;;
 	    *)
-	        os=netbsd
+		os=netbsd
 		;;
 	esac
 	# The OS release
@@ -248,7 +247,7 @@
 		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
 		;;
 	*5.*)
-	        UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
 		;;
 	esac
 	# According to Compaq, /usr/sbin/psrinfo has been available on
@@ -294,7 +293,10 @@
 	# A Xn.n version is an unreleased experimental baselevel.
 	# 1.2 uses "1.2" for uname -r.
 	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
-	exit ;;
+	# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+	exitcode=$?
+	trap '' 0
+	exit $exitcode ;;
     Alpha\ *:Windows_NT*:*)
 	# How do we know it's Interix rather than the generic POSIX subsystem?
 	# Should we change UNAME_MACHINE based on the output of uname instead
@@ -320,7 +322,7 @@
 	echo s390-ibm-zvmoe
 	exit ;;
     *:OS400:*:*)
-        echo powerpc-ibm-os400
+	echo powerpc-ibm-os400
 	exit ;;
     arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
 	echo arm-acorn-riscix${UNAME_RELEASE}
@@ -349,14 +351,33 @@
 	case `/usr/bin/uname -p` in
 	    sparc) echo sparc-icl-nx7; exit ;;
 	esac ;;
+    s390x:SunOS:*:*)
+	echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
     sun4H:SunOS:5.*:*)
 	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
 	exit ;;
     sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
 	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
 	exit ;;
+    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+	echo i386-pc-auroraux${UNAME_RELEASE}
+	exit ;;
     i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
-	echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	eval $set_cc_for_build
+	SUN_ARCH="i386"
+	# If there is a compiler, see if it is configured for 64-bit objects.
+	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+	# This test works for both compilers.
+	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		grep IS_64BIT_ARCH >/dev/null
+	    then
+		SUN_ARCH="x86_64"
+	    fi
+	fi
+	echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
 	exit ;;
     sun4*:SunOS:6*:*)
 	# According to config.sub, this is the proper way to canonicalize
@@ -400,23 +421,23 @@
     # MiNT.  But MiNT is downward compatible to TOS, so this should
     # be no problem.
     atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
-        echo m68k-atari-mint${UNAME_RELEASE}
+	echo m68k-atari-mint${UNAME_RELEASE}
 	exit ;;
     atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
 	echo m68k-atari-mint${UNAME_RELEASE}
-        exit ;;
+	exit ;;
     *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
-        echo m68k-atari-mint${UNAME_RELEASE}
+	echo m68k-atari-mint${UNAME_RELEASE}
 	exit ;;
     milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
-        echo m68k-milan-mint${UNAME_RELEASE}
-        exit ;;
+	echo m68k-milan-mint${UNAME_RELEASE}
+	exit ;;
     hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
-        echo m68k-hades-mint${UNAME_RELEASE}
-        exit ;;
+	echo m68k-hades-mint${UNAME_RELEASE}
+	exit ;;
     *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
-        echo m68k-unknown-mint${UNAME_RELEASE}
-        exit ;;
+	echo m68k-unknown-mint${UNAME_RELEASE}
+	exit ;;
     m68k:machten:*:*)
 	echo m68k-apple-machten${UNAME_RELEASE}
 	exit ;;
@@ -486,8 +507,8 @@
 	echo m88k-motorola-sysv3
 	exit ;;
     AViiON:dgux:*:*)
-        # DG/UX returns AViiON for all architectures
-        UNAME_PROCESSOR=`/usr/bin/uname -p`
+	# DG/UX returns AViiON for all architectures
+	UNAME_PROCESSOR=`/usr/bin/uname -p`
 	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
 	then
 	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
@@ -500,7 +521,7 @@
 	else
 	    echo i586-dg-dgux${UNAME_RELEASE}
 	fi
- 	exit ;;
+	exit ;;
     M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
 	echo m88k-dolphin-sysv3
 	exit ;;
@@ -557,7 +578,7 @@
 		echo rs6000-ibm-aix3.2
 	fi
 	exit ;;
-    *:AIX:*:[456])
+    *:AIX:*:[4567])
 	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
 	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
 		IBM_ARCH=rs6000
@@ -600,52 +621,52 @@
 	    9000/[678][0-9][0-9])
 		if [ -x /usr/bin/getconf ]; then
 		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
-                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
-                    case "${sc_cpu_version}" in
-                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
-                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
-                      532)                      # CPU_PA_RISC2_0
-                        case "${sc_kernel_bits}" in
-                          32) HP_ARCH="hppa2.0n" ;;
-                          64) HP_ARCH="hppa2.0w" ;;
+		    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+		    case "${sc_cpu_version}" in
+		      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+		      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+		      532)                      # CPU_PA_RISC2_0
+			case "${sc_kernel_bits}" in
+			  32) HP_ARCH="hppa2.0n" ;;
+			  64) HP_ARCH="hppa2.0w" ;;
 			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
-                        esac ;;
-                    esac
+			esac ;;
+		    esac
 		fi
 		if [ "${HP_ARCH}" = "" ]; then
 		    eval $set_cc_for_build
-		    sed 's/^              //' << EOF >$dummy.c
+		    sed 's/^		//' << EOF >$dummy.c
 
-              #define _HPUX_SOURCE
-              #include <stdlib.h>
-              #include <unistd.h>
+		#define _HPUX_SOURCE
+		#include <stdlib.h>
+		#include <unistd.h>
 
-              int main ()
-              {
-              #if defined(_SC_KERNEL_BITS)
-                  long bits = sysconf(_SC_KERNEL_BITS);
-              #endif
-                  long cpu  = sysconf (_SC_CPU_VERSION);
+		int main ()
+		{
+		#if defined(_SC_KERNEL_BITS)
+		    long bits = sysconf(_SC_KERNEL_BITS);
+		#endif
+		    long cpu  = sysconf (_SC_CPU_VERSION);
 
-                  switch (cpu)
-              	{
-              	case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
-              	case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
-              	case CPU_PA_RISC2_0:
-              #if defined(_SC_KERNEL_BITS)
-              	    switch (bits)
-              		{
-              		case 64: puts ("hppa2.0w"); break;
-              		case 32: puts ("hppa2.0n"); break;
-              		default: puts ("hppa2.0"); break;
-              		} break;
-              #else  /* !defined(_SC_KERNEL_BITS) */
-              	    puts ("hppa2.0"); break;
-              #endif
-              	default: puts ("hppa1.0"); break;
-              	}
-                  exit (0);
-              }
+		    switch (cpu)
+			{
+			case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+			case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+			case CPU_PA_RISC2_0:
+		#if defined(_SC_KERNEL_BITS)
+			    switch (bits)
+				{
+				case 64: puts ("hppa2.0w"); break;
+				case 32: puts ("hppa2.0n"); break;
+				default: puts ("hppa2.0"); break;
+				} break;
+		#else  /* !defined(_SC_KERNEL_BITS) */
+			    puts ("hppa2.0"); break;
+		#endif
+			default: puts ("hppa1.0"); break;
+			}
+		    exit (0);
+		}
 EOF
 		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
 		    test -z "$HP_ARCH" && HP_ARCH=hppa
@@ -665,7 +686,7 @@
 	    # => hppa64-hp-hpux11.23
 
 	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
-		grep __LP64__ >/dev/null
+		grep -q __LP64__
 	    then
 		HP_ARCH="hppa2.0w"
 	    else
@@ -736,22 +757,22 @@
 	exit ;;
     C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
 	echo c1-convex-bsd
-        exit ;;
+	exit ;;
     C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
 	if getsysinfo -f scalar_acc
 	then echo c32-convex-bsd
 	else echo c2-convex-bsd
 	fi
-        exit ;;
+	exit ;;
     C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
 	echo c34-convex-bsd
-        exit ;;
+	exit ;;
     C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
 	echo c38-convex-bsd
-        exit ;;
+	exit ;;
     C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
 	echo c4-convex-bsd
-        exit ;;
+	exit ;;
     CRAY*Y-MP:*:*:*)
 	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
 	exit ;;
@@ -775,14 +796,14 @@
 	exit ;;
     F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
 	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
-        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
-        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
-        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
-        exit ;;
+	FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+	FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+	echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
     5000:UNIX_System_V:4.*:*)
-        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
-        FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
-        echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+	FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+	echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
 	exit ;;
     i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
 	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
@@ -794,13 +815,12 @@
 	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
 	exit ;;
     *:FreeBSD:*:*)
-	case ${UNAME_MACHINE} in
-	    pc98)
-		echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	UNAME_PROCESSOR=`/usr/bin/uname -p`
+	case ${UNAME_PROCESSOR} in
 	    amd64)
 		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
 	    *)
-		echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+		echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
 	esac
 	exit ;;
     i*:CYGWIN*:*)
@@ -809,19 +829,22 @@
     *:MINGW*:*)
 	echo ${UNAME_MACHINE}-pc-mingw32
 	exit ;;
+    i*:MSYS*:*)
+	echo ${UNAME_MACHINE}-pc-msys
+	exit ;;
     i*:windows32*:*)
-    	# uname -m includes "-pc" on this system.
-    	echo ${UNAME_MACHINE}-mingw32
+	# uname -m includes "-pc" on this system.
+	echo ${UNAME_MACHINE}-mingw32
 	exit ;;
     i*:PW*:*)
 	echo ${UNAME_MACHINE}-pc-pw32
 	exit ;;
-    *:Interix*:[3456]*)
-    	case ${UNAME_MACHINE} in
+    *:Interix*:*)
+	case ${UNAME_MACHINE} in
 	    x86)
 		echo i586-pc-interix${UNAME_RELEASE}
 		exit ;;
-	    EM64T | authenticamd)
+	    authenticamd | genuineintel | EM64T)
 		echo x86_64-unknown-interix${UNAME_RELEASE}
 		exit ;;
 	    IA64)
@@ -831,6 +854,9 @@
     [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
 	echo i${UNAME_MACHINE}-pc-mks
 	exit ;;
+    8664:Windows_NT:*)
+	echo x86_64-pc-mks
+	exit ;;
     i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
 	# How do we know it's Interix rather than the generic POSIX subsystem?
 	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
@@ -860,91 +886,12 @@
     i*86:Minix:*:*)
 	echo ${UNAME_MACHINE}-pc-minix
 	exit ;;
-    arm*:Linux:*:*)
-	eval $set_cc_for_build
-	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
-	    | grep -q __ARM_EABI__
-	then
-	    echo ${UNAME_MACHINE}-unknown-linux-gnu
-	else
-	    echo ${UNAME_MACHINE}-unknown-linux-gnueabi
-	fi
-	exit ;;
-    avr32*:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-gnu
-	exit ;;
-    cris:Linux:*:*)
-	echo cris-axis-linux-gnu
-	exit ;;
-    crisv32:Linux:*:*)
-	echo crisv32-axis-linux-gnu
-	exit ;;
-    frv:Linux:*:*)
-    	echo frv-unknown-linux-gnu
-	exit ;;
-    ia64:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-gnu
-	exit ;;
-    m32r*:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-gnu
-	exit ;;
-    m68*:Linux:*:*)
+    aarch64:Linux:*:*)
 	echo ${UNAME_MACHINE}-unknown-linux-gnu
 	exit ;;
-    mips:Linux:*:*)
-	eval $set_cc_for_build
-	sed 's/^	//' << EOF >$dummy.c
-	#undef CPU
-	#undef mips
-	#undef mipsel
-	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
-	CPU=mipsel
-	#else
-	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
-	CPU=mips
-	#else
-	CPU=
-	#endif
-	#endif
-EOF
-	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
-	    /^CPU/{
-		s: ::g
-		p
-	    }'`"
-	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
-	;;
-    mips64:Linux:*:*)
-	eval $set_cc_for_build
-	sed 's/^	//' << EOF >$dummy.c
-	#undef CPU
-	#undef mips64
-	#undef mips64el
-	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
-	CPU=mips64el
-	#else
-	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
-	CPU=mips64
-	#else
-	CPU=
-	#endif
-	#endif
-EOF
-	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
-	    /^CPU/{
-		s: ::g
-		p
-	    }'`"
-	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
-	;;
-    or32:Linux:*:*)
-	echo or32-unknown-linux-gnu
-	exit ;;
-    ppc:Linux:*:*)
-	echo powerpc-unknown-linux-gnu
-	exit ;;
-    ppc64:Linux:*:*)
-	echo powerpc64-unknown-linux-gnu
+    aarch64_be:Linux:*:*)
+	UNAME_MACHINE=aarch64_be
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
 	exit ;;
     alpha:Linux:*:*)
 	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
@@ -955,11 +902,90 @@
 	  EV6)   UNAME_MACHINE=alphaev6 ;;
 	  EV67)  UNAME_MACHINE=alphaev67 ;;
 	  EV68*) UNAME_MACHINE=alphaev68 ;;
-        esac
-	objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+	esac
+	objdump --private-headers /bin/sh | grep -q ld.so.1
 	if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
 	echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
 	exit ;;
+    arm*:Linux:*:*)
+	eval $set_cc_for_build
+	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+	    | grep -q __ARM_EABI__
+	then
+	    echo ${UNAME_MACHINE}-unknown-linux-gnu
+	else
+	    if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+		| grep -q __ARM_PCS_VFP
+	    then
+		echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+	    else
+		echo ${UNAME_MACHINE}-unknown-linux-gnueabihf
+	    fi
+	fi
+	exit ;;
+    avr32*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    cris:Linux:*:*)
+	echo ${UNAME_MACHINE}-axis-linux-gnu
+	exit ;;
+    crisv32:Linux:*:*)
+	echo ${UNAME_MACHINE}-axis-linux-gnu
+	exit ;;
+    frv:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    hexagon:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    i*86:Linux:*:*)
+	LIBC=gnu
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#ifdef __dietlibc__
+	LIBC=dietlibc
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+	echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+	exit ;;
+    ia64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m32r*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m68*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    mips:Linux:*:* | mips64:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef ${UNAME_MACHINE}
+	#undef ${UNAME_MACHINE}el
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=${UNAME_MACHINE}el
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=${UNAME_MACHINE}
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+	;;
+    or32:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    padre:Linux:*:*)
+	echo sparc-unknown-linux-gnu
+	exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-gnu
+	exit ;;
     parisc:Linux:*:* | hppa:Linux:*:*)
 	# Look for CPU level
 	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
@@ -968,14 +994,17 @@
 	  *)    echo hppa-unknown-linux-gnu ;;
 	esac
 	exit ;;
-    parisc64:Linux:*:* | hppa64:Linux:*:*)
-	echo hppa64-unknown-linux-gnu
+    ppc64:Linux:*:*)
+	echo powerpc64-unknown-linux-gnu
+	exit ;;
+    ppc:Linux:*:*)
+	echo powerpc-unknown-linux-gnu
 	exit ;;
     s390:Linux:*:* | s390x:Linux:*:*)
 	echo ${UNAME_MACHINE}-ibm-linux
 	exit ;;
     sh64*:Linux:*:*)
-    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
 	exit ;;
     sh*:Linux:*:*)
 	echo ${UNAME_MACHINE}-unknown-linux-gnu
@@ -983,78 +1012,18 @@
     sparc:Linux:*:* | sparc64:Linux:*:*)
 	echo ${UNAME_MACHINE}-unknown-linux-gnu
 	exit ;;
+    tile*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
     vax:Linux:*:*)
 	echo ${UNAME_MACHINE}-dec-linux-gnu
 	exit ;;
     x86_64:Linux:*:*)
-	echo x86_64-unknown-linux-gnu
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
 	exit ;;
     xtensa*:Linux:*:*)
-    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
 	exit ;;
-    i*86:Linux:*:*)
-	# The BFD linker knows what the default object file format is, so
-	# first see if it will tell us. cd to the root directory to prevent
-	# problems with other programs or directories called `ld' in the path.
-	# Set LC_ALL=C to ensure ld outputs messages in English.
-	ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
-			 | sed -ne '/supported targets:/!d
-				    s/[ 	][ 	]*/ /g
-				    s/.*supported targets: *//
-				    s/ .*//
-				    p'`
-        case "$ld_supported_targets" in
-	  elf32-i386)
-		TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
-		;;
-	  a.out-i386-linux)
-		echo "${UNAME_MACHINE}-pc-linux-gnuaout"
-		exit ;;
-	  coff-i386)
-		echo "${UNAME_MACHINE}-pc-linux-gnucoff"
-		exit ;;
-	  "")
-		# Either a pre-BFD a.out linker (linux-gnuoldld) or
-		# one that does not give us useful --help.
-		echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
-		exit ;;
-	esac
-	# Determine whether the default compiler is a.out or elf
-	eval $set_cc_for_build
-	sed 's/^	//' << EOF >$dummy.c
-	#include <features.h>
-	#ifdef __ELF__
-	# ifdef __GLIBC__
-	#  if __GLIBC__ >= 2
-	LIBC=gnu
-	#  else
-	LIBC=gnulibc1
-	#  endif
-	# else
-	LIBC=gnulibc1
-	# endif
-	#else
-	#if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
-	LIBC=gnu
-	#else
-	LIBC=gnuaout
-	#endif
-	#endif
-	#ifdef __dietlibc__
-	LIBC=dietlibc
-	#endif
-EOF
-	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
-	    /^LIBC/{
-		s: ::g
-		p
-	    }'`"
-	test x"${LIBC}" != x && {
-		echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
-		exit
-	}
-	test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; }
-	;;
     i*86:DYNIX/ptx:4*:*)
 	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
 	# earlier versions are messed up and put the nodename in both
@@ -1062,11 +1031,11 @@
 	echo i386-sequent-sysv4
 	exit ;;
     i*86:UNIX_SV:4.2MP:2.*)
-        # Unixware is an offshoot of SVR4, but it has its own version
-        # number series starting with 2...
-        # I am not positive that other SVR4 systems won't match this,
+	# Unixware is an offshoot of SVR4, but it has its own version
+	# number series starting with 2...
+	# I am not positive that other SVR4 systems won't match this,
 	# I just have to hope.  -- rms.
-        # Use sysv4.2uw... so that sysv4* matches it.
+	# Use sysv4.2uw... so that sysv4* matches it.
 	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
 	exit ;;
     i*86:OS/2:*:*)
@@ -1083,7 +1052,7 @@
     i*86:syllable:*:*)
 	echo ${UNAME_MACHINE}-pc-syllable
 	exit ;;
-    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
 	echo i386-unknown-lynxos${UNAME_RELEASE}
 	exit ;;
     i*86:*DOS:*:*)
@@ -1098,7 +1067,7 @@
 	fi
 	exit ;;
     i*86:*:5:[678]*)
-    	# UnixWare 7.x, OpenUNIX and OpenServer 6.
+	# UnixWare 7.x, OpenUNIX and OpenServer 6.
 	case `/bin/uname -X | grep "^Machine"` in
 	    *486*)	     UNAME_MACHINE=i486 ;;
 	    *Pentium)	     UNAME_MACHINE=i586 ;;
@@ -1126,10 +1095,13 @@
 	exit ;;
     pc:*:*:*)
 	# Left here for compatibility:
-        # uname -m prints for DJGPP always 'pc', but it prints nothing about
-        # the processor, so we play safe by assuming i386.
-	echo i386-pc-msdosdjgpp
-        exit ;;
+	# uname -m prints for DJGPP always 'pc', but it prints nothing about
+	# the processor, so we play safe by assuming i586.
+	# Note: whatever this is, it MUST be the same as what config.sub
+	# prints for the "djgpp" host, or else GDB configury will decide that
+	# this is a cross-build.
+	echo i586-pc-msdosdjgpp
+	exit ;;
     Intel:Mach:3*:*)
 	echo i386-pc-mach3
 	exit ;;
@@ -1164,8 +1136,18 @@
 	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
 	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
     3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
-        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
-          && { echo i486-ncr-sysv4; exit; } ;;
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4; exit; } ;;
+    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+	OS_REL='.3'
+	test -r /etc/.relid \
+	    && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	    && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
     m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
 	echo m68k-unknown-lynxos${UNAME_RELEASE}
 	exit ;;
@@ -1178,7 +1160,7 @@
     rs6000:LynxOS:2.*:*)
 	echo rs6000-unknown-lynxos${UNAME_RELEASE}
 	exit ;;
-    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
 	echo powerpc-unknown-lynxos${UNAME_RELEASE}
 	exit ;;
     SM[BE]S:UNIX_SV:*:*)
@@ -1198,10 +1180,10 @@
 		echo ns32k-sni-sysv
 	fi
 	exit ;;
-    PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
-                      # says <Richard.M.Bartel@ccMail.Census.GOV>
-        echo i586-unisys-sysv4
-        exit ;;
+    PENTIUM:*:4.0*:*)	# Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+			# says <Richard.M.Bartel@ccMail.Census.GOV>
+	echo i586-unisys-sysv4
+	exit ;;
     *:UNIX_System_V:4*:FTX*)
 	# From Gerald Hewes <hewes@openmarket.com>.
 	# How about differentiating between stratus architectures? -djm
@@ -1227,11 +1209,11 @@
 	exit ;;
     R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
 	if [ -d /usr/nec ]; then
-	        echo mips-nec-sysv${UNAME_RELEASE}
+		echo mips-nec-sysv${UNAME_RELEASE}
 	else
-	        echo mips-unknown-sysv${UNAME_RELEASE}
+		echo mips-unknown-sysv${UNAME_RELEASE}
 	fi
-        exit ;;
+	exit ;;
     BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
 	echo powerpc-be-beos
 	exit ;;
@@ -1241,6 +1223,9 @@
     BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
 	echo i586-pc-beos
 	exit ;;
+    BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.
+	echo i586-pc-haiku
+	exit ;;
     SX-4:SUPER-UX:*:*)
 	echo sx4-nec-superux${UNAME_RELEASE}
 	exit ;;
@@ -1267,12 +1252,17 @@
 	exit ;;
     *:Darwin:*:*)
 	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
-	eval $set_cc_for_build
-	echo "int main(){}" > $dummy.c
-        if test "`$CC_FOR_BUILD -o $dummy $dummy.c; file $dummy |  grep -c x86_64`" = 1 ; then
-             UNAME_PROCESSOR=x86_64
-        fi
 	case $UNAME_PROCESSOR in
+	    i386)
+		eval $set_cc_for_build
+		if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+		  if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+		      (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		      grep IS_64BIT_ARCH >/dev/null
+		  then
+		      UNAME_PROCESSOR="x86_64"
+		  fi
+		fi ;;
 	    unknown) UNAME_PROCESSOR=powerpc ;;
 	esac
 	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
@@ -1288,6 +1278,9 @@
     *:QNX:*:4*)
 	echo i386-pc-qnx
 	exit ;;
+    NEO-?:NONSTOP_KERNEL:*:*)
+	echo neo-tandem-nsk${UNAME_RELEASE}
+	exit ;;
     NSE-?:NONSTOP_KERNEL:*:*)
 	echo nse-tandem-nsk${UNAME_RELEASE}
 	exit ;;
@@ -1333,13 +1326,13 @@
 	echo pdp10-unknown-its
 	exit ;;
     SEI:*:*:SEIUX)
-        echo mips-sei-seiux${UNAME_RELEASE}
+	echo mips-sei-seiux${UNAME_RELEASE}
 	exit ;;
     *:DragonFly:*:*)
 	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
 	exit ;;
     *:*VMS:*:*)
-    	UNAME_MACHINE=`(uname -p) 2>/dev/null`
+	UNAME_MACHINE=`(uname -p) 2>/dev/null`
 	case "${UNAME_MACHINE}" in
 	    A*) echo alpha-dec-vms ; exit ;;
 	    I*) echo ia64-dec-vms ; exit ;;
@@ -1354,6 +1347,12 @@
     i*86:rdos:*:*)
 	echo ${UNAME_MACHINE}-pc-rdos
 	exit ;;
+    i*86:AROS:*:*)
+	echo ${UNAME_MACHINE}-pc-aros
+	exit ;;
+    x86_64:VMkernel:*:*)
+	echo ${UNAME_MACHINE}-unknown-esx
+	exit ;;
 esac
 
 #echo '(No uname command or uname output not recognized.)' 1>&2
@@ -1376,11 +1375,11 @@
 #include <sys/param.h>
   printf ("m68k-sony-newsos%s\n",
 #ifdef NEWSOS4
-          "4"
+	"4"
 #else
-	  ""
+	""
 #endif
-         ); exit (0);
+	); exit (0);
 #endif
 #endif
 
--- a/common/autoconf/configure	Tue Sep 17 08:08:07 2013 -0700
+++ b/common/autoconf/configure	Wed Jul 05 19:11:53 2017 +0200
@@ -219,9 +219,4 @@
   echo configure exiting with result code $conf_result_code
 fi
 
-# Move the log file to the output root, if this was successfully created
-if test -d "$OUTPUT_ROOT"; then
-  mv -f config.log "$OUTPUT_ROOT" 2> /dev/null
-fi
-
 exit $conf_result_code
--- a/common/autoconf/configure.ac	Tue Sep 17 08:08:07 2013 -0700
+++ b/common/autoconf/configure.ac	Wed Jul 05 19:11:53 2017 +0200
@@ -232,9 +232,15 @@
 # We're messing a bit with internal autoconf variables to put the config.status
 # in the output directory instead of the current directory.
 CONFIG_STATUS="$OUTPUT_ROOT/config.status"
+
 # Create the actual output files. Now the main work of configure is done.
 AC_OUTPUT
 
+# Try to move the config.log file to the output directory. 
+if test -e ./config.log; then
+  $MV -f ./config.log "$OUTPUT_ROOT/config.log" 2> /dev/null
+fi
+
 # Make the compare script executable
 $CHMOD +x $OUTPUT_ROOT/compare.sh
 
--- a/common/autoconf/generated-configure.sh	Tue Sep 17 08:08:07 2013 -0700
+++ b/common/autoconf/generated-configure.sh	Wed Jul 05 19:11:53 2017 +0200
@@ -709,7 +709,6 @@
 SHARED_LIBRARY
 OBJ_SUFFIX
 COMPILER_NAME
-TARGET_BITS_FLAG
 JT_HOME
 JTREGEXE
 LIPO
@@ -766,8 +765,6 @@
 BUILD_CXX
 BUILD_CC
 MSVCR_DLL
-DXSDK_INCLUDE_PATH
-DXSDK_LIB_PATH
 VS_PATH
 VS_LIB
 VS_INCLUDE
@@ -1031,6 +1028,7 @@
 with_override_jaxp
 with_override_jaxws
 with_override_hotspot
+with_override_nashorn
 with_override_jdk
 with_import_hotspot
 with_msvcr_dll
@@ -1784,17 +1782,19 @@
   --with-override-jaxp    use this jaxp dir for the build
   --with-override-jaxws   use this jaxws dir for the build
   --with-override-hotspot use this hotspot dir for the build
+  --with-override-nashorn use this nashorn dir for the build
   --with-override-jdk     use this jdk dir for the build
   --with-import-hotspot   import hotspot binaries from this jdk image or
                           hotspot build dist dir instead of building from
                           source
   --with-msvcr-dll        copy this msvcr100.dll into the built JDK (Windows
                           only) [probed]
-  --with-dxsdk            the DirectX SDK (Windows only) [probed]
-  --with-dxsdk-lib        the DirectX SDK lib directory (Windows only)
-                          [probed]
-  --with-dxsdk-include    the DirectX SDK include directory (Windows only)
-                          [probed]
+  --with-dxsdk            Deprecated. Option is kept for backwards
+                          compatibility and is ignored
+  --with-dxsdk-lib        Deprecated. Option is kept for backwards
+                          compatibility and is ignored
+  --with-dxsdk-include    Deprecated. Option is kept for backwards
+                          compatibility and is ignored
   --with-jtreg            Regression Test Harness [probed]
   --with-extra-cflags     extra flags to be used when compiling jdk c-files
   --with-extra-cxxflags   extra flags to be used when compiling jdk c++-files
@@ -3144,6 +3144,10 @@
 
 
 
+# Register a --with argument but mark it as deprecated
+# $1: The name of the with argument to deprecate, not including --with-
+
+
 
 
 # Test that variable $1 denoting a program is not empty. If empty, exit with an error.
@@ -3805,10 +3809,6 @@
 
 
 
-# Setup the DXSDK paths
-
-
-
 
 
 
@@ -3818,7 +3818,7 @@
 #CUSTOM_AUTOCONF_INCLUDE
 
 # Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1378914658
+DATE_WHEN_GENERATED=1379504921
 
 ###############################################################################
 #
@@ -8352,7 +8352,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -8709,7 +8709,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -9063,7 +9063,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -9422,7 +9422,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -9775,7 +9775,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -11075,7 +11075,7 @@
 else
   BUILD_DATE=`date '+%Y_%m_%d_%H_%M'`
   # Avoid [:alnum:] since it depends on the locale.
-  CLEAN_USERNAME=`echo "$USER" | $TR -d -c 'abcdefghijklmnopqrstuvqxyz0123456789'`
+  CLEAN_USERNAME=`echo "$USER" | $TR -d -c 'abcdefghijklmnopqrstuvqxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'`
   USER_RELEASE_SUFFIX=`echo "${CLEAN_USERNAME}_${BUILD_DATE}" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
 fi
 
@@ -16102,6 +16102,10 @@
        test -f $with_add_source_root/hotspot/make/Makefile; then
         as_fn_error $? "Your add source root seems to contain a full hotspot repo! An add source root should only contain additional sources." "$LINENO" 5
     fi
+    if test -f $with_add_source_root/nashorn/makefiles/Makefile || \
+       test -f $with_add_source_root/nashorn/make/Makefile; then
+        as_fn_error $? "Your add source root seems to contain a full nashorn repo! An add source root should only contain additional sources." "$LINENO" 5
+    fi
     if test -f $with_add_source_root/jdk/makefiles/Makefile || \
        test -f $with_add_source_root/jdk/make/Makefile; then
         as_fn_error $? "Your add source root seems to contain a full JDK repo! An add source root should only contain additional sources." "$LINENO" 5
@@ -16137,6 +16141,10 @@
        test -f $with_override_source_root/hotspot/make/Makefile; then
         as_fn_error $? "Your override source root seems to contain a full hotspot repo! An override source root should only contain sources that override." "$LINENO" 5
     fi
+    if test -f $with_override_source_root/nashorn/makefiles/Makefile || \
+       test -f $with_override_source_root/nashorn/make/Makefile; then
+        as_fn_error $? "Your override source root seems to contain a full nashorn repo! An override source root should only contain sources that override." "$LINENO" 5
+    fi
     if test -f $with_override_source_root/jdk/makefiles/Makefile || \
        test -f $with_override_source_root/jdk/make/Makefile; then
         as_fn_error $? "Your override source root seems to contain a full JDK repo! An override source root should only contain sources that override." "$LINENO" 5
@@ -16199,6 +16207,13 @@
 
 
 
+# Check whether --with-override-nashorn was given.
+if test "${with_override_nashorn+set}" = set; then :
+  withval=$with_override_nashorn;
+fi
+
+
+
 # Check whether --with-override-jdk was given.
 if test "${with_override_jdk+set}" = set; then :
   withval=$with_override_jdk;
@@ -16276,7 +16291,7 @@
     cd "$with_override_nashorn"
     NASHORN_TOPDIR="`pwd`"
     cd "$CURDIR"
-    if ! test -f $NASHORN_TOPDIR/makefiles/BuildNashorn.gmk; then
+    if ! test -f $NASHORN_TOPDIR/makefiles/Makefile; then
         as_fn_error $? "You have to override nashorn with a full nashorn repo!" "$LINENO" 5
     fi
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking if nashorn should be overridden" >&5
@@ -17086,7 +17101,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -17586,436 +17601,28 @@
 
 # Check whether --with-dxsdk was given.
 if test "${with_dxsdk+set}" = set; then :
-  withval=$with_dxsdk;
-fi
+  withval=$with_dxsdk; { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Option --with-dxsdk is deprecated and will be ignored." >&5
+$as_echo "$as_me: WARNING: Option --with-dxsdk is deprecated and will be ignored." >&2;}
+fi
+
+
 
 
 # Check whether --with-dxsdk-lib was given.
 if test "${with_dxsdk_lib+set}" = set; then :
-  withval=$with_dxsdk_lib;
-fi
+  withval=$with_dxsdk_lib; { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Option --with-dxsdk-lib is deprecated and will be ignored." >&5
+$as_echo "$as_me: WARNING: Option --with-dxsdk-lib is deprecated and will be ignored." >&2;}
+fi
+
+
 
 
 # Check whether --with-dxsdk-include was given.
 if test "${with_dxsdk_include+set}" = set; then :
-  withval=$with_dxsdk_include;
-fi
-
-
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DirectX SDK" >&5
-$as_echo_n "checking for DirectX SDK... " >&6; }
-
-  if test "x$with_dxsdk" != x; then
-    dxsdk_path="$with_dxsdk"
-  elif test "x$DXSDK_DIR" != x; then
-    dxsdk_path="$DXSDK_DIR"
-  elif test -d "C:/DXSDK"; then
-    dxsdk_path="C:/DXSDK"
-  else
-    as_fn_error $? "Could not find the DirectX SDK" "$LINENO" 5
-  fi
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dxsdk_path" >&5
-$as_echo "$dxsdk_path" >&6; }
-
-  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
-
-  # Input might be given as Windows format, start by converting to
-  # unix format.
-  path="$dxsdk_path"
-  new_path=`$CYGPATH -u "$path"`
-
-  # Cygwin tries to hide some aspects of the Windows file system, such that binaries are
-  # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered
-  # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
-  # "foo.exe" is OK but "foo" is an error.
-  #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
-  # It is also a way to make sure we got the proper file name for the real test later on.
-  test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
-  if test "x$test_shortpath" = x; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: The path of dxsdk_path, which resolves as \"$path\", is invalid." >&5
-$as_echo "$as_me: The path of dxsdk_path, which resolves as \"$path\", is invalid." >&6;}
-    as_fn_error $? "Cannot locate the the path of dxsdk_path" "$LINENO" 5
-  fi
-
-  # Call helper function which possibly converts this using DOS-style short mode.
-  # If so, the updated path is stored in $new_path.
-
-  input_path="$new_path"
-  # Check if we need to convert this using DOS-style short mode. If the path
-  # contains just simple characters, use it. Otherwise (spaces, weird characters),
-  # take no chances and rewrite it.
-  # Note: m4 eats our [], so we need to use [ and ] instead.
-  has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]`
-  if test "x$has_forbidden_chars" != x; then
-    # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
-    shortmode_path=`$CYGPATH -s -m -a "$input_path"`
-    path_after_shortmode=`$CYGPATH -u "$shortmode_path"`
-    if test "x$path_after_shortmode" != "x$input_to_shortpath"; then
-      # Going to short mode and back again did indeed matter. Since short mode is
-      # case insensitive, let's make it lowercase to improve readability.
-      shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
-      # Now convert it back to Unix-stile (cygpath)
-      input_path=`$CYGPATH -u "$shortmode_path"`
-      new_path="$input_path"
-    fi
-  fi
-
-  test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/`
-  if test "x$test_cygdrive_prefix" = x; then
-    # As a simple fix, exclude /usr/bin since it's not a real path.
-    if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then
-      # The path is in a Cygwin special directory (e.g. /home). We need this converted to
-      # a path prefixed by /cygdrive for fixpath to work.
-      new_path="$CYGWIN_ROOT_PATH$input_path"
-    fi
-  fi
-
-
-  if test "x$path" != "x$new_path"; then
-    dxsdk_path="$new_path"
-    { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting dxsdk_path to \"$new_path\"" >&5
-$as_echo "$as_me: Rewriting dxsdk_path to \"$new_path\"" >&6;}
-  fi
-
-  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
-
-  path="$dxsdk_path"
-  has_colon=`$ECHO $path | $GREP ^.:`
-  new_path="$path"
-  if test "x$has_colon" = x; then
-    # Not in mixed or Windows style, start by that.
-    new_path=`cmd //c echo $path`
-  fi
-
-
-  input_path="$new_path"
-  # Check if we need to convert this using DOS-style short mode. If the path
-  # contains just simple characters, use it. Otherwise (spaces, weird characters),
-  # take no chances and rewrite it.
-  # Note: m4 eats our [], so we need to use [ and ] instead.
-  has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]`
-  if test "x$has_forbidden_chars" != x; then
-    # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
-    new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
-  fi
-
-
-  windows_path="$new_path"
-  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
-    unix_path=`$CYGPATH -u "$windows_path"`
-    new_path="$unix_path"
-  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
-    unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
-    new_path="$unix_path"
-  fi
-
-  if test "x$path" != "x$new_path"; then
-    dxsdk_path="$new_path"
-    { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting dxsdk_path to \"$new_path\"" >&5
-$as_echo "$as_me: Rewriting dxsdk_path to \"$new_path\"" >&6;}
-  fi
-
-  # Save the first 10 bytes of this path to the storage, so fixpath can work.
-  all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}")
-
-  else
-    # We're on a posix platform. Hooray! :)
-    path="$dxsdk_path"
-    has_space=`$ECHO "$path" | $GREP " "`
-    if test "x$has_space" != x; then
-      { $as_echo "$as_me:${as_lineno-$LINENO}: The path of dxsdk_path, which resolves as \"$path\", is invalid." >&5
-$as_echo "$as_me: The path of dxsdk_path, which resolves as \"$path\", is invalid." >&6;}
-      as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5
-    fi
-
-    # Use eval to expand a potential ~
-    eval path="$path"
-    if test ! -f "$path" && test ! -d "$path"; then
-      as_fn_error $? "The path of dxsdk_path, which resolves as \"$path\", is not found." "$LINENO" 5
-    fi
-
-    dxsdk_path="`cd "$path"; $THEPWDCMD -L`"
-  fi
-
-
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DirectX SDK lib dir" >&5
-$as_echo_n "checking for DirectX SDK lib dir... " >&6; }
-  if test "x$with_dxsdk_lib" != x; then
-    DXSDK_LIB_PATH="$with_dxsdk_lib"
-  elif test "x$OPENJDK_TARGET_CPU" = "xx86_64"; then
-    DXSDK_LIB_PATH="$dxsdk_path/Lib/x64"
-  else
-    DXSDK_LIB_PATH="$dxsdk_path/Lib"
-  fi
-  # dsound.lib is linked to in jsoundds
-  if test ! -f "$DXSDK_LIB_PATH/dsound.lib"; then
-    as_fn_error $? "Invalid DirectX SDK lib dir" "$LINENO" 5
-  fi
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DXSDK_LIB_PATH" >&5
-$as_echo "$DXSDK_LIB_PATH" >&6; }
-
-  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
-
-  # Input might be given as Windows format, start by converting to
-  # unix format.
-  path="$DXSDK_LIB_PATH"
-  new_path=`$CYGPATH -u "$path"`
-
-  # Cygwin tries to hide some aspects of the Windows file system, such that binaries are
-  # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered
-  # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
-  # "foo.exe" is OK but "foo" is an error.
-  #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
-  # It is also a way to make sure we got the proper file name for the real test later on.
-  test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
-  if test "x$test_shortpath" = x; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: The path of DXSDK_LIB_PATH, which resolves as \"$path\", is invalid." >&5
-$as_echo "$as_me: The path of DXSDK_LIB_PATH, which resolves as \"$path\", is invalid." >&6;}
-    as_fn_error $? "Cannot locate the the path of DXSDK_LIB_PATH" "$LINENO" 5
-  fi
-
-  # Call helper function which possibly converts this using DOS-style short mode.
-  # If so, the updated path is stored in $new_path.
-
-  input_path="$new_path"
-  # Check if we need to convert this using DOS-style short mode. If the path
-  # contains just simple characters, use it. Otherwise (spaces, weird characters),
-  # take no chances and rewrite it.
-  # Note: m4 eats our [], so we need to use [ and ] instead.
-  has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]`
-  if test "x$has_forbidden_chars" != x; then
-    # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
-    shortmode_path=`$CYGPATH -s -m -a "$input_path"`
-    path_after_shortmode=`$CYGPATH -u "$shortmode_path"`
-    if test "x$path_after_shortmode" != "x$input_to_shortpath"; then
-      # Going to short mode and back again did indeed matter. Since short mode is
-      # case insensitive, let's make it lowercase to improve readability.
-      shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
-      # Now convert it back to Unix-stile (cygpath)
-      input_path=`$CYGPATH -u "$shortmode_path"`
-      new_path="$input_path"
-    fi
-  fi
-
-  test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/`
-  if test "x$test_cygdrive_prefix" = x; then
-    # As a simple fix, exclude /usr/bin since it's not a real path.
-    if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then
-      # The path is in a Cygwin special directory (e.g. /home). We need this converted to
-      # a path prefixed by /cygdrive for fixpath to work.
-      new_path="$CYGWIN_ROOT_PATH$input_path"
-    fi
-  fi
-
-
-  if test "x$path" != "x$new_path"; then
-    DXSDK_LIB_PATH="$new_path"
-    { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting DXSDK_LIB_PATH to \"$new_path\"" >&5
-$as_echo "$as_me: Rewriting DXSDK_LIB_PATH to \"$new_path\"" >&6;}
-  fi
-
-  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
-
-  path="$DXSDK_LIB_PATH"
-  has_colon=`$ECHO $path | $GREP ^.:`
-  new_path="$path"
-  if test "x$has_colon" = x; then
-    # Not in mixed or Windows style, start by that.
-    new_path=`cmd //c echo $path`
-  fi
-
-
-  input_path="$new_path"
-  # Check if we need to convert this using DOS-style short mode. If the path
-  # contains just simple characters, use it. Otherwise (spaces, weird characters),
-  # take no chances and rewrite it.
-  # Note: m4 eats our [], so we need to use [ and ] instead.
-  has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]`
-  if test "x$has_forbidden_chars" != x; then
-    # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
-    new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
-  fi
-
-
-  windows_path="$new_path"
-  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
-    unix_path=`$CYGPATH -u "$windows_path"`
-    new_path="$unix_path"
-  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
-    unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
-    new_path="$unix_path"
-  fi
-
-  if test "x$path" != "x$new_path"; then
-    DXSDK_LIB_PATH="$new_path"
-    { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting DXSDK_LIB_PATH to \"$new_path\"" >&5
-$as_echo "$as_me: Rewriting DXSDK_LIB_PATH to \"$new_path\"" >&6;}
-  fi
-
-  # Save the first 10 bytes of this path to the storage, so fixpath can work.
-  all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}")
-
-  else
-    # We're on a posix platform. Hooray! :)
-    path="$DXSDK_LIB_PATH"
-    has_space=`$ECHO "$path" | $GREP " "`
-    if test "x$has_space" != x; then
-      { $as_echo "$as_me:${as_lineno-$LINENO}: The path of DXSDK_LIB_PATH, which resolves as \"$path\", is invalid." >&5
-$as_echo "$as_me: The path of DXSDK_LIB_PATH, which resolves as \"$path\", is invalid." >&6;}
-      as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5
-    fi
-
-    # Use eval to expand a potential ~
-    eval path="$path"
-    if test ! -f "$path" && test ! -d "$path"; then
-      as_fn_error $? "The path of DXSDK_LIB_PATH, which resolves as \"$path\", is not found." "$LINENO" 5
-    fi
-
-    DXSDK_LIB_PATH="`cd "$path"; $THEPWDCMD -L`"
-  fi
-
-
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DirectX SDK include dir" >&5
-$as_echo_n "checking for DirectX SDK include dir... " >&6; }
-  if test "x$with_dxsdk_include" != x; then
-    DXSDK_INCLUDE_PATH="$with_dxsdk_include"
-  else
-    DXSDK_INCLUDE_PATH="$dxsdk_path/Include"
-  fi
-  # dsound.h is included in jsoundds
-  if test ! -f "$DXSDK_INCLUDE_PATH/dsound.h"; then
-    as_fn_error $? "Invalid DirectX SDK lib dir" "$LINENO" 5
-  fi
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DXSDK_INCLUDE_PATH" >&5
-$as_echo "$DXSDK_INCLUDE_PATH" >&6; }
-
-  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
-
-  # Input might be given as Windows format, start by converting to
-  # unix format.
-  path="$DXSDK_INCLUDE_PATH"
-  new_path=`$CYGPATH -u "$path"`
-
-  # Cygwin tries to hide some aspects of the Windows file system, such that binaries are
-  # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered
-  # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
-  # "foo.exe" is OK but "foo" is an error.
-  #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
-  # It is also a way to make sure we got the proper file name for the real test later on.
-  test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
-  if test "x$test_shortpath" = x; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: The path of DXSDK_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&5
-$as_echo "$as_me: The path of DXSDK_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&6;}
-    as_fn_error $? "Cannot locate the the path of DXSDK_INCLUDE_PATH" "$LINENO" 5
-  fi
-
-  # Call helper function which possibly converts this using DOS-style short mode.
-  # If so, the updated path is stored in $new_path.
-
-  input_path="$new_path"
-  # Check if we need to convert this using DOS-style short mode. If the path
-  # contains just simple characters, use it. Otherwise (spaces, weird characters),
-  # take no chances and rewrite it.
-  # Note: m4 eats our [], so we need to use [ and ] instead.
-  has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]`
-  if test "x$has_forbidden_chars" != x; then
-    # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
-    shortmode_path=`$CYGPATH -s -m -a "$input_path"`
-    path_after_shortmode=`$CYGPATH -u "$shortmode_path"`
-    if test "x$path_after_shortmode" != "x$input_to_shortpath"; then
-      # Going to short mode and back again did indeed matter. Since short mode is
-      # case insensitive, let's make it lowercase to improve readability.
-      shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
-      # Now convert it back to Unix-stile (cygpath)
-      input_path=`$CYGPATH -u "$shortmode_path"`
-      new_path="$input_path"
-    fi
-  fi
-
-  test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/`
-  if test "x$test_cygdrive_prefix" = x; then
-    # As a simple fix, exclude /usr/bin since it's not a real path.
-    if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then
-      # The path is in a Cygwin special directory (e.g. /home). We need this converted to
-      # a path prefixed by /cygdrive for fixpath to work.
-      new_path="$CYGWIN_ROOT_PATH$input_path"
-    fi
-  fi
-
-
-  if test "x$path" != "x$new_path"; then
-    DXSDK_INCLUDE_PATH="$new_path"
-    { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting DXSDK_INCLUDE_PATH to \"$new_path\"" >&5
-$as_echo "$as_me: Rewriting DXSDK_INCLUDE_PATH to \"$new_path\"" >&6;}
-  fi
-
-  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
-
-  path="$DXSDK_INCLUDE_PATH"
-  has_colon=`$ECHO $path | $GREP ^.:`
-  new_path="$path"
-  if test "x$has_colon" = x; then
-    # Not in mixed or Windows style, start by that.
-    new_path=`cmd //c echo $path`
-  fi
-
-
-  input_path="$new_path"
-  # Check if we need to convert this using DOS-style short mode. If the path
-  # contains just simple characters, use it. Otherwise (spaces, weird characters),
-  # take no chances and rewrite it.
-  # Note: m4 eats our [], so we need to use [ and ] instead.
-  has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]`
-  if test "x$has_forbidden_chars" != x; then
-    # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
-    new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
-  fi
-
-
-  windows_path="$new_path"
-  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
-    unix_path=`$CYGPATH -u "$windows_path"`
-    new_path="$unix_path"
-  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
-    unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
-    new_path="$unix_path"
-  fi
-
-  if test "x$path" != "x$new_path"; then
-    DXSDK_INCLUDE_PATH="$new_path"
-    { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting DXSDK_INCLUDE_PATH to \"$new_path\"" >&5
-$as_echo "$as_me: Rewriting DXSDK_INCLUDE_PATH to \"$new_path\"" >&6;}
-  fi
-
-  # Save the first 10 bytes of this path to the storage, so fixpath can work.
-  all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}")
-
-  else
-    # We're on a posix platform. Hooray! :)
-    path="$DXSDK_INCLUDE_PATH"
-    has_space=`$ECHO "$path" | $GREP " "`
-    if test "x$has_space" != x; then
-      { $as_echo "$as_me:${as_lineno-$LINENO}: The path of DXSDK_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&5
-$as_echo "$as_me: The path of DXSDK_INCLUDE_PATH, which resolves as \"$path\", is invalid." >&6;}
-      as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5
-    fi
-
-    # Use eval to expand a potential ~
-    eval path="$path"
-    if test ! -f "$path" && test ! -d "$path"; then
-      as_fn_error $? "The path of DXSDK_INCLUDE_PATH, which resolves as \"$path\", is not found." "$LINENO" 5
-    fi
-
-    DXSDK_INCLUDE_PATH="`cd "$path"; $THEPWDCMD -L`"
-  fi
-
-
-
-
-  LDFLAGS_JDK="$LDFLAGS_JDK -libpath:$DXSDK_LIB_PATH"
+  withval=$with_dxsdk_include; { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Option --with-dxsdk-include is deprecated and will be ignored." >&5
+$as_echo "$as_me: WARNING: Option --with-dxsdk-include is deprecated and will be ignored." >&2;}
+fi
+
 
 fi
 
@@ -18140,7 +17747,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -18451,7 +18058,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -18757,7 +18364,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -19350,7 +18957,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -19786,7 +19393,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -20922,7 +20529,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -21358,7 +20965,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -22259,7 +21866,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -22640,7 +22247,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -22987,7 +22594,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -23324,7 +22931,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -23645,7 +23252,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -24020,7 +23627,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -24326,7 +23933,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -24737,7 +24344,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -25137,7 +24744,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -25466,7 +25073,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -25778,7 +25385,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -26084,7 +25691,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -26390,7 +25997,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -26696,7 +26303,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -27055,7 +26662,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -27415,7 +27022,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -27788,7 +27395,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -28159,7 +27766,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -28468,7 +28075,7 @@
   # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
   # "foo.exe" is OK but "foo" is an error.
   #
-  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
   # It is also a way to make sure we got the proper file name for the real test later on.
   test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
   if test "x$test_shortpath" = x; then
@@ -28830,35 +28437,41 @@
 if test "x$OPENJDK_TARGET_OS" = xsolaris; then
   # Always specify -m flags on Solaris
 
-  # keep track of c/cxx flags that we added outselves...
-  #   to prevent emitting warning...
-  TARGET_BITS_FLAG="-m${OPENJDK_TARGET_CPU_BITS}"
-
-
-  CFLAGS="${CFLAGS} ${TARGET_BITS_FLAG}"
-  CXXFLAGS="${CXXFLAGS} ${TARGET_BITS_FLAG}"
-  LDFLAGS="${LDFLAGS} ${TARGET_BITS_FLAG}"
-
-  CFLAGS_JDK="${CFLAGS_JDK} ${TARGET_BITS_FLAG}"
-  CXXFLAGS_JDK="${CXXFLAGS_JDK} ${TARGET_BITS_FLAG}"
-  LDFLAGS_JDK="${LDFLAGS_JDK} ${TARGET_BITS_FLAG}"
+  # When we add flags to the "official" CFLAGS etc, we need to
+  # keep track of these additions in ADDED_CFLAGS etc. These
+  # will later be checked to make sure only controlled additions
+  # have been made to CFLAGS etc.
+  ADDED_CFLAGS=" -m${OPENJDK_TARGET_CPU_BITS}"
+  ADDED_CXXFLAGS=" -m${OPENJDK_TARGET_CPU_BITS}"
+  ADDED_LDFLAGS=" -m${OPENJDK_TARGET_CPU_BITS}"
+
+  CFLAGS="${CFLAGS}${ADDED_CFLAGS}"
+  CXXFLAGS="${CXXFLAGS}${ADDED_CXXFLAGS}"
+  LDFLAGS="${LDFLAGS}${ADDED_LDFLAGS}"
+
+  CFLAGS_JDK="${CFLAGS_JDK}${ADDED_CFLAGS}"
+  CXXFLAGS_JDK="${CXXFLAGS_JDK}${ADDED_CXXFLAGS}"
+  LDFLAGS_JDK="${LDFLAGS_JDK}${ADDED_LDFLAGS}"
 
 elif test "x$COMPILE_TYPE" = xreduced; then
   if test "x$OPENJDK_TARGET_OS" != xwindows; then
     # Specify -m if running reduced on other Posix platforms
 
-  # keep track of c/cxx flags that we added outselves...
-  #   to prevent emitting warning...
-  TARGET_BITS_FLAG="-m${OPENJDK_TARGET_CPU_BITS}"
-
-
-  CFLAGS="${CFLAGS} ${TARGET_BITS_FLAG}"
-  CXXFLAGS="${CXXFLAGS} ${TARGET_BITS_FLAG}"
-  LDFLAGS="${LDFLAGS} ${TARGET_BITS_FLAG}"
-
-  CFLAGS_JDK="${CFLAGS_JDK} ${TARGET_BITS_FLAG}"
-  CXXFLAGS_JDK="${CXXFLAGS_JDK} ${TARGET_BITS_FLAG}"
-  LDFLAGS_JDK="${LDFLAGS_JDK} ${TARGET_BITS_FLAG}"
+  # When we add flags to the "official" CFLAGS etc, we need to
+  # keep track of these additions in ADDED_CFLAGS etc. These
+  # will later be checked to make sure only controlled additions
+  # have been made to CFLAGS etc.
+  ADDED_CFLAGS=" -m${OPENJDK_TARGET_CPU_BITS}"
+  ADDED_CXXFLAGS=" -m${OPENJDK_TARGET_CPU_BITS}"
+  ADDED_LDFLAGS=" -m${OPENJDK_TARGET_CPU_BITS}"
+
+  CFLAGS="${CFLAGS}${ADDED_CFLAGS}"
+  CXXFLAGS="${CXXFLAGS}${ADDED_CXXFLAGS}"
+  LDFLAGS="${LDFLAGS}${ADDED_LDFLAGS}"
+
+  CFLAGS_JDK="${CFLAGS_JDK}${ADDED_CFLAGS}"
+  CXXFLAGS_JDK="${CXXFLAGS_JDK}${ADDED_CXXFLAGS}"
+  LDFLAGS_JDK="${LDFLAGS_JDK}${ADDED_LDFLAGS}"
 
   fi
 fi
@@ -33618,6 +33231,7 @@
 # We're messing a bit with internal autoconf variables to put the config.status
 # in the output directory instead of the current directory.
 CONFIG_STATUS="$OUTPUT_ROOT/config.status"
+
 # Create the actual output files. Now the main work of configure is done.
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
@@ -34899,6 +34513,11 @@
 fi
 
 
+# Try to move the config.log file to the output directory.
+if test -e ./config.log; then
+  $MV -f ./config.log "$OUTPUT_ROOT/config.log" 2> /dev/null
+fi
+
 # Make the compare script executable
 $CHMOD +x $OUTPUT_ROOT/compare.sh
 
--- a/common/autoconf/jdk-options.m4	Tue Sep 17 08:08:07 2013 -0700
+++ b/common/autoconf/jdk-options.m4	Wed Jul 05 19:11:53 2017 +0200
@@ -446,7 +446,7 @@
 else
   BUILD_DATE=`date '+%Y_%m_%d_%H_%M'`
   # Avoid [:alnum:] since it depends on the locale.
-  CLEAN_USERNAME=`echo "$USER" | $TR -d -c 'abcdefghijklmnopqrstuvqxyz0123456789'`
+  CLEAN_USERNAME=`echo "$USER" | $TR -d -c 'abcdefghijklmnopqrstuvqxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'`
   USER_RELEASE_SUFFIX=`echo "${CLEAN_USERNAME}_${BUILD_DATE}" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
 fi
 AC_SUBST(USER_RELEASE_SUFFIX)
--- a/common/autoconf/platform.m4	Tue Sep 17 08:08:07 2013 -0700
+++ b/common/autoconf/platform.m4	Wed Jul 05 19:11:53 2017 +0200
@@ -422,18 +422,21 @@
 # Add -mX to various FLAGS variables.
 AC_DEFUN([PLATFORM_SET_COMPILER_TARGET_BITS_FLAGS],
 [
-  # keep track of c/cxx flags that we added outselves...
-  #   to prevent emitting warning...
-  TARGET_BITS_FLAG="-m${OPENJDK_TARGET_CPU_BITS}"
-  AC_SUBST(TARGET_BITS_FLAG)
+  # When we add flags to the "official" CFLAGS etc, we need to
+  # keep track of these additions in ADDED_CFLAGS etc. These
+  # will later be checked to make sure only controlled additions
+  # have been made to CFLAGS etc.
+  ADDED_CFLAGS=" -m${OPENJDK_TARGET_CPU_BITS}"
+  ADDED_CXXFLAGS=" -m${OPENJDK_TARGET_CPU_BITS}"
+  ADDED_LDFLAGS=" -m${OPENJDK_TARGET_CPU_BITS}"
 
-  CFLAGS="${CFLAGS} ${TARGET_BITS_FLAG}"
-  CXXFLAGS="${CXXFLAGS} ${TARGET_BITS_FLAG}"
-  LDFLAGS="${LDFLAGS} ${TARGET_BITS_FLAG}"
+  CFLAGS="${CFLAGS}${ADDED_CFLAGS}"
+  CXXFLAGS="${CXXFLAGS}${ADDED_CXXFLAGS}"
+  LDFLAGS="${LDFLAGS}${ADDED_LDFLAGS}"
 
-  CFLAGS_JDK="${CFLAGS_JDK} ${TARGET_BITS_FLAG}"
-  CXXFLAGS_JDK="${CXXFLAGS_JDK} ${TARGET_BITS_FLAG}"
-  LDFLAGS_JDK="${LDFLAGS_JDK} ${TARGET_BITS_FLAG}"
+  CFLAGS_JDK="${CFLAGS_JDK}${ADDED_CFLAGS}"
+  CXXFLAGS_JDK="${CXXFLAGS_JDK}${ADDED_CXXFLAGS}"
+  LDFLAGS_JDK="${LDFLAGS_JDK}${ADDED_LDFLAGS}"
 ])
 
 AC_DEFUN_ONCE([PLATFORM_SETUP_OPENJDK_TARGET_BITS],
--- a/common/autoconf/source-dirs.m4	Tue Sep 17 08:08:07 2013 -0700
+++ b/common/autoconf/source-dirs.m4	Wed Jul 05 19:11:53 2017 +0200
@@ -101,6 +101,10 @@
        test -f $with_add_source_root/hotspot/make/Makefile; then
         AC_MSG_ERROR([Your add source root seems to contain a full hotspot repo! An add source root should only contain additional sources.])
     fi
+    if test -f $with_add_source_root/nashorn/makefiles/Makefile || \
+       test -f $with_add_source_root/nashorn/make/Makefile; then
+        AC_MSG_ERROR([Your add source root seems to contain a full nashorn repo! An add source root should only contain additional sources.])
+    fi
     if test -f $with_add_source_root/jdk/makefiles/Makefile || \
        test -f $with_add_source_root/jdk/make/Makefile; then
         AC_MSG_ERROR([Your add source root seems to contain a full JDK repo! An add source root should only contain additional sources.])
@@ -136,6 +140,10 @@
        test -f $with_override_source_root/hotspot/make/Makefile; then
         AC_MSG_ERROR([Your override source root seems to contain a full hotspot repo! An override source root should only contain sources that override.])
     fi
+    if test -f $with_override_source_root/nashorn/makefiles/Makefile || \
+       test -f $with_override_source_root/nashorn/make/Makefile; then
+        AC_MSG_ERROR([Your override source root seems to contain a full nashorn repo! An override source root should only contain sources that override.])
+    fi
     if test -f $with_override_source_root/jdk/makefiles/Makefile || \
        test -f $with_override_source_root/jdk/make/Makefile; then
         AC_MSG_ERROR([Your override source root seems to contain a full JDK repo! An override source root should only contain sources that override.])
@@ -177,6 +185,9 @@
 AC_ARG_WITH(override-hotspot, [AS_HELP_STRING([--with-override-hotspot],
 	[use this hotspot dir for the build])])
 
+AC_ARG_WITH(override-nashorn, [AS_HELP_STRING([--with-override-nashorn],
+	[use this nashorn dir for the build])])
+
 AC_ARG_WITH(override-jdk, [AS_HELP_STRING([--with-override-jdk],
 	[use this jdk dir for the build])])
 
@@ -241,7 +252,7 @@
     cd "$with_override_nashorn"
     NASHORN_TOPDIR="`pwd`"
     cd "$CURDIR"
-    if ! test -f $NASHORN_TOPDIR/makefiles/BuildNashorn.gmk; then
+    if ! test -f $NASHORN_TOPDIR/makefiles/Makefile; then
         AC_MSG_ERROR([You have to override nashorn with a full nashorn repo!])
     fi
     AC_MSG_CHECKING([if nashorn should be overridden])
--- a/common/autoconf/spec.gmk.in	Tue Sep 17 08:08:07 2013 -0700
+++ b/common/autoconf/spec.gmk.in	Wed Jul 05 19:11:53 2017 +0200
@@ -291,10 +291,6 @@
 X_LIBS:=@X_LIBS@
 OPENWIN_HOME:=@OPENWIN_HOME@
 
-# DirectX SDK
-DXSDK_LIB_PATH=@DXSDK_LIB_PATH@
-DXSDK_INCLUDE_PATH=@DXSDK_INCLUDE_PATH@
-
 # The lowest required version of macosx to enforce compatiblity for
 MACOSX_VERSION_MIN=@MACOSX_VERSION_MIN@
 
@@ -304,7 +300,6 @@
 COMPILER_TYPE:=@COMPILER_TYPE@
 COMPILER_NAME:=@COMPILER_NAME@
 
-TARGET_BITS_FLAG=@TARGET_BITS_FLAG@
 COMPILER_SUPPORTS_TARGET_BITS_FLAG=@COMPILER_SUPPORTS_TARGET_BITS_FLAG@
 
 CC_OUT_OPTION:=@CC_OUT_OPTION@
--- a/common/autoconf/toolchain.m4	Tue Sep 17 08:08:07 2013 -0700
+++ b/common/autoconf/toolchain.m4	Wed Jul 05 19:11:53 2017 +0200
@@ -176,7 +176,9 @@
 [
 if test "x$OPENJDK_TARGET_OS" = "xwindows"; then
   TOOLCHAIN_SETUP_VISUAL_STUDIO_ENV
-  TOOLCHAIN_SETUP_DXSDK
+  BASIC_DEPRECATED_ARG_WITH([dxsdk])
+  BASIC_DEPRECATED_ARG_WITH([dxsdk-lib])
+  BASIC_DEPRECATED_ARG_WITH([dxsdk-include])
 fi
 
 AC_SUBST(MSVCR_DLL)
--- a/common/autoconf/toolchain_windows.m4	Tue Sep 17 08:08:07 2013 -0700
+++ b/common/autoconf/toolchain_windows.m4	Wed Jul 05 19:11:53 2017 +0200
@@ -277,61 +277,3 @@
   AC_MSG_RESULT([$MSVCR_DLL])
   BASIC_FIXUP_PATH(MSVCR_DLL)
 ])
-
-
-# Setup the DXSDK paths
-AC_DEFUN([TOOLCHAIN_SETUP_DXSDK],
-[
-  AC_ARG_WITH(dxsdk, [AS_HELP_STRING([--with-dxsdk],
-      [the DirectX SDK (Windows only) @<:@probed@:>@])])
-  AC_ARG_WITH(dxsdk-lib, [AS_HELP_STRING([--with-dxsdk-lib],
-      [the DirectX SDK lib directory (Windows only) @<:@probed@:>@])])
-  AC_ARG_WITH(dxsdk-include, [AS_HELP_STRING([--with-dxsdk-include],
-      [the DirectX SDK include directory (Windows only) @<:@probed@:>@])])
-
-  AC_MSG_CHECKING([for DirectX SDK])
-
-  if test "x$with_dxsdk" != x; then
-    dxsdk_path="$with_dxsdk"
-  elif test "x$DXSDK_DIR" != x; then
-    dxsdk_path="$DXSDK_DIR"
-  elif test -d "C:/DXSDK"; then
-    dxsdk_path="C:/DXSDK"
-  else
-    AC_MSG_ERROR([Could not find the DirectX SDK])
-  fi
-  AC_MSG_RESULT([$dxsdk_path])
-  BASIC_FIXUP_PATH(dxsdk_path)
-
-  AC_MSG_CHECKING([for DirectX SDK lib dir])
-  if test "x$with_dxsdk_lib" != x; then
-    DXSDK_LIB_PATH="$with_dxsdk_lib"
-  elif test "x$OPENJDK_TARGET_CPU" = "xx86_64"; then
-    DXSDK_LIB_PATH="$dxsdk_path/Lib/x64"
-  else
-    DXSDK_LIB_PATH="$dxsdk_path/Lib"
-  fi
-  # dsound.lib is linked to in jsoundds
-  if test ! -f "$DXSDK_LIB_PATH/dsound.lib"; then
-    AC_MSG_ERROR([Invalid DirectX SDK lib dir])
-  fi
-  AC_MSG_RESULT([$DXSDK_LIB_PATH])
-  BASIC_FIXUP_PATH(DXSDK_LIB_PATH)
-
-  AC_MSG_CHECKING([for DirectX SDK include dir])
-  if test "x$with_dxsdk_include" != x; then
-    DXSDK_INCLUDE_PATH="$with_dxsdk_include"
-  else
-    DXSDK_INCLUDE_PATH="$dxsdk_path/Include"
-  fi
-  # dsound.h is included in jsoundds
-  if test ! -f "$DXSDK_INCLUDE_PATH/dsound.h"; then
-    AC_MSG_ERROR([Invalid DirectX SDK lib dir])
-  fi
-  AC_MSG_RESULT([$DXSDK_INCLUDE_PATH])
-  BASIC_FIXUP_PATH(DXSDK_INCLUDE_PATH)
-
-  AC_SUBST(DXSDK_LIB_PATH)
-  AC_SUBST(DXSDK_INCLUDE_PATH)
-  LDFLAGS_JDK="$LDFLAGS_JDK -libpath:$DXSDK_LIB_PATH"
-])
--- a/common/bin/hgforest.sh	Tue Sep 17 08:08:07 2013 -0700
+++ b/common/bin/hgforest.sh	Wed Jul 05 19:11:53 2017 +0200
@@ -47,7 +47,7 @@
 bpython=""
 
 if [ "#!" = "$has_hash_bang" ] ; then
-   python="`head -n 1 ${whichhg} | cut -b 3-`"
+   python="`head -n 1 ${whichhg} | cut -b 3- | sed -e 's/^[ \t]*//;s/[ \t]*$//'`"
    bpython="`basename "$python"`"
 fi
 
--- a/hotspot/.hgtags	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/.hgtags	Wed Jul 05 19:11:53 2017 +0200
@@ -375,3 +375,5 @@
 18b4798adbc42c6fa16f5ecb7d5cd3ca130754bf hs25-b48
 aed585cafc0d9655726af6d1e1081d1c94cb3b5c jdk8-b106
 50794d8ac11c9579b41dec4de23b808fef9f34a1 hs25-b49
+5b7f90aab3ad25a25b75b7b2bb18d5ae23d8231c jdk8-b107
+a09fe9d1e016c285307507a5793bc4fa6215e9c9 hs25-b50
--- a/hotspot/make/hotspot_version	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/make/hotspot_version	Wed Jul 05 19:11:53 2017 +0200
@@ -35,7 +35,7 @@
 
 HS_MAJOR_VER=25
 HS_MINOR_VER=0
-HS_BUILD_NUMBER=49
+HS_BUILD_NUMBER=50
 
 JDK_MAJOR_VER=1
 JDK_MINOR_VER=8
--- a/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp	Wed Jul 05 19:11:53 2017 +0200
@@ -57,6 +57,7 @@
 define_pd_global(bool, UseTLAB,                      true);
 define_pd_global(bool, ResizeTLAB,                   true);
 define_pd_global(intx, LoopUnrollLimit,              60); // Design center runs on 1.3.1
+define_pd_global(intx, MinJumpTableSize,             5);
 
 // Peephole and CISC spilling both break the graph, and so makes the
 // scheduler sick.
--- a/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp	Wed Jul 05 19:11:53 2017 +0200
@@ -30,7 +30,6 @@
 
 // Sets the default values for platform dependent flags used by the server compiler.
 // (see c2_globals.hpp).  Alpha-sorted.
-
 define_pd_global(bool, BackgroundCompilation,        true);
 define_pd_global(bool, UseTLAB,                      true);
 define_pd_global(bool, ResizeTLAB,                   true);
@@ -52,6 +51,7 @@
 define_pd_global(intx, ConditionalMoveLimit,         3);
 define_pd_global(intx, FLOATPRESSURE,                6);
 define_pd_global(intx, FreqInlineSize,               325);
+define_pd_global(intx, MinJumpTableSize,             10);
 #ifdef AMD64
 define_pd_global(intx, INTPRESSURE,                  13);
 define_pd_global(intx, InteriorEntryAlignment,       16);
--- a/hotspot/src/share/vm/ci/ciArray.cpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/share/vm/ci/ciArray.cpp	Wed Jul 05 19:11:53 2017 +0200
@@ -24,13 +24,92 @@
 
 #include "precompiled.hpp"
 #include "ci/ciArray.hpp"
+#include "ci/ciArrayKlass.hpp"
+#include "ci/ciConstant.hpp"
 #include "ci/ciKlass.hpp"
 #include "ci/ciUtilities.hpp"
+#include "oops/objArrayOop.hpp"
+#include "oops/typeArrayOop.hpp"
 
 // ciArray
 //
 // This class represents an arrayOop in the HotSpot virtual
 // machine.
+static BasicType fixup_element_type(BasicType bt) {
+  if (bt == T_ARRAY)    return T_OBJECT;
+  if (bt == T_BOOLEAN)  return T_BYTE;
+  return bt;
+}
+
+ciConstant ciArray::element_value_impl(BasicType elembt,
+                                       arrayOop ary,
+                                       int index) {
+  if (ary == NULL)
+    return ciConstant();
+  assert(ary->is_array(), "");
+  if (index < 0 || index >= ary->length())
+    return ciConstant();
+  ArrayKlass* ak = (ArrayKlass*) ary->klass();
+  BasicType abt = ak->element_type();
+  if (fixup_element_type(elembt) !=
+      fixup_element_type(abt))
+    return ciConstant();
+  switch (elembt) {
+  case T_ARRAY:
+  case T_OBJECT:
+    {
+      assert(ary->is_objArray(), "");
+      objArrayOop objary = (objArrayOop) ary;
+      oop elem = objary->obj_at(index);
+      ciEnv* env = CURRENT_ENV;
+      ciObject* box = env->get_object(elem);
+      return ciConstant(T_OBJECT, box);
+    }
+  }
+  assert(ary->is_typeArray(), "");
+  typeArrayOop tary = (typeArrayOop) ary;
+  jint value = 0;
+  switch (elembt) {
+  case T_LONG:          return ciConstant(tary->long_at(index));
+  case T_FLOAT:         return ciConstant(tary->float_at(index));
+  case T_DOUBLE:        return ciConstant(tary->double_at(index));
+  default:              return ciConstant();
+  case T_BYTE:          value = tary->byte_at(index);           break;
+  case T_BOOLEAN:       value = tary->byte_at(index) & 1;       break;
+  case T_SHORT:         value = tary->short_at(index);          break;
+  case T_CHAR:          value = tary->char_at(index);           break;
+  case T_INT:           value = tary->int_at(index);            break;
+  }
+  return ciConstant(elembt, value);
+}
+
+// ------------------------------------------------------------------
+// ciArray::element_value
+//
+// Current value of an element.
+// Returns T_ILLEGAL if there is no element at the given index.
+ciConstant ciArray::element_value(int index) {
+  BasicType elembt = element_basic_type();
+  GUARDED_VM_ENTRY(
+    return element_value_impl(elembt, get_arrayOop(), index);
+  )
+}
+
+// ------------------------------------------------------------------
+// ciArray::element_value_by_offset
+//
+// Current value of an element at the specified offset.
+// Returns T_ILLEGAL if there is no element at the given offset.
+ciConstant ciArray::element_value_by_offset(intptr_t element_offset) {
+  BasicType elembt = element_basic_type();
+  intptr_t shift  = exact_log2(type2aelembytes(elembt));
+  intptr_t header = arrayOopDesc::base_offset_in_bytes(elembt);
+  intptr_t index = (element_offset - header) >> shift;
+  intptr_t offset = header + ((intptr_t)index << shift);
+  if (offset != element_offset || index != (jint)index)
+    return ciConstant();
+  return element_value((jint) index);
+}
 
 // ------------------------------------------------------------------
 // ciArray::print_impl
--- a/hotspot/src/share/vm/ci/ciArray.hpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/share/vm/ci/ciArray.hpp	Wed Jul 05 19:11:53 2017 +0200
@@ -25,6 +25,8 @@
 #ifndef SHARE_VM_CI_CIARRAY_HPP
 #define SHARE_VM_CI_CIARRAY_HPP
 
+#include "ci/ciArrayKlass.hpp"
+#include "ci/ciConstant.hpp"
 #include "ci/ciObject.hpp"
 #include "oops/arrayOop.hpp"
 #include "oops/objArrayOop.hpp"
@@ -45,15 +47,30 @@
 
   ciArray(ciKlass* klass, int len) : ciObject(klass), _length(len) {}
 
-  arrayOop get_arrayOop() { return (arrayOop)get_oop(); }
+  arrayOop get_arrayOop() const { return (arrayOop)get_oop(); }
 
   const char* type_string() { return "ciArray"; }
 
   void print_impl(outputStream* st);
 
+  ciConstant element_value_impl(BasicType elembt, arrayOop ary, int index);
+
 public:
   int length() { return _length; }
 
+  // Convenience routines.
+  ciArrayKlass* array_type()         { return klass()->as_array_klass(); }
+  ciType*       element_type()       { return array_type()->element_type(); }
+  BasicType     element_basic_type() { return element_type()->basic_type(); }
+
+  // Current value of an element.
+  // Returns T_ILLEGAL if there is no element at the given index.
+  ciConstant element_value(int index);
+
+  // Current value of an element at the specified offset.
+  // Returns T_ILLEGAL if there is no element at the given offset.
+  ciConstant element_value_by_offset(intptr_t element_offset);
+
   // What kind of ciObject is this?
   bool is_array()        { return true; }
   bool is_java_object()  { return true; }
--- a/hotspot/src/share/vm/ci/ciConstant.hpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/share/vm/ci/ciConstant.hpp	Wed Jul 05 19:11:53 2017 +0200
@@ -41,7 +41,6 @@
   union {
     jint      _int;
     jlong     _long;
-    jint      _long_half[2];
     jfloat    _float;
     jdouble   _double;
     ciObject* _object;
@@ -111,6 +110,20 @@
     return _value._object;
   }
 
+  bool      is_null_or_zero() const {
+    if (!is_java_primitive(basic_type())) {
+      return as_object()->is_null_object();
+    } else if (type2size[basic_type()] == 1) {
+      // treat float bits as int, to avoid comparison with -0 and NaN
+      return (_value._int == 0);
+    } else if (type2size[basic_type()] == 2) {
+      // treat double bits as long, to avoid comparison with -0 and NaN
+      return (_value._long == 0);
+    } else {
+      return false;
+    }
+  }
+
   // Debugging output
   void print();
 };
--- a/hotspot/src/share/vm/ci/ciField.cpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/share/vm/ci/ciField.cpp	Wed Jul 05 19:11:53 2017 +0200
@@ -189,12 +189,14 @@
   _holder = CURRENT_ENV->get_instance_klass(fd->field_holder());
 
   // Check to see if the field is constant.
-  if (_holder->is_initialized() && this->is_final()) {
+  bool is_final = this->is_final();
+  bool is_stable = FoldStableValues && this->is_stable();
+  if (_holder->is_initialized() && (is_final || is_stable)) {
     if (!this->is_static()) {
       // A field can be constant if it's a final static field or if
       // it's a final non-static field of a trusted class (classes in
       // java.lang.invoke and sun.invoke packages and subpackages).
-      if (trust_final_non_static_fields(_holder)) {
+      if (is_stable || trust_final_non_static_fields(_holder)) {
         _is_constant = true;
         return;
       }
@@ -227,7 +229,6 @@
 
     Handle mirror = k->java_mirror();
 
-    _is_constant = true;
     switch(type()->basic_type()) {
     case T_BYTE:
       _constant_value = ciConstant(type()->basic_type(), mirror->byte_field(_offset));
@@ -273,6 +274,12 @@
         }
       }
     }
+    if (is_stable && _constant_value.is_null_or_zero()) {
+      // It is not a constant after all; treat it as uninitialized.
+      _is_constant = false;
+    } else {
+      _is_constant = true;
+    }
   } else {
     _is_constant = false;
   }
@@ -373,8 +380,11 @@
   tty->print(" signature=");
   _signature->print_symbol();
   tty->print(" offset=%d type=", _offset);
-  if (_type != NULL) _type->print_name();
-  else               tty->print("(reference)");
+  if (_type != NULL)
+    _type->print_name();
+  else
+    tty->print("(reference)");
+  tty->print(" flags=%04x", flags().as_int());
   tty->print(" is_constant=%s", bool_to_str(_is_constant));
   if (_is_constant && is_static()) {
     tty->print(" constant_value=");
--- a/hotspot/src/share/vm/ci/ciField.hpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/share/vm/ci/ciField.hpp	Wed Jul 05 19:11:53 2017 +0200
@@ -139,7 +139,10 @@
   //      non-constant fields.  These are java.lang.System.in
   //      and java.lang.System.out.  Abomination.
   //
-  // Note: the check for case 4 is not yet implemented.
+  // A field is also considered constant if it is marked @Stable
+  // and is non-null (or non-zero, if a primitive).
+  // For non-static fields, the null/zero check must be
+  // arranged by the user, as constant_value().is_null_or_zero().
   bool is_constant() { return _is_constant; }
 
   // Get the constant value of this field.
@@ -173,6 +176,7 @@
   bool is_protected   () { return flags().is_protected(); }
   bool is_static      () { return flags().is_static(); }
   bool is_final       () { return flags().is_final(); }
+  bool is_stable      () { return flags().is_stable(); }
   bool is_volatile    () { return flags().is_volatile(); }
   bool is_transient   () { return flags().is_transient(); }
 
--- a/hotspot/src/share/vm/ci/ciFlags.hpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/share/vm/ci/ciFlags.hpp	Wed Jul 05 19:11:53 2017 +0200
@@ -59,6 +59,7 @@
   bool is_interface   () const         { return (_flags & JVM_ACC_INTERFACE   ) != 0; }
   bool is_abstract    () const         { return (_flags & JVM_ACC_ABSTRACT    ) != 0; }
   bool is_strict      () const         { return (_flags & JVM_ACC_STRICT      ) != 0; }
+  bool is_stable      () const         { return (_flags & JVM_ACC_FIELD_STABLE) != 0; }
 
   // Conversion
   jint   as_int()                      { return _flags; }
--- a/hotspot/src/share/vm/ci/ciInstance.cpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/share/vm/ci/ciInstance.cpp	Wed Jul 05 19:11:53 2017 +0200
@@ -127,6 +127,8 @@
 ciConstant ciInstance::field_value_by_offset(int field_offset) {
   ciInstanceKlass* ik = klass()->as_instance_klass();
   ciField* field = ik->get_field_by_offset(field_offset, false);
+  if (field == NULL)
+    return ciConstant();  // T_ILLEGAL
   return field_value(field);
 }
 
--- a/hotspot/src/share/vm/ci/ciTypeArray.cpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/share/vm/ci/ciTypeArray.cpp	Wed Jul 05 19:11:53 2017 +0200
@@ -39,5 +39,10 @@
 jchar ciTypeArray::char_at(int index) {
   VM_ENTRY_MARK;
   assert(index >= 0 && index < length(), "out of range");
-  return get_typeArrayOop()->char_at(index);
+  jchar c = get_typeArrayOop()->char_at(index);
+#ifdef ASSERT
+  jchar d = element_value(index).as_char();
+  assert(c == d, "");
+#endif //ASSERT
+  return c;
 }
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp	Wed Jul 05 19:11:53 2017 +0200
@@ -1774,6 +1774,10 @@
     if (_location != _in_method)  break;  // only allow for methods
     if (!privileged)              break;  // only allow in privileged code
     return _method_LambdaForm_Hidden;
+  case vmSymbols::VM_SYMBOL_ENUM_NAME(sun_invoke_Stable_signature):
+    if (_location != _in_field)   break;  // only allow for fields
+    if (!privileged)              break;  // only allow in privileged code
+    return _field_Stable;
   case vmSymbols::VM_SYMBOL_ENUM_NAME(sun_misc_Contended_signature):
     if (_location != _in_field && _location != _in_class)          break;  // only allow for fields and classes
     if (!EnableContended || (RestrictContended && !privileged))    break;  // honor privileges
@@ -1786,6 +1790,8 @@
 void ClassFileParser::FieldAnnotationCollector::apply_to(FieldInfo* f) {
   if (is_contended())
     f->set_contended_group(contended_group());
+  if (is_stable())
+    f->set_stable(true);
 }
 
 ClassFileParser::FieldAnnotationCollector::~FieldAnnotationCollector() {
--- a/hotspot/src/share/vm/classfile/classFileParser.hpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/share/vm/classfile/classFileParser.hpp	Wed Jul 05 19:11:53 2017 +0200
@@ -125,6 +125,7 @@
       _method_LambdaForm_Compiled,
       _method_LambdaForm_Hidden,
       _sun_misc_Contended,
+      _field_Stable,
       _annotation_LIMIT
     };
     const Location _location;
@@ -143,14 +144,23 @@
       assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob");
       _annotations_present |= nth_bit((int)id);
     }
+
+    void remove_annotation(ID id) {
+      assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob");
+      _annotations_present &= ~nth_bit((int)id);
+    }
+
     // Report if the annotation is present.
-    bool has_any_annotations() { return _annotations_present != 0; }
-    bool has_annotation(ID id) { return (nth_bit((int)id) & _annotations_present) != 0; }
+    bool has_any_annotations() const { return _annotations_present != 0; }
+    bool has_annotation(ID id) const { return (nth_bit((int)id) & _annotations_present) != 0; }
 
     void set_contended_group(u2 group) { _contended_group = group; }
-    u2 contended_group() { return _contended_group; }
+    u2 contended_group() const { return _contended_group; }
 
-    bool is_contended() { return has_annotation(_sun_misc_Contended); }
+    bool is_contended() const { return has_annotation(_sun_misc_Contended); }
+
+    void set_stable(bool stable) { set_annotation(_field_Stable); }
+    bool is_stable() const { return has_annotation(_field_Stable); }
   };
 
   // This class also doubles as a holder for metadata cleanup.
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp	Wed Jul 05 19:11:53 2017 +0200
@@ -270,6 +270,7 @@
   template(java_lang_invoke_LambdaForm,               "java/lang/invoke/LambdaForm")              \
   template(java_lang_invoke_ForceInline_signature,    "Ljava/lang/invoke/ForceInline;")           \
   template(java_lang_invoke_DontInline_signature,     "Ljava/lang/invoke/DontInline;")            \
+  template(sun_invoke_Stable_signature,               "Lsun/invoke/Stable;")                      \
   template(java_lang_invoke_LambdaForm_Compiled_signature, "Ljava/lang/invoke/LambdaForm$Compiled;") \
   template(java_lang_invoke_LambdaForm_Hidden_signature, "Ljava/lang/invoke/LambdaForm$Hidden;")  \
   template(java_lang_invoke_MagicLambdaImpl,          "java/lang/invoke/MagicLambdaImpl")         \
--- a/hotspot/src/share/vm/oops/fieldInfo.hpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/share/vm/oops/fieldInfo.hpp	Wed Jul 05 19:11:53 2017 +0200
@@ -240,6 +240,14 @@
     return (access_flags() & JVM_ACC_FIELD_INTERNAL) != 0;
   }
 
+  bool is_stable() const {
+    return (access_flags() & JVM_ACC_FIELD_STABLE) != 0;
+  }
+  void set_stable(bool z) {
+    if (z) _shorts[access_flags_offset] |=  JVM_ACC_FIELD_STABLE;
+    else   _shorts[access_flags_offset] &= ~JVM_ACC_FIELD_STABLE;
+  }
+
   Symbol* lookup_symbol(int symbol_index) const {
     assert(is_internal(), "only internal fields");
     return vmSymbols::symbol_at((vmSymbols::SID)symbol_index);
--- a/hotspot/src/share/vm/opto/c2_globals.hpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/share/vm/opto/c2_globals.hpp	Wed Jul 05 19:11:53 2017 +0200
@@ -421,7 +421,7 @@
   product(bool, UseDivMod, true,                                            \
           "Use combined DivMod instruction if available")                   \
                                                                             \
-  product(intx, MinJumpTableSize, 18,                                       \
+  product_pd(intx, MinJumpTableSize,                                        \
           "Minimum number of targets in a generated jump table")            \
                                                                             \
   product(intx, MaxJumpTableSize, 65000,                                    \
@@ -448,6 +448,9 @@
   product(bool, EliminateAutoBox, true,                                     \
           "Control optimizations for autobox elimination")                  \
                                                                             \
+  experimental(bool, UseImplicitStableValues, false,                        \
+          "Mark well-known stable fields as such (e.g. String.value)")      \
+                                                                            \
   product(intx, AutoBoxCacheMax, 128,                                       \
           "Sets max value cached by the java.lang.Integer autobox cache")   \
                                                                             \
--- a/hotspot/src/share/vm/opto/compile.cpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/share/vm/opto/compile.cpp	Wed Jul 05 19:11:53 2017 +0200
@@ -1297,6 +1297,10 @@
 
   // Array pointers need some flattening
   const TypeAryPtr *ta = tj->isa_aryptr();
+  if (ta && ta->is_stable()) {
+    // Erase stability property for alias analysis.
+    tj = ta = ta->cast_to_stable(false);
+  }
   if( ta && is_known_inst ) {
     if ( offset != Type::OffsetBot &&
          offset > arrayOopDesc::length_offset_in_bytes() ) {
@@ -1497,6 +1501,7 @@
   _index = i;
   _adr_type = at;
   _field = NULL;
+  _element = NULL;
   _is_rewritable = true; // default
   const TypeOopPtr *atoop = (at != NULL) ? at->isa_oopptr() : NULL;
   if (atoop != NULL && atoop->is_known_instance()) {
@@ -1615,6 +1620,16 @@
           && flat->is_instptr()->klass() == env()->Class_klass())
         alias_type(idx)->set_rewritable(false);
     }
+    if (flat->isa_aryptr()) {
+#ifdef ASSERT
+      const int header_size_min  = arrayOopDesc::base_offset_in_bytes(T_BYTE);
+      // (T_BYTE has the weakest alignment and size restrictions...)
+      assert(flat->offset() < header_size_min, "array body reference must be OffsetBot");
+#endif
+      if (flat->offset() == TypePtr::OffsetBot) {
+        alias_type(idx)->set_element(flat->is_aryptr()->elem());
+      }
+    }
     if (flat->isa_klassptr()) {
       if (flat->offset() == in_bytes(Klass::super_check_offset_offset()))
         alias_type(idx)->set_rewritable(false);
@@ -1677,7 +1692,7 @@
   else
     t = TypeOopPtr::make_from_klass_raw(field->holder());
   AliasType* atp = alias_type(t->add_offset(field->offset_in_bytes()), field);
-  assert(field->is_final() == !atp->is_rewritable(), "must get the rewritable bits correct");
+  assert((field->is_final() || field->is_stable()) == !atp->is_rewritable(), "must get the rewritable bits correct");
   return atp;
 }
 
--- a/hotspot/src/share/vm/opto/compile.hpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/share/vm/opto/compile.hpp	Wed Jul 05 19:11:53 2017 +0200
@@ -72,6 +72,7 @@
 class StartNode;
 class SafePointNode;
 class JVMState;
+class Type;
 class TypeData;
 class TypePtr;
 class TypeOopPtr;
@@ -119,6 +120,7 @@
     int             _index;         // unique index, used with MergeMemNode
     const TypePtr*  _adr_type;      // normalized address type
     ciField*        _field;         // relevant instance field, or null if none
+    const Type*     _element;       // relevant array element type, or null if none
     bool            _is_rewritable; // false if the memory is write-once only
     int             _general_index; // if this is type is an instance, the general
                                     // type that this is an instance of
@@ -129,6 +131,7 @@
     int             index()         const { return _index; }
     const TypePtr*  adr_type()      const { return _adr_type; }
     ciField*        field()         const { return _field; }
+    const Type*     element()       const { return _element; }
     bool            is_rewritable() const { return _is_rewritable; }
     bool            is_volatile()   const { return (_field ? _field->is_volatile() : false); }
     int             general_index() const { return (_general_index != 0) ? _general_index : _index; }
@@ -137,7 +140,14 @@
     void set_field(ciField* f) {
       assert(!_field,"");
       _field = f;
-      if (f->is_final())  _is_rewritable = false;
+      if (f->is_final() || f->is_stable()) {
+        // In the case of @Stable, multiple writes are possible but may be assumed to be no-ops.
+        _is_rewritable = false;
+      }
+    }
+    void set_element(const Type* e) {
+      assert(_element == NULL, "");
+      _element = e;
     }
 
     void print_on(outputStream* st) PRODUCT_RETURN;
--- a/hotspot/src/share/vm/opto/graphKit.cpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/share/vm/opto/graphKit.cpp	Wed Jul 05 19:11:53 2017 +0200
@@ -3825,8 +3825,13 @@
                                                    TypeAry::make(TypeInt::CHAR,TypeInt::POS),
                                                    ciTypeArrayKlass::make(T_CHAR), true, 0);
   int value_field_idx = C->get_alias_index(value_field_type);
-  return make_load(ctrl, basic_plus_adr(str, str, value_offset),
-                   value_type, T_OBJECT, value_field_idx);
+  Node* load = make_load(ctrl, basic_plus_adr(str, str, value_offset),
+                         value_type, T_OBJECT, value_field_idx);
+  // String.value field is known to be @Stable.
+  if (UseImplicitStableValues) {
+    load = cast_array_to_stable(load, value_type);
+  }
+  return load;
 }
 
 void GraphKit::store_String_offset(Node* ctrl, Node* str, Node* value) {
@@ -3844,9 +3849,6 @@
   const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(),
                                                      false, NULL, 0);
   const TypePtr* value_field_type = string_type->add_offset(value_offset);
-  const TypeAryPtr*  value_type = TypeAryPtr::make(TypePtr::NotNull,
-                                                   TypeAry::make(TypeInt::CHAR,TypeInt::POS),
-                                                   ciTypeArrayKlass::make(T_CHAR), true, 0);
   int value_field_idx = C->get_alias_index(value_field_type);
   store_to_memory(ctrl, basic_plus_adr(str, value_offset),
                   value, T_OBJECT, value_field_idx);
@@ -3861,3 +3863,9 @@
   store_to_memory(ctrl, basic_plus_adr(str, count_offset),
                   value, T_INT, count_field_idx);
 }
+
+Node* GraphKit::cast_array_to_stable(Node* ary, const TypeAryPtr* ary_type) {
+  // Reify the property as a CastPP node in Ideal graph to comply with monotonicity
+  // assumption of CCP analysis.
+  return _gvn.transform(new(C) CastPPNode(ary, ary_type->cast_to_stable(true)));
+}
--- a/hotspot/src/share/vm/opto/graphKit.hpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/share/vm/opto/graphKit.hpp	Wed Jul 05 19:11:53 2017 +0200
@@ -836,6 +836,9 @@
   // Insert a loop predicate into the graph
   void add_predicate(int nargs = 0);
   void add_predicate_impl(Deoptimization::DeoptReason reason, int nargs);
+
+  // Produce new array node of stable type
+  Node* cast_array_to_stable(Node* ary, const TypeAryPtr* ary_type);
 };
 
 // Helper class to support building of control flow branches. Upon
--- a/hotspot/src/share/vm/opto/library_call.cpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/share/vm/opto/library_call.cpp	Wed Jul 05 19:11:53 2017 +0200
@@ -1280,6 +1280,11 @@
   const TypeAry* target_array_type = TypeAry::make(TypeInt::CHAR, TypeInt::make(0, target_length, Type::WidenMin));
   const TypeAryPtr* target_type = TypeAryPtr::make(TypePtr::BotPTR, target_array_type, target_array->klass(), true, Type::OffsetBot);
 
+  // String.value field is known to be @Stable.
+  if (UseImplicitStableValues) {
+    target = cast_array_to_stable(target, target_type);
+  }
+
   IdealKit kit(this, false, true);
 #define __ kit.
   Node* zero             = __ ConI(0);
--- a/hotspot/src/share/vm/opto/memnode.cpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/share/vm/opto/memnode.cpp	Wed Jul 05 19:11:53 2017 +0200
@@ -962,6 +962,19 @@
   return (uintptr_t)in(Control) + (uintptr_t)in(Memory) + (uintptr_t)in(Address);
 }
 
+static bool skip_through_membars(Compile::AliasType* atp, const TypeInstPtr* tp, bool eliminate_boxing) {
+  if ((atp != NULL) && (atp->index() >= Compile::AliasIdxRaw)) {
+    bool non_volatile = (atp->field() != NULL) && !atp->field()->is_volatile();
+    bool is_stable_ary = FoldStableValues &&
+                         (tp != NULL) && (tp->isa_aryptr() != NULL) &&
+                         tp->isa_aryptr()->is_stable();
+
+    return (eliminate_boxing && non_volatile) || is_stable_ary;
+  }
+
+  return false;
+}
+
 //---------------------------can_see_stored_value------------------------------
 // This routine exists to make sure this set of tests is done the same
 // everywhere.  We need to make a coordinated change: first LoadNode::Ideal
@@ -976,11 +989,9 @@
   const TypeInstPtr* tp = phase->type(ld_adr)->isa_instptr();
   Compile::AliasType* atp = (tp != NULL) ? phase->C->alias_type(tp) : NULL;
   // This is more general than load from boxing objects.
-  if (phase->C->eliminate_boxing() && (atp != NULL) &&
-      (atp->index() >= Compile::AliasIdxRaw) &&
-      (atp->field() != NULL) && !atp->field()->is_volatile()) {
+  if (skip_through_membars(atp, tp, phase->C->eliminate_boxing())) {
     uint alias_idx = atp->index();
-    bool final = atp->field()->is_final();
+    bool final = !atp->is_rewritable();
     Node* result = NULL;
     Node* current = st;
     // Skip through chains of MemBarNodes checking the MergeMems for
@@ -1015,7 +1026,6 @@
     }
   }
 
-
   // Loop around twice in the case Load -> Initialize -> Store.
   // (See PhaseIterGVN::add_users_to_worklist, which knows about this case.)
   for (int trip = 0; trip <= 1; trip++) {
@@ -1577,6 +1587,40 @@
   return NULL;
 }
 
+// Try to constant-fold a stable array element.
+static const Type* fold_stable_ary_elem(const TypeAryPtr* ary, int off, BasicType loadbt) {
+  assert(ary->is_stable(), "array should be stable");
+
+  if (ary->const_oop() != NULL) {
+    // Decode the results of GraphKit::array_element_address.
+    ciArray* aobj = ary->const_oop()->as_array();
+    ciConstant con = aobj->element_value_by_offset(off);
+
+    if (con.basic_type() != T_ILLEGAL && !con.is_null_or_zero()) {
+      const Type* con_type = Type::make_from_constant(con);
+      if (con_type != NULL) {
+        if (con_type->isa_aryptr()) {
+          // Join with the array element type, in case it is also stable.
+          int dim = ary->stable_dimension();
+          con_type = con_type->is_aryptr()->cast_to_stable(true, dim-1);
+        }
+        if (loadbt == T_NARROWOOP && con_type->isa_oopptr()) {
+          con_type = con_type->make_narrowoop();
+        }
+#ifndef PRODUCT
+        if (TraceIterativeGVN) {
+          tty->print("FoldStableValues: array element [off=%d]: con_type=", off);
+          con_type->dump(); tty->cr();
+        }
+#endif //PRODUCT
+        return con_type;
+      }
+    }
+  }
+
+  return NULL;
+}
+
 //------------------------------Value-----------------------------------------
 const Type *LoadNode::Value( PhaseTransform *phase ) const {
   // Either input is TOP ==> the result is TOP
@@ -1591,8 +1635,31 @@
   Compile* C = phase->C;
 
   // Try to guess loaded type from pointer type
-  if (tp->base() == Type::AryPtr) {
-    const Type *t = tp->is_aryptr()->elem();
+  if (tp->isa_aryptr()) {
+    const TypeAryPtr* ary = tp->is_aryptr();
+    const Type *t = ary->elem();
+
+    // Determine whether the reference is beyond the header or not, by comparing
+    // the offset against the offset of the start of the array's data.
+    // Different array types begin at slightly different offsets (12 vs. 16).
+    // We choose T_BYTE as an example base type that is least restrictive
+    // as to alignment, which will therefore produce the smallest
+    // possible base offset.
+    const int min_base_off = arrayOopDesc::base_offset_in_bytes(T_BYTE);
+    const bool off_beyond_header = ((uint)off >= (uint)min_base_off);
+
+    // Try to constant-fold a stable array element.
+    if (FoldStableValues && ary->is_stable()) {
+      // Make sure the reference is not into the header
+      if (off_beyond_header && off != Type::OffsetBot) {
+        assert(adr->is_AddP() && adr->in(AddPNode::Offset)->is_Con(), "offset is a constant");
+        const Type* con_type = fold_stable_ary_elem(ary, off, memory_type());
+        if (con_type != NULL) {
+          return con_type;
+        }
+      }
+    }
+
     // Don't do this for integer types. There is only potential profit if
     // the element type t is lower than _type; that is, for int types, if _type is
     // more restrictive than t.  This only happens here if one is short and the other
@@ -1613,14 +1680,7 @@
         && Opcode() != Op_LoadKlass && Opcode() != Op_LoadNKlass) {
       // t might actually be lower than _type, if _type is a unique
       // concrete subclass of abstract class t.
-      // Make sure the reference is not into the header, by comparing
-      // the offset against the offset of the start of the array's data.
-      // Different array types begin at slightly different offsets (12 vs. 16).
-      // We choose T_BYTE as an example base type that is least restrictive
-      // as to alignment, which will therefore produce the smallest
-      // possible base offset.
-      const int min_base_off = arrayOopDesc::base_offset_in_bytes(T_BYTE);
-      if ((uint)off >= (uint)min_base_off) {  // is the offset beyond the header?
+      if (off_beyond_header) {  // is the offset beyond the header?
         const Type* jt = t->join(_type);
         // In any case, do not allow the join, per se, to empty out the type.
         if (jt->empty() && !t->empty()) {
--- a/hotspot/src/share/vm/opto/parse.hpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/share/vm/opto/parse.hpp	Wed Jul 05 19:11:53 2017 +0200
@@ -518,7 +518,7 @@
 
   // loading from a constant field or the constant pool
   // returns false if push failed (non-perm field constants only, not ldcs)
-  bool push_constant(ciConstant con, bool require_constant = false, bool is_autobox_cache = false);
+  bool push_constant(ciConstant con, bool require_constant = false, bool is_autobox_cache = false, const Type* basic_type = NULL);
 
   // implementation of object creation bytecodes
   void emit_guard_for_new(ciInstanceKlass* klass);
--- a/hotspot/src/share/vm/opto/parse3.cpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/share/vm/opto/parse3.cpp	Wed Jul 05 19:11:53 2017 +0200
@@ -147,7 +147,15 @@
 void Parse::do_get_xxx(Node* obj, ciField* field, bool is_field) {
   // Does this field have a constant value?  If so, just push the value.
   if (field->is_constant()) {
-    // final field
+    // final or stable field
+    const Type* stable_type = NULL;
+    if (FoldStableValues && field->is_stable()) {
+      stable_type = Type::get_const_type(field->type());
+      if (field->type()->is_array_klass()) {
+        int stable_dimension = field->type()->as_array_klass()->dimension();
+        stable_type = stable_type->is_aryptr()->cast_to_stable(true, stable_dimension);
+      }
+    }
     if (field->is_static()) {
       // final static field
       if (C->eliminate_boxing()) {
@@ -167,11 +175,10 @@
           }
         }
       }
-      if (push_constant(field->constant_value()))
+      if (push_constant(field->constant_value(), false, false, stable_type))
         return;
-    }
-    else {
-      // final non-static field
+    } else {
+      // final or stable non-static field
       // Treat final non-static fields of trusted classes (classes in
       // java.lang.invoke and sun.invoke packages and subpackages) as
       // compile time constants.
@@ -179,8 +186,12 @@
         const TypeOopPtr* oop_ptr = obj->bottom_type()->isa_oopptr();
         ciObject* constant_oop = oop_ptr->const_oop();
         ciConstant constant = field->constant_value_of(constant_oop);
-        if (push_constant(constant, true))
-          return;
+        if (FoldStableValues && field->is_stable() && constant.is_null_or_zero()) {
+          // fall through to field load; the field is not yet initialized
+        } else {
+          if (push_constant(constant, true, false, stable_type))
+            return;
+        }
       }
     }
   }
@@ -301,7 +312,8 @@
   // Note the presence of writes to final non-static fields, so that we
   // can insert a memory barrier later on to keep the writes from floating
   // out of the constructor.
-  if (is_field && field->is_final()) {
+  // Any method can write a @Stable field; insert memory barriers after those also.
+  if (is_field && (field->is_final() || field->is_stable())) {
     set_wrote_final(true);
     // Preserve allocation ptr to create precedent edge to it in membar
     // generated on exit from constructor.
@@ -314,35 +326,21 @@
 }
 
 
-bool Parse::push_constant(ciConstant constant, bool require_constant, bool is_autobox_cache) {
+
+bool Parse::push_constant(ciConstant constant, bool require_constant, bool is_autobox_cache, const Type* stable_type) {
+  const Type* con_type = Type::make_from_constant(constant, require_constant, is_autobox_cache);
   switch (constant.basic_type()) {
-  case T_BOOLEAN:  push( intcon(constant.as_boolean()) ); break;
-  case T_INT:      push( intcon(constant.as_int())     ); break;
-  case T_CHAR:     push( intcon(constant.as_char())    ); break;
-  case T_BYTE:     push( intcon(constant.as_byte())    ); break;
-  case T_SHORT:    push( intcon(constant.as_short())   ); break;
-  case T_FLOAT:    push( makecon(TypeF::make(constant.as_float())) );  break;
-  case T_DOUBLE:   push_pair( makecon(TypeD::make(constant.as_double())) );  break;
-  case T_LONG:     push_pair( longcon(constant.as_long()) ); break;
   case T_ARRAY:
-  case T_OBJECT: {
+  case T_OBJECT:
     // cases:
     //   can_be_constant    = (oop not scavengable || ScavengeRootsInCode != 0)
     //   should_be_constant = (oop not scavengable || ScavengeRootsInCode >= 2)
     // An oop is not scavengable if it is in the perm gen.
-    ciObject* oop_constant = constant.as_object();
-    if (oop_constant->is_null_object()) {
-      push( zerocon(T_OBJECT) );
-      break;
-    } else if (require_constant || oop_constant->should_be_constant()) {
-      push( makecon(TypeOopPtr::make_from_constant(oop_constant, require_constant, is_autobox_cache)) );
-      break;
-    } else {
-      // we cannot inline the oop, but we can use it later to narrow a type
-      return false;
-    }
-  }
-  case T_ILLEGAL: {
+    if (stable_type != NULL && con_type != NULL && con_type->isa_oopptr())
+      con_type = con_type->join(stable_type);
+    break;
+
+  case T_ILLEGAL:
     // Invalid ciConstant returned due to OutOfMemoryError in the CI
     assert(C->env()->failing(), "otherwise should not see this");
     // These always occur because of object types; we are going to
@@ -350,17 +348,16 @@
     push( zerocon(T_OBJECT) );
     return false;
   }
-  default:
-    ShouldNotReachHere();
+
+  if (con_type == NULL)
+    // we cannot inline the oop, but we can use it later to narrow a type
     return false;
-  }
 
-  // success
+  push_node(constant.basic_type(), makecon(con_type));
   return true;
 }
 
 
-
 //=============================================================================
 void Parse::do_anewarray() {
   bool will_link;
--- a/hotspot/src/share/vm/opto/type.cpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/share/vm/opto/type.cpp	Wed Jul 05 19:11:53 2017 +0200
@@ -189,6 +189,38 @@
 }
 
 
+//-----------------------make_from_constant------------------------------------
+const Type* Type::make_from_constant(ciConstant constant,
+                                     bool require_constant, bool is_autobox_cache) {
+  switch (constant.basic_type()) {
+  case T_BOOLEAN:  return TypeInt::make(constant.as_boolean());
+  case T_CHAR:     return TypeInt::make(constant.as_char());
+  case T_BYTE:     return TypeInt::make(constant.as_byte());
+  case T_SHORT:    return TypeInt::make(constant.as_short());
+  case T_INT:      return TypeInt::make(constant.as_int());
+  case T_LONG:     return TypeLong::make(constant.as_long());
+  case T_FLOAT:    return TypeF::make(constant.as_float());
+  case T_DOUBLE:   return TypeD::make(constant.as_double());
+  case T_ARRAY:
+  case T_OBJECT:
+    {
+      // cases:
+      //   can_be_constant    = (oop not scavengable || ScavengeRootsInCode != 0)
+      //   should_be_constant = (oop not scavengable || ScavengeRootsInCode >= 2)
+      // An oop is not scavengable if it is in the perm gen.
+      ciObject* oop_constant = constant.as_object();
+      if (oop_constant->is_null_object()) {
+        return Type::get_zero_type(T_OBJECT);
+      } else if (require_constant || oop_constant->should_be_constant()) {
+        return TypeOopPtr::make_from_constant(oop_constant, require_constant, is_autobox_cache);
+      }
+    }
+  }
+  // Fall through to failure
+  return NULL;
+}
+
+
 //------------------------------make-------------------------------------------
 // Create a simple Type, with default empty symbol sets.  Then hashcons it
 // and look for an existing copy in the type dictionary.
@@ -1824,12 +1856,12 @@
 }
 
 //------------------------------make-------------------------------------------
-const TypeAry *TypeAry::make( const Type *elem, const TypeInt *size) {
+const TypeAry* TypeAry::make(const Type* elem, const TypeInt* size, bool stable) {
   if (UseCompressedOops && elem->isa_oopptr()) {
     elem = elem->make_narrowoop();
   }
   size = normalize_array_size(size);
-  return (TypeAry*)(new TypeAry(elem,size))->hashcons();
+  return (TypeAry*)(new TypeAry(elem,size,stable))->hashcons();
 }
 
 //------------------------------meet-------------------------------------------
@@ -1850,7 +1882,8 @@
   case Array: {                 // Meeting 2 arrays?
     const TypeAry *a = t->is_ary();
     return TypeAry::make(_elem->meet(a->_elem),
-                         _size->xmeet(a->_size)->is_int());
+                         _size->xmeet(a->_size)->is_int(),
+                         _stable & a->_stable);
   }
   case Top:
     break;
@@ -1863,7 +1896,7 @@
 const Type *TypeAry::xdual() const {
   const TypeInt* size_dual = _size->dual()->is_int();
   size_dual = normalize_array_size(size_dual);
-  return new TypeAry( _elem->dual(), size_dual);
+  return new TypeAry(_elem->dual(), size_dual, !_stable);
 }
 
 //------------------------------eq---------------------------------------------
@@ -1871,13 +1904,14 @@
 bool TypeAry::eq( const Type *t ) const {
   const TypeAry *a = (const TypeAry*)t;
   return _elem == a->_elem &&
+    _stable == a->_stable &&
     _size == a->_size;
 }
 
 //------------------------------hash-------------------------------------------
 // Type-specific hashing function.
 int TypeAry::hash(void) const {
-  return (intptr_t)_elem + (intptr_t)_size;
+  return (intptr_t)_elem + (intptr_t)_size + (_stable ? 43 : 0);
 }
 
 //----------------------interface_vs_oop---------------------------------------
@@ -1894,6 +1928,7 @@
 //------------------------------dump2------------------------------------------
 #ifndef PRODUCT
 void TypeAry::dump2( Dict &d, uint depth, outputStream *st ) const {
+  if (_stable)  st->print("stable:");
   _elem->dump2(d, depth, st);
   st->print("[");
   _size->dump2(d, depth, st);
@@ -3457,11 +3492,39 @@
   assert(new_size != NULL, "");
   new_size = narrow_size_type(new_size);
   if (new_size == size())  return this;
-  const TypeAry* new_ary = TypeAry::make(elem(), new_size);
+  const TypeAry* new_ary = TypeAry::make(elem(), new_size, is_stable());
   return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id);
 }
 
 
+//------------------------------cast_to_stable---------------------------------
+const TypeAryPtr* TypeAryPtr::cast_to_stable(bool stable, int stable_dimension) const {
+  if (stable_dimension <= 0 || (stable_dimension == 1 && stable == this->is_stable()))
+    return this;
+
+  const Type* elem = this->elem();
+  const TypePtr* elem_ptr = elem->make_ptr();
+
+  if (stable_dimension > 1 && elem_ptr != NULL && elem_ptr->isa_aryptr()) {
+    // If this is widened from a narrow oop, TypeAry::make will re-narrow it.
+    elem = elem_ptr = elem_ptr->is_aryptr()->cast_to_stable(stable, stable_dimension - 1);
+  }
+
+  const TypeAry* new_ary = TypeAry::make(elem, size(), stable);
+
+  return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id);
+}
+
+//-----------------------------stable_dimension--------------------------------
+int TypeAryPtr::stable_dimension() const {
+  if (!is_stable())  return 0;
+  int dim = 1;
+  const TypePtr* elem_ptr = elem()->make_ptr();
+  if (elem_ptr != NULL && elem_ptr->isa_aryptr())
+    dim += elem_ptr->is_aryptr()->stable_dimension();
+  return dim;
+}
+
 //------------------------------eq---------------------------------------------
 // Structural equality check for Type representations
 bool TypeAryPtr::eq( const Type *t ) const {
@@ -3570,7 +3633,7 @@
         // Something like byte[int+] meets char[int+].
         // This must fall to bottom, not (int[-128..65535])[int+].
         instance_id = InstanceBot;
-        tary = TypeAry::make(Type::BOTTOM, tary->_size);
+        tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable);
       }
     } else // Non integral arrays.
     // Must fall to bottom if exact klasses in upper lattice
@@ -3584,7 +3647,7 @@
          (tap ->_klass_is_exact && !tap->klass()->is_subtype_of(klass())) ||
          // 'this' is exact and super or unrelated:
          (this->_klass_is_exact && !klass()->is_subtype_of(tap->klass())))) {
-      tary = TypeAry::make(Type::BOTTOM, tary->_size);
+      tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable);
       return make( NotNull, NULL, tary, lazy_klass, false, off, InstanceBot );
     }
 
--- a/hotspot/src/share/vm/opto/type.hpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/share/vm/opto/type.hpp	Wed Jul 05 19:11:53 2017 +0200
@@ -372,6 +372,10 @@
   // Mapping from CI type system to compiler type:
   static const Type* get_typeflow_type(ciType* type);
 
+  static const Type* make_from_constant(ciConstant constant,
+                                        bool require_constant = false,
+                                        bool is_autobox_cache = false);
+
 private:
   // support arrays
   static const BasicType _basic_type[];
@@ -588,8 +592,8 @@
 //------------------------------TypeAry----------------------------------------
 // Class of Array Types
 class TypeAry : public Type {
-  TypeAry( const Type *elem, const TypeInt *size) : Type(Array),
-    _elem(elem), _size(size) {}
+  TypeAry(const Type* elem, const TypeInt* size, bool stable) : Type(Array),
+      _elem(elem), _size(size), _stable(stable) {}
 public:
   virtual bool eq( const Type *t ) const;
   virtual int  hash() const;             // Type specific hashing
@@ -599,10 +603,11 @@
 private:
   const Type *_elem;            // Element type of array
   const TypeInt *_size;         // Elements in array
+  const bool _stable;           // Are elements @Stable?
   friend class TypeAryPtr;
 
 public:
-  static const TypeAry *make(  const Type *elem, const TypeInt *size);
+  static const TypeAry* make(const Type* elem, const TypeInt* size, bool stable = false);
 
   virtual const Type *xmeet( const Type *t ) const;
   virtual const Type *xdual() const;    // Compute dual right now.
@@ -988,6 +993,7 @@
   const TypeAry* ary() const  { return _ary; }
   const Type*    elem() const { return _ary->_elem; }
   const TypeInt* size() const { return _ary->_size; }
+  bool      is_stable() const { return _ary->_stable; }
 
   bool is_autobox_cache() const { return _is_autobox_cache; }
 
@@ -1011,6 +1017,9 @@
   virtual const Type *xmeet( const Type *t ) const;
   virtual const Type *xdual() const;    // Compute dual right now.
 
+  const TypeAryPtr* cast_to_stable(bool stable, int stable_dimension = 1) const;
+  int stable_dimension() const;
+
   // Convenience common pre-built types.
   static const TypeAryPtr *RANGE;
   static const TypeAryPtr *OOPS;
--- a/hotspot/src/share/vm/runtime/globals.hpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/share/vm/runtime/globals.hpp	Wed Jul 05 19:11:53 2017 +0200
@@ -3649,6 +3649,9 @@
   experimental(bool, TrustFinalNonStaticFields, false,                      \
           "trust final non-static declarations for constant folding")       \
                                                                             \
+  experimental(bool, FoldStableValues, false,                               \
+          "Private flag to control optimizations for stable variables")     \
+                                                                            \
   develop(bool, TraceInvokeDynamic, false,                                  \
           "trace internal invoke dynamic operations")                       \
                                                                             \
--- a/hotspot/src/share/vm/runtime/interfaceSupport.hpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/share/vm/runtime/interfaceSupport.hpp	Wed Jul 05 19:11:53 2017 +0200
@@ -471,16 +471,6 @@
     VM_ENTRY_BASE(result_type, header, thread)                       \
     debug_only(VMEntryWrapper __vew;)
 
-// Another special case for nmethod_entry_point so the nmethod that the
-// interpreter is about to branch to doesn't get flushed before as we
-// branch to it's interpreter_entry_point.  Skip stress testing here too.
-// Also we don't allow async exceptions because it is just too painful.
-#define IRT_ENTRY_FOR_NMETHOD(result_type, header)                   \
-  result_type header {                                               \
-    nmethodLocker _nmlock(nm);                                       \
-    ThreadInVMfromJavaNoAsyncException __tiv(thread);                                \
-    VM_ENTRY_BASE(result_type, header, thread)
-
 #define IRT_END }
 
 
--- a/hotspot/src/share/vm/utilities/accessFlags.hpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/src/share/vm/utilities/accessFlags.hpp	Wed Jul 05 19:11:53 2017 +0200
@@ -78,11 +78,13 @@
   JVM_ACC_FIELD_ACCESS_WATCHED       = 0x00002000,  // field access is watched by JVMTI
   JVM_ACC_FIELD_MODIFICATION_WATCHED = 0x00008000,  // field modification is watched by JVMTI
   JVM_ACC_FIELD_INTERNAL             = 0x00000400,  // internal field, same as JVM_ACC_ABSTRACT
+  JVM_ACC_FIELD_STABLE               = 0x00000020,  // @Stable field, same as JVM_ACC_SYNCHRONIZED
   JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE = 0x00000800, // field has generic signature
 
   JVM_ACC_FIELD_INTERNAL_FLAGS       = JVM_ACC_FIELD_ACCESS_WATCHED |
                                        JVM_ACC_FIELD_MODIFICATION_WATCHED |
                                        JVM_ACC_FIELD_INTERNAL |
+                                       JVM_ACC_FIELD_STABLE |
                                        JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE,
 
                                                     // flags accepted by set_field_flags()
@@ -148,6 +150,7 @@
                                         { return (_flags & JVM_ACC_FIELD_MODIFICATION_WATCHED) != 0; }
   bool on_stack() const                 { return (_flags & JVM_ACC_ON_STACK) != 0; }
   bool is_internal() const              { return (_flags & JVM_ACC_FIELD_INTERNAL) != 0; }
+  bool is_stable() const                { return (_flags & JVM_ACC_FIELD_STABLE) != 0; }
   bool field_has_generic_signature() const
                                         { return (_flags & JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE) != 0; }
 
--- a/hotspot/test/gc/TestVerifyDuringStartup.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/test/gc/TestVerifyDuringStartup.java	Wed Jul 05 19:11:53 2017 +0200
@@ -48,7 +48,7 @@
                                              "-XX:+VerifyDuringStartup",
                                              "-version"});
 
-    System.out.print("Testing:\n" + JDKToolFinder.getJDKTool("java"));
+    System.out.print("Testing:\n" + JDKToolFinder.getCurrentJDKTool("java"));
     for (int i = 0; i < vmOpts.size(); i += 1) {
       System.out.print(" " + vmOpts.get(i));
     }
--- a/hotspot/test/testlibrary/com/oracle/java/testlibrary/JDKToolFinder.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/JDKToolFinder.java	Wed Jul 05 19:11:53 2017 +0200
@@ -27,24 +27,43 @@
 
 public final class JDKToolFinder {
 
-  private JDKToolFinder() {
-  }
-
-  /**
-   * Returns the full path to an executable in jdk/bin based on System property
-   * test.jdk (set by jtreg test suite)
-   *
-   * @return Full path to an executable in jdk/bin
-   */
-  public static String getJDKTool(String tool) {
-    String binPath = System.getProperty("test.jdk");
-    if (binPath == null) {
-      throw new RuntimeException("System property 'test.jdk' not set. This property is normally set by jtreg. "
-          + "When running test separately, set this property using '-Dtest.jdk=/path/to/jdk'.");
+    private JDKToolFinder() {
     }
 
-    binPath += File.separatorChar + "bin" + File.separatorChar + tool;
+    /**
+     * Returns the full path to an executable in jdk/bin based on System
+     * property {@code compile.jdk} (set by jtreg test suite)
+     *
+     * @return Full path to an executable in jdk/bin
+     */
+    public static String getJDKTool(String tool) {
+        String binPath = System.getProperty("compile.jdk");
+        if (binPath == null) {
+            throw new RuntimeException("System property 'compile.jdk' not set. "
+                    + "This property is normally set by jtreg. "
+                    + "When running test separately, set this property using "
+                    + "'-Dcompile.jdk=/path/to/jdk'.");
+        }
+        binPath += File.separatorChar + "bin" + File.separatorChar + tool;
 
-    return binPath;
-  }
+        return binPath;
+    }
+    /**
+     * Returns the full path to an executable in &lt;current jdk&gt;/bin based
+     * on System property {@code test.jdk} (set by jtreg test suite)
+     *
+     * @return Full path to an executable in jdk/bin
+     */
+    public static String getCurrentJDKTool(String tool) {
+        String binPath = System.getProperty("test.jdk");
+        if (binPath == null) {
+            throw new RuntimeException("System property 'test.jdk' not set. "
+                + "This property is normally set by jtreg. "
+                + "When running test separately, set this property using "
+                + "'-Dtest.jdk=/path/to/jdk'.");
+        }
+        binPath += File.separatorChar + "bin" + File.separatorChar + tool;
+
+        return binPath;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/Makefile	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,73 @@
+#
+# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.	See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+#
+
+ifneq "x$(ALT_BOOTDIR)" "x"
+	BOOTDIR := $(ALT_BOOTDIR)
+endif
+
+ifeq "x$(BOOTDIR)" "x"
+	JDK_HOME := $(shell dirname $(shell which java))/..
+else
+	JDK_HOME := $(BOOTDIR)
+endif
+
+SRC_DIR = src
+BUILD_DIR = build
+OUTPUT_DIR = $(BUILD_DIR)/classes
+WHITEBOX_DIR = ../whitebox
+
+JAVAC = $(JDK_HOME)/bin/javac
+JAR = $(JDK_HOME)/bin/jar
+
+SRC_FILES = $(shell find $(SRC_DIR) -name '*.java')
+
+MAIN_CLASS = sun.hotspot.tools.ctw.CompileTheWorld
+
+.PHONY: clean cleantmp
+
+all: ctw.jar cleantmp
+
+clean: cleantmp
+	@rm -rf ctw.jar wb.jar
+
+cleantmp:
+	@rm -rf filelist manifest.mf
+	@rm -rf $(BUILD_DIR)
+
+ctw.jar: filelist wb.jar manifest.mf
+	@mkdir -p $(OUTPUT_DIR)
+	$(JAVAC) -sourcepath $(SRC_DIR) -d $(OUTPUT_DIR) -cp wb.jar @filelist
+	$(JAR) cfm ctw.jar manifest.mf -C $(OUTPUT_DIR) .
+
+wb.jar: 
+	make -C ${WHITEBOX_DIR} wb.jar
+	cp ${WHITEBOX_DIR}/wb.jar ./
+	make -C ${WHITEBOX_DIR} clean
+
+filelist: $(SRC_FILES)
+	@rm -f $@
+	@echo $(SRC_FILES) > $@
+
+manifest.mf:
+	@echo "Main-Class: ${MAIN_CLASS}" > manifest.mf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/README	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,93 @@
+#
+# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+#
+
+DESCRIPTION
+
+This is replacement for CompileTheWorld (CTW) written on java. Its purpose is
+to make possible the use of CTW in product builds.
+
+DEPENDENCES
+
+The tool depends on Whitebox API. Assumed, that the sources of whitebox are
+located in '../whitebox' directory.
+
+BUILDING
+
+Simple way to build, just type 'make'.
+
+Makefile uses environment variables 'ALT_BOOTDIR', 'BOOTDIR' as root-dir of jdk
+that will be used for compilation and creating jar.
+
+On successful building 'ctw.jar' will be created.
+
+RUNNING
+
+Since the tool uses WhiteBox API, options 'UnlockDiagnosticVMOptions' and
+'WhiteBoxAPI' should be specified, and 'wb.jar' should be added to
+boot-classpath:
+  $ java -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:wb.jar -jar ctw.jar 
+
+Arguments can be paths to '.jar, '.zip', '.lst' files or directories with
+classes, that define which classes will be compiled:
+  - '.jar', '.zip' files and directories are interpreted like in classpath
+(including '<dir>/*' syntax)
+  - '.lst' files -- files with class names (in java notation) to compile.
+CTW will try to find these classes with default class loader, so they should
+be located in classpath.
+
+Without arguments it would work as old version of CTW: all classes in
+boot-classpath will be compiled, excluding classes in 'rt.jar' if 'rt.jar' isn't
+first in boot-classpath.
+
+Due CTW's flags also are not available in product builds, the tool uses
+properties with the same names:
+  - 'CompileTheWorldPreloadClasses' -- type:boolean, default:true, description:
+Preload all classes used by a class before start loading
+  - 'CompileTheWorldStartAt' -- type:long, default:1, description: First class
+to consider
+  - 'CompileTheWorldStopAt' -- type:long, default:Long.MAX_VALUE, description:
+Last class to consider
+
+Also it uses additional properties:
+  - 'sun.hotspot.tools.ctw.verbose' -- type:boolean, default:false,
+description: Verbose output, adds additional information about compilation
+  - 'sun.hotspot.tools.ctw.logfile' -- type:string, default:null,
+description: Path to logfile, if it's null, cout will be used.
+
+EXAMPLES
+
+compile classes from 'rt.jar':
+  $ java -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:wb.jar -jar ctw.jar ${JAVA_HOME}/jre/lib/rt.jar
+
+compile classes from all '.jar' in './testjars' directory:
+  $ java -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:wb.jar -jar ctw.jar ./testjars/*
+
+compile classes from './build/classes' directory:
+  $ java -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:wb.jar -jar ctw.jar ./build/classes
+
+compile only java.lang.String, java.lang.Object classes:
+  $ echo java.lang.String > classes.lst
+  $ echo java.lang.Object >> classes.lst
+  $ java -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:wb.jar -jar ctw.jar classes.lst
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathDirEntry.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.hotspot.tools.ctw;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Set;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.concurrent.Executor;
+
+import java.io.*;
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+
+/**
+ * * Handler for dirs containing classes to compile.
+ * @author igor.ignatyev@oracle.com
+ */
+public class ClassPathDirEntry extends PathHandler {
+
+    private final int rootLength = root.toString().length();
+
+    public ClassPathDirEntry(Path root, Executor executor) {
+        super(root, executor);
+        try {
+            URL url = root.toUri().toURL();
+            setLoader(new URLClassLoader(new URL[]{url}));
+        } catch (MalformedURLException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void process() {
+        System.out.println("# dir: " + root);
+        if (!Files.exists(root)) {
+            return;
+        }
+        try {
+            Files.walkFileTree(root, EnumSet.of(FileVisitOption.FOLLOW_LINKS),
+                    Integer.MAX_VALUE, new CompileFileVisitor());
+        } catch (IOException ioe) {
+            ioe.printStackTrace();
+        }
+    }
+
+    private void processFile(Path file) {
+        if (Utils.isClassFile(file.toString())) {
+            processClass(pathToClassName(file));
+        }
+    }
+
+    private String pathToClassName(Path file) {
+        String fileString;
+        if (root == file) {
+            fileString = file.normalize().toString();
+        } else {
+            fileString = file.normalize().toString().substring(rootLength + 1);
+        }
+        return Utils.fileNameToClassName(fileString);
+    }
+
+    private class CompileFileVisitor extends SimpleFileVisitor<Path> {
+
+        private final Set<Path> ready = new HashSet<>();
+
+        @Override
+        public FileVisitResult preVisitDirectory(Path dir,
+                BasicFileAttributes attrs) throws IOException {
+            if (ready.contains(dir)) {
+                return FileVisitResult.SKIP_SUBTREE;
+            }
+            ready.add(dir);
+            return super.preVisitDirectory(dir, attrs);
+        }
+
+        @Override
+        public FileVisitResult visitFile(Path file,
+                BasicFileAttributes attrs) throws IOException {
+            if (!ready.contains(file)) {
+                processFile(file);
+            }
+            return isFinished() ? FileVisitResult.TERMINATE
+                    : FileVisitResult.CONTINUE;
+        }
+
+        @Override
+        public FileVisitResult visitFileFailed(Path file,
+                IOException exc) throws IOException {
+            return FileVisitResult.CONTINUE;
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarEntry.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.hotspot.tools.ctw;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.*;
+import java.util.jar.*;
+import java.util.concurrent.Executor;
+
+import java.io.*;
+import java.nio.file.*;
+
+/**
+ * Handler for jar-files containing classes to compile.
+ * @author igor.ignatyev@oracle.com
+ */
+public class ClassPathJarEntry extends PathHandler {
+
+    public ClassPathJarEntry(Path root, Executor executor) {
+        super(root, executor);
+        try {
+            URL url = root.toUri().toURL();
+            setLoader(new URLClassLoader(new URL[]{url}));
+        } catch (MalformedURLException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public void process() {
+        System.out.println("# jar: " + root);
+        if (!Files.exists(root)) {
+            return;
+        }
+        try {
+            JarFile jarFile = new JarFile(root.toFile());
+            JarEntry entry;
+            for (Enumeration<JarEntry> e = jarFile.entries();
+                    e.hasMoreElements(); ) {
+                entry = e.nextElement();
+                processJarEntry(entry);
+                if (isFinished()) {
+                    return;
+                }
+            }
+        } catch (IOException ioe) {
+            ioe.printStackTrace();
+        }
+    }
+
+     private void processJarEntry(JarEntry entry) {
+        String filename = entry.getName();
+        if (Utils.isClassFile(filename)) {
+            processClass(Utils.fileNameToClassName(filename));
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassPathJarInDirEntry.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.hotspot.tools.ctw;
+
+import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.concurrent.Executor;
+
+/**
+ * Handler for dirs containing jar-files with classes to compile.
+ *
+ * @author igor.ignatyev@oracle.com
+ */
+public class ClassPathJarInDirEntry extends PathHandler {
+
+    public ClassPathJarInDirEntry(Path root, Executor executor) {
+        super(root, executor);
+    }
+
+    @Override
+    public void process() {
+        System.out.println("# jar_in_dir: " + root);
+        if (!Files.exists(root)) {
+            return;
+        }
+        try (DirectoryStream<Path> ds
+                = Files.newDirectoryStream(root, "*.jar")) {
+            for (Path p : ds) {
+                new ClassPathJarEntry(p, executor).process();
+                if (isFinished()) {
+                    return;
+                }
+            }
+        } catch (IOException ioe) {
+            ioe.printStackTrace();
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/ClassesListInFile.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.hotspot.tools.ctw;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.concurrent.Executor;
+
+/**
+ * Handler for files containing a list of classes to compile.
+ *
+ * @author igor.ignatyev@oracle.com
+ */
+public class ClassesListInFile extends PathHandler {
+    public ClassesListInFile(Path root, Executor executor) {
+        super(root, executor);
+    }
+
+    @Override
+    public void process() {
+        System.out.println("# list: " + root);
+        if (!Files.exists(root)) {
+            return;
+        }
+        try {
+            try (BufferedReader reader = Files.newBufferedReader(root,
+                    StandardCharsets.UTF_8)) {
+                String line;
+                while (!isFinished() && ((line = reader.readLine()) != null)) {
+                    processClass(line);
+                }
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/CompileTheWorld.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.hotspot.tools.ctw;
+
+import sun.management.ManagementFactoryHelper;
+
+import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import java.util.List;
+import java.util.concurrent.*;
+
+/**
+ * @author igor.ignatyev@oracle.com
+ */
+public class CompileTheWorld {
+    /**
+     * Entry point. Compiles classes in {@code args}, or all classes in
+     * boot-classpath if args is empty
+     *
+     * @param args paths to jar/zip, dir contains classes, or to .lst file
+     *             contains list of classes to compile
+     */
+    public static void main(String[] args) {
+        String logfile = Utils.LOG_FILE;
+        PrintStream os = null;
+        if (logfile != null) {
+            try {
+                os = new PrintStream(Files.newOutputStream(Paths.get(logfile)));
+            } catch (IOException io) {
+            }
+        }
+        if (os != null) {
+            System.setOut(os);
+        }
+
+        try {
+            try {
+                if (ManagementFactoryHelper.getCompilationMXBean() == null) {
+                    throw new RuntimeException(
+                            "CTW can not work in interpreted mode");
+                }
+            } catch (java.lang.NoClassDefFoundError e) {
+                // compact1, compact2 support
+            }
+            String[] paths = args;
+            boolean skipRtJar = false;
+            if (args.length == 0) {
+                paths = getDefaultPaths();
+                skipRtJar = true;
+            }
+            ExecutorService executor = createExecutor();
+            long start = System.currentTimeMillis();
+            try {
+                String path;
+                for (int i = 0, n = paths.length; i < n
+                        && !PathHandler.isFinished(); ++i) {
+                    path = paths[i];
+                    if (skipRtJar && i > 0 && isRtJar(path)) {
+                        // rt.jar is not first, so skip it
+                        continue;
+                    }
+                    PathHandler.create(path, executor).process();
+                }
+            } finally {
+                await(executor);
+            }
+            System.out.printf("Done (%d classes, %d methods, %d ms)%n",
+                    Compiler.getClassCount(),
+                    Compiler.getMethodCount(),
+                    System.currentTimeMillis() - start);
+        } finally {
+            if (os != null) {
+                os.close();
+            }
+        }
+    }
+
+    private static ExecutorService createExecutor() {
+        final int threadsCount = Math.min(
+                Runtime.getRuntime().availableProcessors(),
+                Utils.CI_COMPILER_COUNT);
+        ExecutorService result;
+        if (threadsCount > 1) {
+            result = new ThreadPoolExecutor(threadsCount, threadsCount,
+                    /* keepAliveTime */ 0L, TimeUnit.MILLISECONDS,
+                    new ArrayBlockingQueue<>(threadsCount),
+                    new ThreadPoolExecutor.CallerRunsPolicy());
+        } else {
+            result = new CurrentThreadExecutor();
+        }
+        return result;
+    }
+
+    private static String[] getDefaultPaths() {
+        String property = System.getProperty("sun.boot.class.path");
+        System.out.println(
+                "# use 'sun.boot.class.path' as args: " + property);
+        return Utils.PATH_SEPARATOR.split(property);
+    }
+
+    private static void await(ExecutorService executor) {
+        executor.shutdown();
+        while (!executor.isTerminated()) {
+            try {
+                executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
+            } catch (InterruptedException ie) {
+                Thread.currentThread().interrupt();
+                break;
+            }
+        }
+    }
+
+    private static boolean isRtJar(String path) {
+        return Utils.endsWithIgnoreCase(path, File.separator + "rt.jar");
+    }
+
+    private static class CurrentThreadExecutor extends AbstractExecutorService {
+        private boolean isShutdown;
+
+        @Override
+        public void shutdown() {
+            this.isShutdown = true;
+        }
+
+        @Override
+        public List<Runnable> shutdownNow() {
+            return null;
+        }
+
+        @Override
+        public boolean isShutdown() {
+            return isShutdown;
+        }
+
+        @Override
+        public boolean isTerminated() {
+            return isShutdown;
+        }
+
+        @Override
+        public boolean awaitTermination(long timeout, TimeUnit unit)
+                throws InterruptedException {
+            return isShutdown;
+        }
+
+        @Override
+        public void execute(Runnable command) {
+            command.run();
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Compiler.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.hotspot.tools.ctw;
+
+import sun.hotspot.WhiteBox;
+import sun.misc.SharedSecrets;
+import sun.reflect.ConstantPool;
+
+import java.lang.reflect.Executable;
+
+import java.util.Objects;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Provide method to compile whole class.
+ * Also contains compiled methods and classes counters.
+ *
+ * @author igor.ignatyev@oracle.com
+ */
+public class Compiler {
+    private Compiler() { }
+    private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
+    private static final AtomicLong CLASS_COUNT = new AtomicLong(0L);
+    private static final AtomicLong METHOD_COUNT = new AtomicLong(0L);
+    private static volatile boolean CLASSES_LIMIT_REACHED = false;
+
+    /**
+     * @return count of processed classes
+     */
+    public static long getClassCount() {
+        return CLASS_COUNT.get();
+    }
+
+    /**
+     * @return count of processed methods
+     */
+    public static long getMethodCount() {
+        return METHOD_COUNT.get();
+    }
+
+    /**
+     * @return {@code true} if classes limit is reached
+     */
+    public static boolean isLimitReached() {
+        return CLASSES_LIMIT_REACHED;
+    }
+
+    /**
+     * Compiles all methods and constructors.
+     *
+     * @param aClass class to compile
+     * @param executor executor used for compile task invocation
+     * @throws NullPointerException if {@code class} or {@code executor}
+     *                              is {@code null}
+     */
+    public static void compileClass(Class aClass, Executor executor) {
+        Objects.requireNonNull(aClass);
+        Objects.requireNonNull(executor);
+        long id = CLASS_COUNT.incrementAndGet();
+        if (id > Utils.COMPILE_THE_WORLD_STOP_AT) {
+            CLASS_COUNT.decrementAndGet();
+            CLASSES_LIMIT_REACHED = true;
+            return;
+        }
+
+        if (id >= Utils.COMPILE_THE_WORLD_START_AT) {
+            String name = aClass.getName();
+            try {
+                System.out.printf("[%d]\t%s%n", id, name);
+                ConstantPool constantPool = SharedSecrets.getJavaLangAccess().
+                        getConstantPool(aClass);
+                if (Utils.COMPILE_THE_WORLD_PRELOAD_CLASSES) {
+                    preloadClasses(name, id, constantPool);
+                }
+                long methodCount = 0;
+                for (Executable e : aClass.getDeclaredConstructors()) {
+                    ++methodCount;
+                    executor.execute(new CompileMethodCommand(id, name, e));
+                }
+                for (Executable e : aClass.getDeclaredMethods()) {
+                    ++methodCount;
+                    executor.execute(new CompileMethodCommand(id, name, e));
+                }
+                METHOD_COUNT.addAndGet(methodCount);
+
+                if (Utils.DEOPTIMIZE_ALL_CLASSES_RATE > 0
+                        && (id % Utils.DEOPTIMIZE_ALL_CLASSES_RATE == 0)) {
+                    WHITE_BOX.deoptimizeAll();
+                }
+            } catch (Throwable t) {
+                System.out.printf("[%d]\t%s\tskipping %s%n", id, name, t);
+                t.printStackTrace();
+            }
+        }
+    }
+
+    private static void preloadClasses(String className, long id,
+            ConstantPool constantPool) {
+        try {
+            for (int i = 0, n = constantPool.getSize(); i < n; ++i) {
+                try {
+                    constantPool.getClassAt(i);
+                } catch (IllegalArgumentException ignore) {
+                }
+            }
+        } catch (Throwable t) {
+            System.out.printf("[%d]\t%s\tpreloading failed : %s%n", id,
+                    className, t);
+        }
+    }
+
+
+
+    /**
+     * Compilation of method.
+     * Will compile method on all available comp levels.
+     */
+    private static class CompileMethodCommand implements Runnable {
+        private final long classId;
+        private final String className;
+        private final Executable method;
+
+        /**
+         * @param classId   id of class
+         * @param className name of class
+         * @param method    compiled for compilation
+         */
+        public CompileMethodCommand(long classId, String className,
+                Executable method) {
+            this.classId = classId;
+            this.className = className;
+            this.method = method;
+        }
+
+        @Override
+        public final void run() {
+            int compLevel = Utils.INITIAL_COMP_LEVEL;
+            if (Utils.TIERED_COMPILATION) {
+                for (int i = compLevel; i <= Utils.TIERED_STOP_AT_LEVEL; ++i) {
+                    WHITE_BOX.deoptimizeMethod(method);
+                    compileMethod(method, i);
+                }
+            } else {
+                compileMethod(method, compLevel);
+            }
+        }
+
+        private void waitCompilation() {
+            if (!Utils.BACKGROUND_COMPILATION) {
+                return;
+            }
+            final Object obj = new Object();
+            synchronized (obj) {
+                for (int i = 0;
+                     i < 10 && WHITE_BOX.isMethodQueuedForCompilation(method);
+                     ++i) {
+                    try {
+                        obj.wait(1000);
+                    } catch (InterruptedException e) {
+                        Thread.currentThread().interrupt();
+                    }
+                }
+            }
+        }
+
+        private void compileMethod(Executable method, int compLevel) {
+            if (WHITE_BOX.isMethodCompilable(method, compLevel)) {
+                try {
+                    WHITE_BOX.enqueueMethodForCompilation(method, compLevel);
+                    waitCompilation();
+                    int tmp = WHITE_BOX.getMethodCompilationLevel(method);
+                    if (tmp != compLevel) {
+                        logMethod(method, "compilation level = " + tmp
+                                + ", but not " + compLevel);
+                    } else if (Utils.IS_VERBOSE) {
+                        logMethod(method, "compilation level = " + tmp + ". OK");
+                    }
+                } catch (Throwable t) {
+                    logMethod(method, "error on compile at " + compLevel
+                            + " level");
+                    t.printStackTrace();
+                }
+            } else if (Utils.IS_VERBOSE) {
+                logMethod(method, "not compilable at " + compLevel);
+            }
+        }
+
+        private void logMethod(Executable method, String message) {
+            StringBuilder builder = new StringBuilder("[");
+            builder.append(classId);
+            builder.append("]\t");
+            builder.append(className);
+            builder.append("::");
+            builder.append(method.getName());
+            builder.append('(');
+            Class[] params = method.getParameterTypes();
+            for (int i = 0, n = params.length - 1; i < n; ++i) {
+                builder.append(params[i].getName());
+                builder.append(", ");
+            }
+            if (params.length != 0) {
+                builder.append(params[params.length - 1].getName());
+            }
+            builder.append(')');
+            if (message != null) {
+                builder.append('\t');
+                builder.append(message);
+            }
+            System.err.println(builder);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/PathHandler.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.hotspot.tools.ctw;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.io.File;
+
+import java.util.Objects;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.concurrent.Executor;
+
+/**
+ * Abstract handler for path.
+ * <p/>
+ * Concrete subclasses should implement method {@link #process()}.
+ *
+ * @author igor.ignatyev@oracle.com
+ */
+public abstract class PathHandler {
+    private static final Pattern JAR_IN_DIR_PATTERN
+            = Pattern.compile("^(.*[/\\\\])?\\*$");
+    protected final Path root;
+    protected final Executor executor;
+    private ClassLoader loader;
+
+    /**
+     * @param root     root path to process
+     * @param executor executor used for process task invocation
+     * @throws NullPointerException if {@code root} or {@code executor} is
+     *                              {@code null}
+     */
+    protected PathHandler(Path root, Executor executor) {
+        Objects.requireNonNull(root);
+        Objects.requireNonNull(executor);
+        this.root = root.normalize();
+        this.executor = executor;
+        this.loader = ClassLoader.getSystemClassLoader();
+    }
+
+   /**
+     * Factory method. Construct concrete handler in depends from {@code path}.
+     *
+     * @param path     the path to process
+     * @param executor executor used for compile task invocation
+     * @throws NullPointerException if {@code path} or {@code executor} is
+     *                              {@code null}
+     */
+    public static PathHandler create(String path, Executor executor) {
+        Objects.requireNonNull(path);
+        Objects.requireNonNull(executor);
+        Matcher matcher = JAR_IN_DIR_PATTERN.matcher(path);
+        if (matcher.matches()) {
+            path = matcher.group(1);
+            path = path.isEmpty() ? "." : path;
+            return new ClassPathJarInDirEntry(Paths.get(path), executor);
+        } else {
+            path = path.isEmpty() ? "." : path;
+            Path p = Paths.get(path);
+            if (isJarFile(p)) {
+                return new ClassPathJarEntry(p, executor);
+            } else if (isListFile(p)) {
+                return new ClassesListInFile(p, executor);
+            } else {
+                return new ClassPathDirEntry(p, executor);
+            }
+        }
+    }
+
+    private static boolean isJarFile(Path path) {
+        if (Files.isRegularFile(path)) {
+            String name = path.toString();
+            return Utils.endsWithIgnoreCase(name, ".zip")
+                    || Utils.endsWithIgnoreCase(name, ".jar");
+        }
+        return false;
+    }
+
+    private static boolean isListFile(Path path) {
+        if (Files.isRegularFile(path)) {
+            String name = path.toString();
+            return Utils.endsWithIgnoreCase(name, ".lst");
+        }
+        return false;
+    }
+
+    /**
+     * Processes all classes in specified path.
+     */
+    public abstract void process();
+
+   /**
+     * Sets class loader, that will be used to define class at
+     * {@link #processClass(String)}.
+     *
+     * @param loader class loader
+     * @throws NullPointerException if {@code loader} is {@code null}
+     */
+    protected final void setLoader(ClassLoader loader) {
+        Objects.requireNonNull(loader);
+        this.loader = loader;
+    }
+
+    /**
+     * Processes specificed class.
+     * @param name fully qualified name of class to process
+     */
+    protected final void processClass(String name) {
+        try {
+            Class aClass = Class.forName(name, true, loader);
+            Compiler.compileClass(aClass, executor);
+        } catch (ClassNotFoundException | LinkageError e) {
+            System.out.printf("Class %s loading failed : %s%n", name,
+                e.getMessage());
+        }
+    }
+
+    /**
+     * @return {@code true} if processing should be stopped
+     */
+    public static boolean isFinished() {
+        return Compiler.isLimitReached();
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/src/sun/hotspot/tools/ctw/Utils.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.hotspot.tools.ctw;
+
+import com.sun.management.HotSpotDiagnosticMXBean;
+import sun.management.ManagementFactoryHelper;
+
+import java.io.File;
+import java.util.regex.Pattern;
+
+/**
+ * Auxiliary methods.
+ *
+ * @author igor.ignatyev@oracle.com
+ */
+public class Utils {
+    /**
+     * Value of {@code -XX:CompileThreshold}
+     */
+    public static final boolean TIERED_COMPILATION
+            = Boolean.parseBoolean(getVMOption("TieredCompilation", "false"));
+    /**
+     * Value of {@code -XX:BackgroundCompilation}
+     */
+    public static final boolean BACKGROUND_COMPILATION
+            = Boolean.parseBoolean(getVMOption("BackgroundCompilation",
+            "false"));
+    /**
+     * Value of {@code -XX:TieredStopAtLevel}
+     */
+    public static final int TIERED_STOP_AT_LEVEL;
+    /**
+     * Value of {@code -XX:CICompilerCount}
+     */
+    public static final Integer CI_COMPILER_COUNT
+            = Integer.valueOf(getVMOption("CICompilerCount", "1"));
+    /**
+     * Initial compilation level.
+     */
+    public static final int INITIAL_COMP_LEVEL;
+    /**
+     * Compiled path-separator regexp.
+     */
+    public static final Pattern PATH_SEPARATOR = Pattern.compile(
+            File.pathSeparator, Pattern.LITERAL);
+    /**
+     * Value of {@code -DDeoptimizeAllClassesRate}. Frequency of
+     * {@code WB.deoptimizeAll()} invocation If it less that {@code 0},
+     * {@code WB.deoptimizeAll()} will not be invoked.
+     */
+    public static final int DEOPTIMIZE_ALL_CLASSES_RATE
+            = Integer.getInteger("DeoptimizeAllClassesRate", -1);
+    /**
+     * Value of {@code -DCompileTheWorldStopAt}. Last class to consider.
+     */
+    public static final long COMPILE_THE_WORLD_STOP_AT
+            = Long.getLong("CompileTheWorldStopAt", Long.MAX_VALUE);
+    /**
+     * Value of {@code -DCompileTheWorldStartAt}. First class to consider.
+     */
+    public static final long COMPILE_THE_WORLD_START_AT
+            = Long.getLong("CompileTheWorldStartAt", 1);
+    /**
+     * Value of {@code -DCompileTheWorldPreloadClasses}. Preload all classes
+     * used by a class before start loading.
+     */
+    public static final boolean COMPILE_THE_WORLD_PRELOAD_CLASSES;
+    /**
+     * Value of {@code -Dsun.hotspot.tools.ctw.verbose}. Verbose output,
+     * adds additional information about compilation.
+     */
+    public static final boolean IS_VERBOSE
+            = Boolean.getBoolean("sun.hotspot.tools.ctw.verbose");
+    /**
+     * Value of {@code -Dsun.hotspot.tools.ctw.logfile}.Path to logfile, if
+     * it's null, cout will be used.
+     */
+    public static final String LOG_FILE
+            = System.getProperty("sun.hotspot.tools.ctw.logfile");
+    static {
+        if (Utils.TIERED_COMPILATION) {
+            INITIAL_COMP_LEVEL = 1;
+        } else {
+            String vmName = System.getProperty("java.vm.name");
+            if (Utils.endsWithIgnoreCase(vmName, " Server VM")) {
+                INITIAL_COMP_LEVEL = 4;
+            } else if (Utils.endsWithIgnoreCase(vmName, " Client VM")
+                    || Utils.endsWithIgnoreCase(vmName, " Minimal VM")) {
+                INITIAL_COMP_LEVEL = 1;
+            } else {
+                throw new RuntimeException("Unknown VM: " + vmName);
+            }
+        }
+
+        TIERED_STOP_AT_LEVEL = Integer.parseInt(getVMOption("TieredStopAtLevel",
+                String.valueOf(INITIAL_COMP_LEVEL)));
+    }
+
+    static {
+        String tmp = System.getProperty("CompileTheWorldPreloadClasses");
+        if (tmp == null) {
+            COMPILE_THE_WORLD_PRELOAD_CLASSES = true;
+        } else {
+            COMPILE_THE_WORLD_PRELOAD_CLASSES = Boolean.parseBoolean(tmp);
+        }
+    }
+
+    public static final String CLASSFILE_EXT = ".class";
+
+    private Utils() {
+    }
+
+    /**
+     * Tests if the string ends with the suffix, ignoring case
+     * considerations
+     *
+     * @param string the tested string
+     * @param suffix the suffix
+     * @return {@code true} if {@code string} ends with the {@code suffix}
+     * @see String#endsWith(String)
+     */
+    public static boolean endsWithIgnoreCase(String string, String suffix) {
+        if (string == null || suffix == null) {
+            return false;
+        }
+        int length = suffix.length();
+        int toffset = string.length() - length;
+        if (toffset < 0) {
+            return false;
+        }
+        return string.regionMatches(true, toffset, suffix, 0, length);
+    }
+
+    /**
+     * Returns value of VM option.
+     *
+     * @param name option's name
+     * @return value of option or {@code null}, if option doesn't exist
+     * @throws NullPointerException if name is null
+     */
+    public static String getVMOption(String name) {
+        String result;
+        HotSpotDiagnosticMXBean diagnostic
+                = ManagementFactoryHelper.getDiagnosticMXBean();
+        result = diagnostic.getVMOption(name).getValue();
+        return result;
+    }
+
+    /**
+     * Returns value of VM option or default value.
+     *
+     * @param name         option's name
+     * @param defaultValue default value
+     * @return value of option or {@code defaultValue}, if option doesn't exist
+     * @throws NullPointerException if name is null
+     * @see #getVMOption(String)
+     */
+    public static String getVMOption(String name, String defaultValue) {
+        String result;
+        try {
+            result = getVMOption(name);
+        } catch (NoClassDefFoundError e) {
+            // compact1, compact2 support
+            result = defaultValue;
+        }
+        return result == null ? defaultValue : result;
+    }
+
+    /**
+     * Tests if the filename is valid filename for class file.
+     *
+     * @param filename tested filename
+     */
+    public static boolean isClassFile(String filename) {
+        // If the filename has a period after removing '.class', it's not valid class file
+        return endsWithIgnoreCase(filename, CLASSFILE_EXT)
+                && (filename.indexOf('.')
+                == (filename.length() - CLASSFILE_EXT.length()));
+    }
+
+    /**
+     * Converts the filename to classname.
+     *
+     * @param filename filename to convert
+     * @return corresponding classname.
+     * @throws AssertionError if filename isn't valid filename for class file -
+     *                        {@link #isClassFile(String)}
+     */
+    public static String fileNameToClassName(String filename) {
+        assert isClassFile(filename);
+        return filename.substring(0, filename.length() - CLASSFILE_EXT.length())
+                       .replace(File.separatorChar, '.');
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/test/Bar.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,5 @@
+public class Bar {
+  private static void staticMethod() { }
+  public void method() { }
+  protected Bar() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/test/ClassesDirTest.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test ClassesDirTest
+ * @bug 8012447
+ * @library /testlibrary /testlibrary/whitebox /testlibrary/ctw/src
+ * @build sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox ClassesDirTest Foo Bar
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
+ * @run main ClassesDirTest prepare
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld classes
+ * @run main ClassesDirTest check ctw.log
+ * @summary testing of CompileTheWorld :: classes in directory
+ * @author igor.ignatyev@oracle.com
+ */
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+
+public class ClassesDirTest extends CtwTest {
+    private static final String[] SHOULD_CONTAIN
+            = {"# dir: classes", "Done (2 classes, 6 methods, "};
+
+    private ClassesDirTest() {
+        super(SHOULD_CONTAIN);
+    }
+
+    public static void main(String[] args) throws Exception {
+        new ClassesDirTest().run(args);
+    }
+
+    protected void prepare() throws Exception {
+        String path = "classes";
+        Files.createDirectory(Paths.get(path));
+        Files.move(Paths.get("Foo.class"), Paths.get(path, "Foo.class"),
+                StandardCopyOption.REPLACE_EXISTING);
+        Files.move(Paths.get("Bar.class"), Paths.get(path, "Bar.class"),
+                StandardCopyOption.REPLACE_EXISTING);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/test/ClassesListTest.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test ClassesListTest
+ * @bug 8012447
+ * @library /testlibrary /testlibrary/whitebox /testlibrary/ctw/src
+ * @build sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox ClassesListTest Foo Bar
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
+ * @run main ClassesListTest prepare
+ * @run main/othervm/timeout=600 -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld classes.lst
+ * @run main ClassesListTest check ctw.log
+ * @summary testing of CompileTheWorld :: list of classes in file
+ * @author igor.ignatyev@oracle.com
+ */
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+
+public class ClassesListTest extends CtwTest {
+    private static final String[] SHOULD_CONTAIN
+            = {"# list: classes.lst", "Done (4 classes, "};
+
+    private ClassesListTest() {
+        super(SHOULD_CONTAIN);
+    }
+
+    public static void main(String[] args) throws Exception {
+        new ClassesListTest().run(args);
+    }
+
+    protected void prepare() throws Exception {
+        String path = "classes.lst";
+        Files.copy(Paths.get(System.getProperty("test.src"), path),
+                Paths.get(path), StandardCopyOption.REPLACE_EXISTING);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/test/CtwTest.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.List;
+import java.util.Collections;
+import java.util.ArrayList;
+
+import java.io.File;
+import java.io.Writer;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.BufferedReader;
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.nio.charset.Charset;
+
+import com.oracle.java.testlibrary.JDKToolFinder;
+import com.oracle.java.testlibrary.OutputAnalyzer;
+
+public abstract class CtwTest {
+    protected final String[] shouldContain;
+    protected CtwTest(String[] shouldContain) {
+        this.shouldContain = shouldContain;
+    }
+
+    public void run(String[] args) throws Exception {
+        if (args.length == 0) {
+            throw new Error("args is empty");
+        }
+        switch (args[0]) {
+            case "prepare":
+                prepare();
+                break;
+            case "check":
+                check(args);
+                break;
+            default:
+                throw new Error("unregonized action -- " + args[0]);
+        }
+    }
+
+    protected void prepare() throws Exception { }
+
+    protected void check(String[] args) throws Exception  {
+        if (args.length < 2) {
+            throw new Error("logfile isn't specified");
+        }
+        String logfile = args[1];
+        try (BufferedReader r = Files.newBufferedReader(Paths.get(logfile),
+                Charset.defaultCharset())) {
+            OutputAnalyzer output = readOutput(r);
+           for (String test : shouldContain) {
+                output.shouldContain(test);
+            }
+        }
+    }
+
+    private static OutputAnalyzer readOutput(BufferedReader reader)
+            throws IOException {
+        StringBuilder builder = new StringBuilder();
+        String eol = String.format("%n");
+        String line;
+
+        while ((line = reader.readLine()) != null) {
+            builder.append(line);
+            builder.append(eol);
+        }
+        return new OutputAnalyzer(builder.toString(), "");
+    }
+
+    protected void dump(OutputAnalyzer output, String name) {
+        try (Writer w = new FileWriter(name + ".out")) {
+            String s = output.getStdout();
+            w.write(s, s.length(), 0);
+        } catch (IOException io) {
+            io.printStackTrace();
+        }
+        try (Writer w = new FileWriter(name + ".err")) {
+            String s = output.getStderr();
+            w.write(s, s.length(), 0);
+        } catch (IOException io) {
+            io.printStackTrace();
+        }
+    }
+
+    protected ProcessBuilder createJarProcessBuilder(String... command)
+            throws Exception {
+        String javapath = JDKToolFinder.getJDKTool("jar");
+
+        ArrayList<String> args = new ArrayList<>();
+        args.add(javapath);
+        Collections.addAll(args, command);
+
+        return new ProcessBuilder(args.toArray(new String[args.size()]));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/test/Foo.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,5 @@
+public class Foo {
+  private static void staticMethod() { }
+  public void method() { }
+  protected Foo() { }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/test/JarDirTest.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test JarDirTest
+ * @bug 8012447
+ * @library /testlibrary /testlibrary/whitebox /testlibrary/ctw/src
+ * @build sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox JarDirTest Foo Bar
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
+ * @run main JarDirTest prepare
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld jars/*
+ * @run main JarDirTest check ctw.log
+ * @summary testing of CompileTheWorld :: jars in directory
+ * @author igor.ignatyev@oracle.com
+ */
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+
+public class JarDirTest extends CtwTest {
+    private static final String[] SHOULD_CONTAIN
+            = {"# jar_in_dir: jars",
+                    "# jar: jars" + File.separator +"foo.jar",
+                    "# jar: jars" + File.separator +"bar.jar",
+                    "Done (4 classes, 12 methods, "};
+
+    private JarDirTest() {
+        super(SHOULD_CONTAIN);
+    }
+
+    public static void main(String[] args) throws Exception {
+        new JarDirTest().run(args);
+    }
+
+    protected void prepare() throws Exception {
+        String path = "jars";
+        Files.createDirectory(Paths.get(path));
+
+        ProcessBuilder pb = createJarProcessBuilder("cf", "jars/foo.jar",
+                "Foo.class", "Bar.class");
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+        dump(output, "ctw-foo.jar");
+        output.shouldHaveExitValue(0);
+
+        pb = createJarProcessBuilder("cf", "jars/bar.jar", "Foo.class",
+                "Bar.class");
+        output = new OutputAnalyzer(pb.start());
+        dump(output, "ctw-bar.jar");
+        output.shouldHaveExitValue(0);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/test/JarsTest.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test JarsTest
+ * @bug 8012447
+ * @library /testlibrary /testlibrary/whitebox /testlibrary/ctw/src
+ * @build sun.hotspot.tools.ctw.CompileTheWorld sun.hotspot.WhiteBox JarsTest Foo Bar
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox Foo Bar
+ * @run main JarsTest prepare
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Dsun.hotspot.tools.ctw.logfile=ctw.log sun.hotspot.tools.ctw.CompileTheWorld foo.jar bar.jar
+ * @run main JarsTest check ctw.log
+ * @summary testing of CompileTheWorld :: jars
+ * @author igor.ignatyev@oracle.com
+ */
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+
+public class JarsTest extends CtwTest {
+    private static final String[] SHOULD_CONTAIN
+            = {"# jar: foo.jar", "# jar: bar.jar",
+                    "Done (4 classes, 12 methods, "};
+
+    private JarsTest() {
+        super(SHOULD_CONTAIN);
+    }
+
+    public static void main(String[] args) throws Exception {
+        new JarsTest().run(args);
+    }
+
+    protected void prepare() throws Exception {
+        ProcessBuilder pb = createJarProcessBuilder("cf", "foo.jar",
+                "Foo.class", "Bar.class");
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+        dump(output, "ctw-foo.jar");
+        output.shouldHaveExitValue(0);
+
+        pb = createJarProcessBuilder("cf", "bar.jar", "Foo.class", "Bar.class");
+        output = new OutputAnalyzer(pb.start());
+        dump(output, "ctw-bar.jar");
+        output.shouldHaveExitValue(0);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/ctw/test/classes.lst	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,4 @@
+java.lang.String
+java.lang.Object
+Foo
+Bar
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/whitebox/Makefile	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,63 @@
+#
+# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.	See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+#
+
+ifneq "x$(ALT_BOOTDIR)" "x"
+	BOOTDIR := $(ALT_BOOTDIR)
+endif
+
+ifeq "x$(BOOTDIR)" "x"
+	JDK_HOME := $(shell dirname $(shell which java))/..
+else
+	JDK_HOME := $(BOOTDIR)
+endif
+
+SRC_DIR = ./
+BUILD_DIR = build
+OUTPUT_DIR = $(BUILD_DIR)/classes
+
+JAVAC = $(JDK_HOME)/bin/javac
+JAR = $(JDK_HOME)/bin/jar
+
+SRC_FILES = $(shell find $(SRC_DIR) -name '*.java')
+
+.PHONY: filelist clean cleantmp
+
+all: wb.jar cleantmp
+
+wb.jar: filelist
+	@mkdir -p $(OUTPUT_DIR)
+	$(JAVAC) -sourcepath $(SRC_DIR) -d $(OUTPUT_DIR) -cp $(OUTPUT_DIR) @filelist
+	$(JAR) cf wb.jar -C $(OUTPUT_DIR) .
+	@rm -rf $(OUTPUT_DIR)
+
+filelist: $(SRC_FILES)
+	@rm -f $@
+	@echo $(SRC_FILES) > $@
+
+clean: cleantmp
+	@rm -rf wb.jar
+
+cleantmp:
+	@rm -rf filelist
+	@rm -rf $(BUILD_DIR)
--- a/jdk/.hgtags	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/.hgtags	Wed Jul 05 19:11:53 2017 +0200
@@ -228,3 +228,4 @@
 f1d8d15bfcb5ada858a942f8a31f6598f23214d1 jdk8-b104
 1fe211ae3d2b8cc2dfc4f58d9a6eb96418679672 jdk8-b105
 c817276bd870dfe1dcc3a3dbbc092436b6907f75 jdk8-b106
+eea685b9ccaa1980e0a7e07d6a3a84bcc7e9ab82 jdk8-b107
--- a/jdk/make/Makefile	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/make/Makefile	Wed Jul 05 19:11:53 2017 +0200
@@ -99,7 +99,6 @@
 CACERTS_FILE.desc          = Location of certificates file
 DEVTOOLS_PATH.desc         = Directory containing zip and unzip
 CUPS_HEADERS_PATH.desc     = Include directory location for CUPS header files
-DXSDK_PATH.desc            = Root directory of DirectX SDK
 
 # Make variables to print out (description and value)
 VARIABLE_PRINTVAL_LIST +=       \
@@ -128,17 +127,6 @@
 VARIABLE_CHECKFIL_LIST +=       \
     CACERTS_FILE
 
-# Some are windows specific
-ifeq ($(PLATFORM), windows)
-
-VARIABLE_PRINTVAL_LIST +=       \
-    DXSDK_PATH
-
-VARIABLE_CHECKDIR_LIST +=       \
-    DXSDK_PATH
-
-endif
-
 # For pattern rules below, so all are treated the same
 DO_PRINTVAL_LIST=$(VARIABLE_PRINTVAL_LIST:%=%.printval)
 DO_CHECKDIR_LIST=$(VARIABLE_CHECKDIR_LIST:%=%.checkdir)
--- a/jdk/make/common/Defs-macosx.gmk	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/make/common/Defs-macosx.gmk	Wed Jul 05 19:11:53 2017 +0200
@@ -397,12 +397,10 @@
   INCLUDE_SA = true
 endif
 
-ifdef CROSS_COMPILE_ARCH
-  # X11 headers are not under /usr/include
-  OTHER_CFLAGS += -I$(OPENWIN_HOME)/include
-  OTHER_CXXFLAGS += -I$(OPENWIN_HOME)/include
-  OTHER_CPPFLAGS += -I$(OPENWIN_HOME)/include
-endif
+# X11 headers are not under /usr/include
+OTHER_CFLAGS += -I$(OPENWIN_HOME)/include
+OTHER_CXXFLAGS += -I$(OPENWIN_HOME)/include
+OTHER_CPPFLAGS += -I$(OPENWIN_HOME)/include
 
 LIB_LOCATION ?= $(LIBDIR)
 
--- a/jdk/make/common/Defs-windows.gmk	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/make/common/Defs-windows.gmk	Wed Jul 05 19:11:53 2017 +0200
@@ -78,8 +78,6 @@
   MS_RUNTIME_LIBRARIES = $(MSVCRNN_DLL)
 endif
 
-EXTRA_LFLAGS += -LIBPATH:$(DXSDK_LIB_PATH)
-
 # Full Debug Symbols has been enabled on Windows since JDK1.4.1.
 # The Full Debug Symbols (FDS) default for VARIANT == OPT builds is
 # enabled with debug info files ZIP'ed to save space. For VARIANT !=
--- a/jdk/make/common/Sanity.gmk	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/make/common/Sanity.gmk	Wed Jul 05 19:11:53 2017 +0200
@@ -65,7 +65,6 @@
     sane-libCrun \
     sane-unixccs_path \
     sane-msdevtools_path \
-    sane-dxsdk \
     sane-compiler \
     sane-cacerts \
     sane-ant_version \
--- a/jdk/make/common/shared/Defs-versions.gmk	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/make/common/shared/Defs-versions.gmk	Wed Jul 05 19:11:53 2017 +0200
@@ -74,9 +74,6 @@
 # REQUIRED_CYGWIN_VER
 #   Windows only: If CYGWIN is used, the minimum CYGWIN version.
 #
-# REQUIRED_DXSDK_VER
-#   Windows only: The version of DirectX SDK expected.
-#
 # REQUIRED_FREETYPE_VERSION
 #   If we are using freetype, the freetype version expected.
 #
@@ -193,7 +190,6 @@
   REQUIRED_OS_VARIANT_VERSION = $(REQUIRED_OS_VERSION)
   REQUIRED_CYGWIN_VER         = 4.0
   REQUIRED_MKS_VER            = 6.1
-  REQUIRED_DXSDK_VER          = 0x0900
   ifeq ($(CC_VERSION),msvc)
     REQUIRED_COMPILER_NAME    = Visual Studio 10
     REQUIRED_COMPILER_VERSION = VS2010
--- a/jdk/make/common/shared/Defs-windows.gmk	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/make/common/shared/Defs-windows.gmk	Wed Jul 05 19:11:53 2017 +0200
@@ -79,7 +79,7 @@
 #   The ALT values should never really have spaces or use \.
 #   Suspect these environment variables to have spaces and/or \ characters:
 #     SYSTEMROOT, SystemRoot, WINDIR, windir, PROGRAMFILES, ProgramFiles,
-#     DXSDK_DIR, MSTOOLS, Mstools, MSSDK, MSSdk, VCnnCOMNTOOLS, 
+#     MSTOOLS, Mstools, MSSDK, MSSdk, VCnnCOMNTOOLS, 
 #     MSVCDIR, MSVCDir.
 #     So use $(subst \,/,) on them first adding quotes and placing them in
 #         their own variable assigned with :=, then use FullPath.
@@ -255,18 +255,6 @@
   _program_files:=
 endif
 
-# DirectX SDK
-ifdef ALT_DXSDK_DRIVE
-  _dx_sdk_dir  =$(ALT_DXSDK_DRIVE):/DXSDK
-else
-  ifdef DXSDK_DIR
-    xDXSDK_DIR  :="$(subst \,/,$(DXSDK_DIR))"
-  else
-    xDXSDK_DIR  :="$(_system_drive)/DXSDK"
-  endif
-  _dx_sdk_dir :=$(call FullPath,$(xDXSDK_DIR))
-endif
-
 # Use of the Visual Studio compilers requires certain env variables be set:
 #   PATH should include the path to cl.exe
 #   INCLUDE should be defined
@@ -489,39 +477,6 @@
   MSVCRNN_DLL_PATH:=$(call AltCheckValue,MSVCRNN_DLL_PATH)
 endif
 
-# DXSDK_PATH: path to Microsoft DirectX SDK Include and Lib
-ifdef ALT_DXSDK_PATH
-  xALT_DXSDK_PATH :="$(subst \,/,$(ALT_DXSDK_PATH))"
-  DXSDK_PATH      :=$(call FullPath,$(xALT_DXSDK_PATH))
-else
-  _DXSDK_PATH1 :=$(_dx_sdk_dir)
-  _DXSDK_PATH2 :=$(JDK_DEVTOOLS_DIR)/windows/dxsdk
-  DXSDK_PATH  :=$(call DirExists,$(_DXSDK_PATH1),$(_DXSDK_PATH2),$(_dx_sdk_dir))
-endif
-DXSDK_PATH :=$(call AltCheckSpaces,DXSDK_PATH)
-DXSDK_PATH:=$(call AltCheckValue,DXSDK_PATH)
-
-# DXSDK_INCLUDE_PATH: path to Microsoft DirectX SDK Include
-ifdef ALT_DXSDK_INCLUDE_PATH
-  xALT_DXSDK_INCLUDE_PATH :="$(subst \,/,$(ALT_DXSDK_INCLUDE_PATH))"
-  DXSDK_INCLUDE_PATH      :=$(call FullPath,$(xALT_DXSDK_INCLUDE_PATH))
-else
-  DXSDK_INCLUDE_PATH =$(subst //,/,$(DXSDK_PATH)/Include)
-endif
-
-# DXSDK_LIB_PATH: path to Microsoft DirectX SDK Lib
-ifdef ALT_DXSDK_LIB_PATH
-  xALT_DXSDK_LIB_PATH :="$(subst \,/,$(ALT_DXSDK_LIB_PATH))"
-  DXSDK_LIB_PATH      :=$(call FullPath,$(xALT_DXSDK_LIB_PATH))
-else
-  ifeq ($(ARCH_DATA_MODEL), 64)
-    # 64bit libs are located in "Lib/x64" subdir
-    DXSDK_LIB_PATH =$(subst //,/,$(DXSDK_PATH)/Lib/x64)
-  else
-    DXSDK_LIB_PATH =$(subst //,/,$(DXSDK_PATH)/Lib)
-  endif
-endif
-
 # DEPLOY_MSSDK: Microsoft SDK for this platform (for deploy)
 ifdef ALT_DEPLOY_MSSDK
   xALT_DEPLOY_MSSDK :="$(subst \,/,$(ALT_DEPLOY_MSSDK))"
--- a/jdk/make/common/shared/Sanity-Settings.gmk	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/make/common/shared/Sanity-Settings.gmk	Wed Jul 05 19:11:53 2017 +0200
@@ -234,10 +234,6 @@
 ALL_SETTINGS+=$(call addAltSetting,HOTSPOT_SERVER_PATH)
 ifeq ($(PLATFORM),windows)
   ALL_SETTINGS+=$(call addAltSetting,HOTSPOT_LIB_PATH)
-  ALL_SETTINGS+=$(call addRequiredSetting,DXSDK_VER)
-  ALL_SETTINGS+=$(call addAltSetting,DXSDK_PATH)
-  ALL_SETTINGS+=$(call addAltSetting,DXSDK_INCLUDE_PATH)
-  ALL_SETTINGS+=$(call addAltSetting,DXSDK_LIB_PATH)
   ALL_SETTINGS+=$(call addAltSetting,WINDOWSSDKDIR)
   ALL_SETTINGS+=$(call addRequiredSetting,RC)
   ALL_SETTINGS+=$(call addRequiredSetting,REBASE)
--- a/jdk/make/common/shared/Sanity.gmk	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/make/common/shared/Sanity.gmk	Wed Jul 05 19:11:53 2017 +0200
@@ -143,8 +143,6 @@
     _CYGWIN_VER := $(SYSTEM_UNAME)
     CYGWIN_VER  :=$(call GetVersion,$(_CYGWIN_VER))
   endif
-  DXSDK_VER := $(shell $(EGREP) DIRECT3D_VERSION $(DXSDK_INCLUDE_PATH)/d3d9.h 2>&1 | \
-    $(EGREP) "\#define" | $(NAWK) '{print $$3}')
 endif
 
 # Get the version numbers of what we are using
@@ -1301,51 +1299,6 @@
 	fi
 
 ######################################################
-# Check for windows DirectX sdk directory
-######################################################
-sane-dxsdk:
-ifeq ($(PLATFORM), windows)
-	@if [ ! -r $(DXSDK_INCLUDE_PATH)/d3d9.h  ]; then \
-	$(ECHO) "ERROR: You do not have access to a valid DirectX SDK Include dir.\n" \
-	  "      The value of DXSDK_INCLUDE_PATH must point a valid DX SDK dir.\n" \
-	  "      Please check your access to \n" \
-	  "          $(DXSDK_INCLUDE_PATH) \n" \
-	  "      and/or check your value of ALT_DXSDK_PATH or ALT_DXSDK_INCLUDE_PATH.\n" \
-	  "      Microsoft DirectX 9 SDK (Summer 2004 Update or newer) can be downloaded from the following location:\n" \
-	  "          http://msdn.microsoft.com/library/default.asp?url=/downloads/list/directx.asp\n" \
-	  "      Or  http://www.microsoft.com/directx\n" \
-	  "" >> $(ERROR_FILE) ; \
-	else \
-	  if [ ! "$(DXSDK_VER)" = "$(REQUIRED_DXSDK_VER)" ]; then \
-	  $(ECHO) "ERROR: The DirectX SDK must be version $(REQUIRED_DXSDK_VER).\n" \
-	    "      $(YOU_ARE_USING) DirectX SDK version: $(DXSDK_VER)\n" \
-	    "      The DirectX SDK was obtained from the following location: \n" \
-	    "          $(DXSDK_PATH) \n" \
-	    "      Please change your DirectX SDK. \n" \
-	    "      Microsoft DirectX 9 SDK (Summer 2004 Update or newer) can be downloaded from the following location:\n" \
-	    "          http://msdn.microsoft.com/library/default.asp?url=/downloads/list/directx.asp\n" \
-	    "      Or  http://www.microsoft.com/directx\n" \
-	    "" >> $(ERROR_FILE) ; \
-	  else \
-	    if [ -r $(DXSDK_INCLUDE_PATH)/basetsd.h ]; then \
-              if [ `$(EGREP) -c __int3264 $(DXSDK_INCLUDE_PATH)/basetsd.h` -ne 0 ]; then \
-	      $(ECHO) "WARNING: The DirectX SDK Include directory contains a newer basetsd.h,\n" \
-		"      which may indicate that you're using an incorrect version of DirectX SDK.\n" \
-		"      This may result in a build failure.\n" \
-		"      The DirectX SDK Include dir was obtained from the following location:\n" \
-		" 	  $(DXSDK_INCLUDE_PATH) \n" \
-		"      Please change your DirectX SDK to version 9 (Summer 2004 Update or newer).\n" \
-	        "      Microsoft DirectX 9 SDK can be downloaded from the following location:\n" \
-	        "          http://msdn.microsoft.com/library/default.asp?url=/downloads/list/directx.asp\n" \
-		"      Or  http://www.microsoft.com/directx\n" \
-		"" >> $(WARNING_FILE) ; \
-	      fi \
-	    fi \
-	  fi \
-	fi
-endif
-
-######################################################
 # Check the linker version(s)
 ######################################################
 ifeq ($(PLATFORM), windows)
--- a/jdk/make/java/java/Makefile	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/make/java/java/Makefile	Wed Jul 05 19:11:53 2017 +0200
@@ -105,6 +105,7 @@
 		java/util/prefs/MacOSXPreferencesFactory.java
 
 CFLAGS_$(VARIANT)/java_props_md.o = -Os -x objective-c
+CFLAGS_$(VARIANT)/java_props_macosx.o = -Os -x objective-c
 endif
 
 #
--- a/jdk/make/java/java/genlocales.gmk	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/make/java/java/genlocales.gmk	Wed Jul 05 19:11:53 2017 +0200
@@ -38,31 +38,31 @@
 # only FILES_java and FILES_compiled_properties variables will be picked up
 #
 # $(BUILDDIR)/java/util/FILES_java.gmk & $(BUILDDIR)/java/util/FILES_properties.gmk
-# contain "sun.util.resources" for US language support
+# contain "sun.util.resources" for EN language support
 
 include $(BUILDDIR)/java/util/FILES_java.gmk
 include $(BUILDDIR)/java/util/FILES_properties.gmk
 
-US_Resources_java := $(FILES_java)
-US_Resources_properties := $(FILES_compiled_properties)
+EN_Resources_java := $(FILES_java)
+EN_Resources_properties := $(FILES_compiled_properties)
 
 # $(BUILDDIR)/java/text/FILES_java.gmk contains the "sun.text.resources" for 
-# US language support
+# EN language support
 
 include $(BUILDDIR)/java/text/base/FILES_java.gmk
 
-US_Resources_java += $(FILES_java)
+EN_Resources_java += $(FILES_java)
 
 FILES_compiled_properties=
 
 # $(BUILDDIR)/sun/text/FILES_java.gmk & $(BUILDDIR)/sun/text/FILES_properties.gmk
-# contain both resources for Non-US language support
+# contain both resources for Non-EN language support
 
 include $(BUILDDIR)/sun/text/FILES_java.gmk
 include $(BUILDDIR)/sun/text/FILES_properties.gmk
 
-NonUS_Resources_java := $(FILES_java)
-NonUS_Resources_properties := $(FILES_compiled_properties)
+NonEN_Resources_java := $(FILES_java)
+NonEN_Resources_properties := $(FILES_compiled_properties)
 
 # Restore the orignal FILES_java & FILES_compiled_properties variables
 FILES_java := $(FILES_java_orig)
@@ -80,30 +80,30 @@
 ifeq ($(PLATFORM), macosx)
 
 $(LocaleDataMetaInfo_Dest):$(LocaleDataMetaInfo_Src) $(LOCALEGEN_SH)
-	@$(RM) $@.tmp.us $@.tmp.nonus;
+	@$(RM) $@.tmp.en $@.tmp.nonen;
 	@$(prep-target) 
-	@$(ECHO) $(US_Resources_properties) | $(NAWK) 'gsub(/.properties/,"\n") {print}'  > $@.tmp.us;
-	@$(ECHO) $(US_Resources_java) | $(NAWK) 'gsub(/.java/,"\n") {print}' >> $@.tmp.us;
-	@$(ECHO) $(NonUS_Resources_properties) | $(NAWK) 'gsub(/.properties/,"\n") {print}' > $@.tmp.nonus;
-	@$(ECHO) $(NonUS_Resources_java) | $(NAWK) 'gsub(/.java/,"\n") {print}' >> $@.tmp.nonus;
+	@$(ECHO) $(EN_Resources_properties) | $(NAWK) 'gsub(/.properties/,"\n") {print}'  > $@.tmp.en;
+	@$(ECHO) $(EN_Resources_java) | $(NAWK) 'gsub(/.java/,"\n") {print}' >> $@.tmp.en;
+	@$(ECHO) $(NonEN_Resources_properties) | $(NAWK) 'gsub(/.properties/,"\n") {print}' > $@.tmp.nonen;
+	@$(ECHO) $(NonEN_Resources_java) | $(NAWK) 'gsub(/.java/,"\n") {print}' >> $@.tmp.nonen;
 	NAWK="$(NAWK)" SED="$(SED)" SORT="$(SORT)" \
-	     $(SH) $(LOCALEGEN_SH) $(RESOURCE_NAMES) $@.tmp.us \
-		$@.tmp.nonus $< $@
-	@$(RM) $@.tmp.us $@.tmp.nonus;
+	     $(SH) $(LOCALEGEN_SH) $(RESOURCE_NAMES) $@.tmp.en \
+		$@.tmp.nonen $< $@
+	@$(RM) $@.tmp.en $@.tmp.nonen;
 
 else
 
 $(LocaleDataMetaInfo_Dest):$(LocaleDataMetaInfo_Src) $(LOCALEGEN_SH)
-	@$(RM) $@.tmp.us $@.tmp.nonus;
+	@$(RM) $@.tmp.en $@.tmp.nonen;
 	@$(prep-target) 
-	@$(ECHO) $(subst .properties,'\n',$(US_Resources_properties)) > $@.tmp.us;
-	@$(ECHO) $(subst .java,'\n',$(US_Resources_java)) >> $@.tmp.us;	
-	@$(ECHO) $(subst .properties,'\n',$(NonUS_Resources_properties)) > $@.tmp.nonus;
-	@$(ECHO) $(subst .java,'\n',$(NonUS_Resources_java)) >> $@.tmp.nonus;
+	@$(ECHO) $(subst .properties,'\n',$(EN_Resources_properties)) > $@.tmp.en;
+	@$(ECHO) $(subst .java,'\n',$(EN_Resources_java)) >> $@.tmp.en;	
+	@$(ECHO) $(subst .properties,'\n',$(NonEN_Resources_properties)) > $@.tmp.nonen;
+	@$(ECHO) $(subst .java,'\n',$(NonEN_Resources_java)) >> $@.tmp.nonen;
 	NAWK="$(NAWK)" SED="$(SED)" SORT="$(SORT)" \
-	     $(SH) $(LOCALEGEN_SH) $(RESOURCE_NAMES) $@.tmp.us \
-		$@.tmp.nonus $< $@
-	@$(RM) $@.tmp.us $@.tmp.nonus;
+	     $(SH) $(LOCALEGEN_SH) $(RESOURCE_NAMES) $@.tmp.en \
+		$@.tmp.nonen $< $@
+	@$(RM) $@.tmp.en $@.tmp.nonen;
 endif
 	
 genlocales : $(LocaleDataMetaInfo_Dest)  
--- a/jdk/make/java/java/localegen.sh	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/make/java/java/localegen.sh	Wed Jul 05 19:11:53 2017 +0200
@@ -35,11 +35,11 @@
 # A list of resource base name list;
 RESOURCE_NAMES=$1
 
-# A list of US resources;
-US_FILES_LIST=$2
+# A list of EN resources;
+EN_FILES_LIST=$2
 
-# A list of non-US resources;
-NONUS_FILES_LIST=$3
+# A list of non-EN resources;
+NONEN_FILES_LIST=$3
 
 INPUT_FILE=$4
 OUTPUT_FILE=$5
@@ -53,23 +53,23 @@
 sed_script="$SED -e \"s@^#warn .*@// -- This file was mechanically generated: Do not edit! -- //@\" "
 
 # ja-JP-JP and th-TH-TH need to be manually added, as they don't have any resource files.
-nonusall=" ja-JP-JP th-TH-TH "
+nonenall=" ja-JP-JP th-TH-TH "
 
 for FILE in $RESOURCE_NAMES
 do
-    getlocalelist $FILE $US_FILES_LIST
-    sed_script=$sed_script"-e \"s@#"$FILE"_USLocales#@$localelist@g\" "
-    usall=$usall" "$localelist
-    getlocalelist $FILE $NONUS_FILES_LIST
-    sed_script=$sed_script"-e \"s@#"$FILE"_NonUSLocales#@$localelist@g\" "
-    nonusall=$nonusall" "$localelist
+    getlocalelist $FILE $EN_FILES_LIST
+    sed_script=$sed_script"-e \"s@#"$FILE"_ENLocales#@$localelist@g\" "
+    enall=$enall" "$localelist
+    getlocalelist $FILE $NONEN_FILES_LIST
+    sed_script=$sed_script"-e \"s@#"$FILE"_NonENLocales#@$localelist@g\" "
+    nonenall=$nonenall" "$localelist
 done
 
-usall=`(for LOC in $usall; do echo $LOC;done) |$SORT -u`
-nonusall=`(for LOC in $nonusall; do echo $LOC;done) |$SORT -u`
+enall=`(for LOC in $enall; do echo $LOC;done) |$SORT -u`
+nonenall=`(for LOC in $nonenall; do echo $LOC;done) |$SORT -u`
 
-sed_script=$sed_script"-e \"s@#AvailableLocales_USLocales#@$usall@g\" "
-sed_script=$sed_script"-e \"s@#AvailableLocales_NonUSLocales#@$nonusall@g\" "
+sed_script=$sed_script"-e \"s@#AvailableLocales_ENLocales#@$enall@g\" "
+sed_script=$sed_script"-e \"s@#AvailableLocales_NonENLocales#@$nonenall@g\" "
 
 sed_script=$sed_script"$INPUT_FILE > $OUTPUT_FILE"
 eval $sed_script
--- a/jdk/make/java/text/base/FILES_java.gmk	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/make/java/text/base/FILES_java.gmk	Wed Jul 05 19:11:53 2017 +0200
@@ -107,5 +107,17 @@
         sun/text/resources/FormatData.java \
         sun/text/resources/JavaTimeSupplementary.java \
         sun/text/resources/en/FormatData_en.java \
+        sun/text/resources/en/FormatData_en_AU.java \
+        sun/text/resources/en/FormatData_en_CA.java \
+        sun/text/resources/en/FormatData_en_GB.java \
+        sun/text/resources/en/FormatData_en_IE.java \
+        sun/text/resources/en/FormatData_en_IN.java \
+        sun/text/resources/en/FormatData_en_MT.java \
+        sun/text/resources/en/FormatData_en_NZ.java \
+        sun/text/resources/en/FormatData_en_PH.java \
+        sun/text/resources/en/FormatData_en_SG.java \
         sun/text/resources/en/FormatData_en_US.java \
+        sun/text/resources/en/FormatData_en_ZA.java \
         sun/text/resources/en/JavaTimeSupplementary_en.java \
+        sun/text/resources/en/JavaTimeSupplementary_en_GB.java \
+        sun/text/resources/en/JavaTimeSupplementary_en_SG.java
--- a/jdk/make/java/util/FILES_java.gmk	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/make/java/util/FILES_java.gmk	Wed Jul 05 19:11:53 2017 +0200
@@ -30,4 +30,7 @@
         sun/util/resources/LocaleNamesBundle.java \
         sun/util/resources/TimeZoneNamesBundle.java \
         sun/util/resources/TimeZoneNames.java \
-        sun/util/resources/en/TimeZoneNames_en.java
+        sun/util/resources/en/TimeZoneNames_en.java \
+        sun/util/resources/en/TimeZoneNames_en_CA.java \
+        sun/util/resources/en/TimeZoneNames_en_GB.java \
+        sun/util/resources/en/TimeZoneNames_en_IE.java
--- a/jdk/make/java/util/FILES_properties.gmk	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/make/java/util/FILES_properties.gmk	Wed Jul 05 19:11:53 2017 +0200
@@ -26,9 +26,25 @@
 FILES_compiled_properties = \
         sun/util/resources/LocaleNames.properties \
         sun/util/resources/en/LocaleNames_en.properties \
+        sun/util/resources/en/LocaleNames_en_MT.properties \
+        sun/util/resources/en/LocaleNames_en_PH.properties \
+        sun/util/resources/en/LocaleNames_en_SG.properties \
 	\
         sun/util/resources/CalendarData.properties \
         sun/util/resources/en/CalendarData_en.properties \
+        sun/util/resources/en/CalendarData_en_GB.properties \
+        sun/util/resources/en/CalendarData_en_IE.properties \
+        sun/util/resources/en/CalendarData_en_MT.properties \
 	\
         sun/util/resources/CurrencyNames.properties \
-        sun/util/resources/en/CurrencyNames_en_US.properties
+        sun/util/resources/en/CurrencyNames_en_AU.properties \
+        sun/util/resources/en/CurrencyNames_en_CA.properties \
+        sun/util/resources/en/CurrencyNames_en_GB.properties \
+        sun/util/resources/en/CurrencyNames_en_IE.properties \
+        sun/util/resources/en/CurrencyNames_en_IN.properties \
+        sun/util/resources/en/CurrencyNames_en_MT.properties \
+        sun/util/resources/en/CurrencyNames_en_NZ.properties \
+        sun/util/resources/en/CurrencyNames_en_PH.properties \
+        sun/util/resources/en/CurrencyNames_en_SG.properties \
+        sun/util/resources/en/CurrencyNames_en_US.properties \
+        sun/util/resources/en/CurrencyNames_en_ZA.properties
--- a/jdk/make/javax/sound/jsoundds/Makefile	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/make/javax/sound/jsoundds/Makefile	Wed Jul 05 19:11:53 2017 +0200
@@ -55,8 +55,7 @@
 LDLIBS += dsound.lib winmm.lib user32.lib ole32.lib
 CPPFLAGS += \
 	-DUSE_DAUDIO=TRUE \
-	-I$(SHARE_SRC)/native/com/sun/media/sound \
-	-I$(DXSDK_INCLUDE_PATH)
+	-I$(SHARE_SRC)/native/com/sun/media/sound
 
 #
 # Add to the ambient VPATH.
--- a/jdk/make/jdk_generic_profile.sh	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/make/jdk_generic_profile.sh	Wed Jul 05 19:11:53 2017 +0200
@@ -80,7 +80,6 @@
 #    ALT_BOOTDIR
 #    Windows Only:
 #      ALT_UNIXCOMMAND_PATH
-#      ALT_DXSDK_PATH
 #      ALT_MSVCRNN_DLL_PATH
 #
 #############################################################################
--- a/jdk/make/netbeans/awt2d/README	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/make/netbeans/awt2d/README	Wed Jul 05 19:11:53 2017 +0200
@@ -39,7 +39,6 @@
       (on Windows):
         #>env | grep ALT
         ALT_JDK_IMPORT_PATH=c:/devtools/java/jdk1.7.0
-        ALT_DXSDK_PATH=c:/devtools/DirectX/DXSDK_Dec06
         ALT_BOOTDIR=c:/DevTools/java/jdk1.6.0
 
       If your build is a FASTDEBUG build, don't forget
@@ -50,7 +49,6 @@
       accordingly:
         make.options=\
             ALT_JDK_IMPORT_PATH=c:/devtools/java/jdk1.7.0 \
-            ALT_DXSDK_PATH=c:/devtools/DirectX/DXSDK_Dec06 \
             ALT_BOOTDIR=c:/DevTools/java/jdk1.6.0 \
             FASTDEBUG=true
         make=c:/devtools/cygwin/bin/make
@@ -175,7 +173,6 @@
   ../../build/windows-i586/tmp/sun/sun.awt/splashscreen/CClassHeaders;
   ../../build/windows-i586/tmp/sun/sun.font/fontmanager/CClassHeaders;
   ../../build/windows-i586/tmp/sun/sun.font/t2k/CClassHeaders;
-  C:/DevTools/DirectX/DXSDK_Dec06/Include;
   C:/devtools/VS2003/SDK/v1.1/include;
   C:/devtools/VS2003/VC7/ATLMFC/INCLUDE;
   C:/devtools/VS2003/VC7/INCLUDE;
@@ -188,7 +185,7 @@
   Note that most paths are relative to the native project directory - 
   this helps if you decide to relocate the workspace later. The ones that 
   aren't relative are paths to external include directories, like those 
-  of the Platform SDK, DirectX SDK.
+  of the Platform SDK.
   On Unix platforms these may be directories like /usr/include.
 
   The parser must know some defines to correctly parse the source files,
--- a/jdk/make/sun/awt/Makefile	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/make/sun/awt/Makefile	Wed Jul 05 19:11:53 2017 +0200
@@ -564,7 +564,6 @@
 	-I$(OBJDIR) \
 	-I$(SHARE_SRC)/native/common \
 	-I$(WINAWT_native) \
-	-I$(DXSDK_INCLUDE_PATH) \
 	-I$(SHARE_SRC)/native/sun/awt/image/cvutils \
 	-I$(SHARE_SRC)/native/sun/awt/image \
 	-I$(SHARE_SRC)/native/sun/java2d/loops \
--- a/jdk/make/sun/cmm/lcms/mapfile-vers	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/make/sun/cmm/lcms/mapfile-vers	Wed Jul 05 19:11:53 2017 +0200
@@ -28,9 +28,8 @@
 SUNWprivate_1.1 {
 	global:
         Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative;
-        Java_sun_java2d_cmm_lcms_LCMS_freeProfileNative;
-        Java_sun_java2d_cmm_lcms_LCMS_getProfileSize;
-        Java_sun_java2d_cmm_lcms_LCMS_getProfileData;
+        Java_sun_java2d_cmm_lcms_LCMS_getProfileSizeNative;
+        Java_sun_java2d_cmm_lcms_LCMS_getProfileDataNative;
         Java_sun_java2d_cmm_lcms_LCMS_getTagNative;
         Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative;
         Java_sun_java2d_cmm_lcms_LCMS_colorConvert;
--- a/jdk/make/sun/jawt/Makefile	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/make/sun/jawt/Makefile	Wed Jul 05 19:11:53 2017 +0200
@@ -69,7 +69,6 @@
 # Other extra flags needed for compiling.
 #
 CPPFLAGS += -I$(SHARE_SRC)/native/common \
-	-I$(DXSDK_INCLUDE_PATH) \
 	-I$(PLATFORM_SRC)/native/sun/windows \
 	-I$(CLASSHDRDIR)/../../awt/CClassHeaders \
         -I$(SHARE_SRC)/native/sun/awt/debug \
--- a/jdk/make/sun/text/FILES_java.gmk	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/make/sun/text/FILES_java.gmk	Wed Jul 05 19:11:53 2017 +0200
@@ -96,16 +96,6 @@
                 sun/text/resources/el/FormatData_el.java \
                 sun/text/resources/el/FormatData_el_CY.java \
                 sun/text/resources/el/FormatData_el_GR.java \
-                sun/text/resources/en/FormatData_en_AU.java \
-                sun/text/resources/en/FormatData_en_CA.java \
-                sun/text/resources/en/FormatData_en_GB.java \
-                sun/text/resources/en/FormatData_en_IE.java \
-                sun/text/resources/en/FormatData_en_IN.java \
-                sun/text/resources/en/FormatData_en_MT.java \
-                sun/text/resources/en/FormatData_en_NZ.java \
-                sun/text/resources/en/FormatData_en_PH.java \
-                sun/text/resources/en/FormatData_en_SG.java \
-                sun/text/resources/en/FormatData_en_ZA.java \
                 sun/text/resources/es/FormatData_es.java \
                 sun/text/resources/es/FormatData_es_BO.java \
                 sun/text/resources/es/FormatData_es_AR.java \
@@ -214,9 +204,6 @@
                 sun/util/resources/zh/CurrencyNames_zh_SG.java \
                 sun/util/resources/zh/LocaleNames_zh_HK.java \
                 sun/util/resources/de/TimeZoneNames_de.java \
-                sun/util/resources/en/TimeZoneNames_en_CA.java \
-                sun/util/resources/en/TimeZoneNames_en_GB.java \
-                sun/util/resources/en/TimeZoneNames_en_IE.java \
                 sun/util/resources/es/TimeZoneNames_es.java \
                 sun/util/resources/fr/TimeZoneNames_fr.java \
                 sun/util/resources/hi/TimeZoneNames_hi.java \
@@ -237,8 +224,6 @@
                 sun/text/resources/da/JavaTimeSupplementary_da.java \
                 sun/text/resources/de/JavaTimeSupplementary_de.java \
                 sun/text/resources/el/JavaTimeSupplementary_el.java \
-                sun/text/resources/en/JavaTimeSupplementary_en_GB.java \
-                sun/text/resources/en/JavaTimeSupplementary_en_SG.java \
                 sun/text/resources/es/JavaTimeSupplementary_es.java \
                 sun/text/resources/et/JavaTimeSupplementary_et.java \
                 sun/text/resources/fi/JavaTimeSupplementary_fi.java \
--- a/jdk/make/sun/text/FILES_properties.gmk	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/make/sun/text/FILES_properties.gmk	Wed Jul 05 19:11:53 2017 +0200
@@ -33,9 +33,6 @@
         sun/util/resources/de/LocaleNames_de.properties \
         sun/util/resources/el/LocaleNames_el.properties \
         sun/util/resources/el/LocaleNames_el_CY.properties \
-        sun/util/resources/en/LocaleNames_en_MT.properties \
-        sun/util/resources/en/LocaleNames_en_PH.properties \
-        sun/util/resources/en/LocaleNames_en_SG.properties \
         sun/util/resources/es/LocaleNames_es.properties \
         sun/util/resources/es/LocaleNames_es_US.properties \
         sun/util/resources/et/LocaleNames_et.properties \
@@ -88,9 +85,6 @@
         sun/util/resources/de/CalendarData_de.properties \
         sun/util/resources/el/CalendarData_el.properties \
         sun/util/resources/el/CalendarData_el_CY.properties \
-        sun/util/resources/en/CalendarData_en_GB.properties \
-        sun/util/resources/en/CalendarData_en_IE.properties \
-        sun/util/resources/en/CalendarData_en_MT.properties \
         sun/util/resources/es/CalendarData_es.properties \
         sun/util/resources/es/CalendarData_es_ES.properties \
         sun/util/resources/es/CalendarData_es_US.properties \
@@ -164,16 +158,6 @@
         sun/util/resources/de/CurrencyNames_de_LU.properties \
         sun/util/resources/el/CurrencyNames_el_CY.properties \
         sun/util/resources/el/CurrencyNames_el_GR.properties \
-        sun/util/resources/en/CurrencyNames_en_AU.properties \
-        sun/util/resources/en/CurrencyNames_en_CA.properties \
-        sun/util/resources/en/CurrencyNames_en_GB.properties \
-        sun/util/resources/en/CurrencyNames_en_IE.properties \
-        sun/util/resources/en/CurrencyNames_en_IN.properties \
-        sun/util/resources/en/CurrencyNames_en_MT.properties \
-        sun/util/resources/en/CurrencyNames_en_NZ.properties \
-        sun/util/resources/en/CurrencyNames_en_PH.properties \
-        sun/util/resources/en/CurrencyNames_en_SG.properties \
-        sun/util/resources/en/CurrencyNames_en_ZA.properties \
         sun/util/resources/es/CurrencyNames_es.properties \
         sun/util/resources/es/CurrencyNames_es_AR.properties \
         sun/util/resources/es/CurrencyNames_es_BO.properties \
--- a/jdk/make/tools/src/build/tools/generatecharacter/CharacterName.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/make/tools/src/build/tools/generatecharacter/CharacterName.java	Wed Jul 05 19:11:53 2017 +0200
@@ -11,7 +11,7 @@
         FileReader reader = null;
         try {
             if (args.length != 2) {
-                System.err.println("Usage: java CharacterName UniocdeData.txt uniName.dat");
+                System.err.println("Usage: java CharacterName UnicodeData.txt uniName.dat");
                 System.exit(1);
             }
 
--- a/jdk/makefiles/CompileNativeLibraries.gmk	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/makefiles/CompileNativeLibraries.gmk	Wed Jul 05 19:11:53 2017 +0200
@@ -211,6 +211,7 @@
 	LIBJAVA_EXCLUDE_FILES += java_props_macosx.c
 else
 	BUILD_LIBJAVA_java_props_md.c_CFLAGS:=-x objective-c
+        BUILD_LIBJAVA_java_props_macosx.c_CFLAGS:=-x objective-c
 endif
 
 ifeq ($(OPENJDK_TARGET_OS),windows)
@@ -252,6 +253,7 @@
 		LDFLAGS_SUFFIX_linux:=$(LIBDL) $(BUILD_LIBFDLIBM),\
 		LDFLAGS_SUFFIX_macosx:=-L$(JDK_OUTPUTDIR)/objs/ -lfdlibm \
                                          -framework CoreFoundation \
+                                         -framework Foundation \
                                          -framework Security -framework SystemConfiguration, \
 		LDFLAGS_SUFFIX_windows:=-export:winFileHandleOpen -export:handleLseek \
 					jvm.lib $(BUILD_LIBFDLIBM) $(WIN_VERIFY_LIB) \
@@ -472,7 +474,6 @@
 	$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/sun/windows \
 	$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/sun/java2d/windows \
 	$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/sun/java2d/d3d
-    LIBAWT_CFLAGS+=-I$(DXSDK_INCLUDE_PATH)
 else
     LIBAWT_DIRS+=\
 	$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/sun/java2d/x11
@@ -1482,8 +1483,7 @@
 		        -I$(JDK_TOPDIR)/src/share/native/sun/awt/debug \
 		        -I$(JDK_TOPDIR)/src/share/native/sun/java2d \
 			-I$(JDK_TOPDIR)/src/share/native/sun/awt/image/cvutils \
-			-I$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/sun/java2d/windows \
-			-I$(DXSDK_INCLUDE_PATH), \
+			-I$(JDK_TOPDIR)/src/$(OPENJDK_TARGET_OS_API_DIR)/native/sun/java2d/windows, \
 		LDFLAGS:=$(LDFLAGS_JDKLIB) $(KERNEL32_LIB) $(LDFLAGS_CXX_JDK) \
 			 advapi32.lib $(WIN_AWT_LIB),\
 		LDFLAGS_SUFFIX:=$(LDFLAGS_JDKLIB_SUFFIX),\
@@ -2961,8 +2961,7 @@
 		OPTIMIZATION:=LOW, \
 		CFLAGS:=$(CFLAGS_JDKLIB) \
 			$(LIBJSOUND_CFLAGS) \
-			-DUSE_DAUDIO=TRUE \
-                        -I$(DXSDK_INCLUDE_PATH), \
+			-DUSE_DAUDIO=TRUE, \
 		LDFLAGS:=$(LDFLAGS_JDKLIB) $(LDFLAGS_CXX_JDK) \
 			 $(call SET_SHARED_LIBRARY_ORIGIN),\
 		LDFLAGS_SUFFIX:=$(LDFLAGS_JDKLIB_SUFFIX) dsound.lib winmm.lib user32.lib ole32.lib,\
--- a/jdk/makefiles/CreateJars.gmk	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/makefiles/CreateJars.gmk	Wed Jul 05 19:11:53 2017 +0200
@@ -80,39 +80,6 @@
 LOCALEDATA_INCLUDES := $(addprefix sun/text/resources/,$(LOCALEDATA_INCLUDE_LOCALES)) \
 		       $(addprefix sun/util/resources/,$(LOCALEDATA_INCLUDE_LOCALES))
 
-# For non-US English locale data
-
-LOCALEDATA_INCLUDES += \
-                sun/text/resources/en/FormatData_en_AU.class \
-                sun/text/resources/en/FormatData_en_CA.class \
-                sun/text/resources/en/FormatData_en_GB.class \
-                sun/text/resources/en/FormatData_en_IE.class \
-                sun/text/resources/en/FormatData_en_IN.class \
-                sun/text/resources/en/FormatData_en_MT.class \
-                sun/text/resources/en/FormatData_en_NZ.class \
-                sun/text/resources/en/FormatData_en_PH.class \
-                sun/text/resources/en/FormatData_en_SG.class \
-                sun/text/resources/en/FormatData_en_ZA.class \
-                sun/util/resources/en/CalendarData_en_GB.class \
-                sun/util/resources/en/CalendarData_en_IE.class \
-                sun/util/resources/en/CalendarData_en_MT.class \
-                sun/util/resources/en/CurrencyNames_en_AU.class \
-                sun/util/resources/en/CurrencyNames_en_CA.class \
-                sun/util/resources/en/CurrencyNames_en_GB.class \
-                sun/util/resources/en/CurrencyNames_en_IE.class \
-                sun/util/resources/en/CurrencyNames_en_IN.class \
-                sun/util/resources/en/CurrencyNames_en_MT.class \
-                sun/util/resources/en/CurrencyNames_en_NZ.class \
-                sun/util/resources/en/CurrencyNames_en_PH.class \
-                sun/util/resources/en/CurrencyNames_en_SG.class \
-                sun/util/resources/en/CurrencyNames_en_ZA.class \
-                sun/util/resources/en/LocaleNames_en_MT.class \
-                sun/util/resources/en/LocaleNames_en_PH.class \
-                sun/util/resources/en/LocaleNames_en_SG.class \
-                sun/util/resources/en/TimeZoneNames_en_CA.class \
-                sun/util/resources/en/TimeZoneNames_en_GB.class \
-                sun/util/resources/en/TimeZoneNames_en_IE.class
-
 $(eval $(call SetupArchive,BUILD_LOCALEDATA_JAR,,\
 		SRCS:=$(JDK_OUTPUTDIR)/classes,\
 		SUFFIXES:=.class _dict _th,\
--- a/jdk/makefiles/GensrcLocaleDataMetaInfo.gmk	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/makefiles/GensrcLocaleDataMetaInfo.gmk	Wed Jul 05 19:11:53 2017 +0200
@@ -50,27 +50,27 @@
     $(shell $(RM) $(JDK_OUTPUTDIR)/gensrc/sun/util/locale/provider/LocaleDataMetaInfo.java)
 endif
 
-# The US locales
-US_LOCALES:=en en-US
+# The EN locales
+EN_LOCALES:=en%
 
 # ja-JP-JP and th-TH-TH need to be manually added, as they don't have any resource files.
-ALL_NON_US_LOCALES:=ja-JP-JP th-TH-TH
+ALL_NON_EN_LOCALES:=ja-JP-JP th-TH-TH
 
 SED_ARGS:=-e 's|$(HASH)warn This file is preprocessed before being compiled|// -- This file was mechanically generated: Do not edit! -- //|g'
 
 # This macro creates a sed expression that substitues for example:
-# #FormatData_USLocales# with: en and/or en_US.
+# #FormatData_ENLocales# with: en% locales.
 define CaptureLocale
     $1_LOCALES := $$(subst _,-,$$(filter-out $1,$$(subst $1_,,$$(filter $1_%,$(LOCALE_RESOURCES)))))
-    $1_US_LOCALES := $$(filter $(US_LOCALES),$$($1_LOCALES))
-    $1_NON_US_LOCALES := $$(filter-out $(US_LOCALES),$$($1_LOCALES))
+    $1_EN_LOCALES := $$(filter $(EN_LOCALES),$$($1_LOCALES))
+    $1_NON_EN_LOCALES := $$(filter-out $(EN_LOCALES),$$($1_LOCALES))
 
-    ALL_US_LOCALES += $$($1_US_LOCALES)
-    ALL_NON_US_LOCALES += $$($1_NON_US_LOCALES)
+    ALL_EN_LOCALES += $$($1_EN_LOCALES)
+    ALL_NON_EN_LOCALES += $$($1_NON_EN_LOCALES)
 
     # Don't sed in a space if there are no locales.
-    SED_ARGS+= -e 's/$$(HASH)$1_USLocales$$(HASH)/$$(if $$($1_US_LOCALES),$$(SPACE)$$($1_US_LOCALES),)/g'
-    SED_ARGS+= -e 's/$$(HASH)$1_NonUSLocales$$(HASH)/$$(if $$($1_NON_US_LOCALES),$$(SPACE)$$($1_NON_US_LOCALES),)/g'
+    SED_ARGS+= -e 's/$$(HASH)$1_ENLocales$$(HASH)/$$(if $$($1_EN_LOCALES),$$(SPACE)$$($1_EN_LOCALES),)/g'
+    SED_ARGS+= -e 's/$$(HASH)$1_NonENLocales$$(HASH)/$$(if $$($1_NON_EN_LOCALES),$$(SPACE)$$($1_NON_EN_LOCALES),)/g'
 endef
 
 #sun.text.resources.FormatData
@@ -91,8 +91,8 @@
 #sun.util.resources.CalendarData
 $(eval $(call CaptureLocale,CalendarData))
 
-SED_ARGS+= -e 's/$(HASH)AvailableLocales_USLocales$(HASH)/$(sort $(ALL_US_LOCALES))/g'
-SED_ARGS+= -e 's/$(HASH)AvailableLocales_NonUSLocales$(HASH)/$(sort $(ALL_NON_US_LOCALES))/g'
+SED_ARGS+= -e 's/$(HASH)AvailableLocales_ENLocales$(HASH)/$(sort $(ALL_EN_LOCALES))/g'
+SED_ARGS+= -e 's/$(HASH)AvailableLocales_NonENLocales$(HASH)/$(sort $(ALL_NON_EN_LOCALES))/g'
 
 $(JDK_OUTPUTDIR)/gensrc/sun/util/locale/provider/LocaleDataMetaInfo.java: \
 		$(JDK_TOPDIR)/src/share/classes/sun/util/locale/provider/LocaleDataMetaInfo-XLocales.java.template
--- a/jdk/makefiles/Setup.gmk	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/makefiles/Setup.gmk	Wed Jul 05 19:11:53 2017 +0200
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,10 @@
 
 DISABLE_WARNINGS:=-Xlint:all,-deprecation,-unchecked,-rawtypes,-cast,-serial,-dep-ann,-static,-fallthrough,-try,-varargs,-empty,-finally
 
+# To build with all warnings enabled, do the following:
+# make JAVAC_WARNINGS="-Xlint:all -Xmaxwarns 10000" 
+JAVAC_WARNINGS:=-Xlint:-unchecked,-deprecation,-overrides,classfile,dep-ann,divzero,varargs -Werror
+
 # The generate old bytecode javac setup uses the new compiler to compile for the
 # boot jdk to generate tools that need to be run with the boot jdk.
 # Thus we force the target bytecode to 7.
@@ -41,7 +45,7 @@
      JVM:=$(JAVA),\
      JAVAC:=$(NEW_JAVAC),\
      FLAGS:=-bootclasspath $(JDK_OUTPUTDIR)/classes -source 8 -target 8 \
-	    -encoding ascii -XDignore.symbol.file=true $(DISABLE_WARNINGS) \
+	    -encoding ascii -XDignore.symbol.file=true $(JAVAC_WARNINGS) \
 	    $(GENERATE_JDKBYTECODE_EXTRA_FLAGS),\
      SERVER_DIR:=$(SJAVAC_SERVER_DIR),\
      SERVER_JVM:=$(SJAVAC_SERVER_JAVA)))
--- a/jdk/makefiles/mapfiles/liblcms/mapfile-vers	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/makefiles/mapfiles/liblcms/mapfile-vers	Wed Jul 05 19:11:53 2017 +0200
@@ -28,9 +28,8 @@
 SUNWprivate_1.1 {
 	global:
         Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative;
-        Java_sun_java2d_cmm_lcms_LCMS_freeProfileNative;
-        Java_sun_java2d_cmm_lcms_LCMS_getProfileSize;
-        Java_sun_java2d_cmm_lcms_LCMS_getProfileData;
+        Java_sun_java2d_cmm_lcms_LCMS_getProfileSizeNative;
+        Java_sun_java2d_cmm_lcms_LCMS_getProfileDataNative;
         Java_sun_java2d_cmm_lcms_LCMS_getTagNative;
         Java_sun_java2d_cmm_lcms_LCMS_setTagDataNative;
         Java_sun_java2d_cmm_lcms_LCMS_colorConvert;
--- a/jdk/src/macosx/classes/sun/lwawt/LWToolkit.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/macosx/classes/sun/lwawt/LWToolkit.java	Wed Jul 05 19:11:53 2017 +0200
@@ -38,6 +38,7 @@
 import sun.awt.*;
 import sun.lwawt.macosx.*;
 import sun.print.*;
+import sun.security.util.SecurityConstants;
 
 public abstract class LWToolkit extends SunToolkit implements Runnable {
 
@@ -502,7 +503,7 @@
     public Clipboard getSystemClipboard() {
         SecurityManager security = System.getSecurityManager();
         if (security != null) {
-            security.checkSystemClipboardAccess();
+            security.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
         }
 
         synchronized (this) {
--- a/jdk/src/macosx/native/sun/awt/CTextPipe.m	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/macosx/native/sun/awt/CTextPipe.m	Wed Jul 05 19:11:53 2017 +0200
@@ -145,11 +145,6 @@
 
     BOOL saved = false;
 
-    /* Save and restore of graphics context is done before the iteration.  
-       This seems to work using our test case (see bug ID 7158350) so we are restoring it at
-       the end of the for loop.  If we find out that save/restore outside the loop
-       doesn't work on all cases then we will move the Save/Restore inside the loop.*/
-    CGContextSaveGState(cgRef);
     CGAffineTransform invTx = CGAffineTransformInvert(strike->fTx);
 
     NSUInteger i;
@@ -226,7 +221,9 @@
 
     }
     // reset the font on the context after striking a unicode with CoreText
-    CGContextRestoreGState(cgRef);
+    if (saved) {
+        CGContextRestoreGState(cgRef);
+    }
 }
 
 // Using the Quartz Surface Data context, draw a hot-substituted character run
--- a/jdk/src/share/classes/com/sun/nio/sctp/Association.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/com/sun/nio/sctp/Association.java	Wed Jul 05 19:11:53 2017 +0200
@@ -58,6 +58,13 @@
 
     /**
      * Initializes a new instance of this class.
+     *
+     * @param  associationID
+     *         The association ID
+     * @param  maxInStreams
+     *         The maximum number of inbound streams
+     * @param  maxOutStreams
+     *         The maximum number of outbound streams
      */
     protected Association(int associationID,
                           int maxInStreams,
--- a/jdk/src/share/classes/com/sun/nio/sctp/IllegalReceiveException.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/com/sun/nio/sctp/IllegalReceiveException.java	Wed Jul 05 19:11:53 2017 +0200
@@ -41,6 +41,9 @@
 
     /**
      * Constructs an instance of this class with the specified message.
+     *
+     * @param  msg
+     *         The String that contains a detailed message
      */
     public IllegalReceiveException(String msg) {
         super(msg);
--- a/jdk/src/share/classes/com/sun/nio/sctp/IllegalUnbindException.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/com/sun/nio/sctp/IllegalUnbindException.java	Wed Jul 05 19:11:53 2017 +0200
@@ -41,6 +41,9 @@
 
     /**
      * Constructs an instance of this class with the specified detailed message.
+     *
+     * @param  msg
+     *         The String that contains a detailed message
      */
     public IllegalUnbindException(String msg) {
         super(msg);
--- a/jdk/src/share/classes/com/sun/nio/sctp/InvalidStreamException.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/com/sun/nio/sctp/InvalidStreamException.java	Wed Jul 05 19:11:53 2017 +0200
@@ -40,6 +40,9 @@
 
     /**
      * Constructs an instance of this class with the specified detailed message.
+     *
+     * @param  msg
+     *         The String that contains a detailed message
      */
     public InvalidStreamException(String msg) {
         super(msg);
--- a/jdk/src/share/classes/com/sun/nio/sctp/MessageInfo.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/com/sun/nio/sctp/MessageInfo.java	Wed Jul 05 19:11:53 2017 +0200
@@ -48,7 +48,7 @@
  * longer required to be sent after the time period expires. It is not a hard
  * timeout and may be influenced by whether the association supports the partial
  * reliability extension, <a href=http://www.ietf.org/rfc/rfc3758.txt>RFC 3758
- * <a>
+ * </a>.
  *
  * <P> {@code MessageInfo} instances are not safe for use by multiple concurrent
  * threads. If a MessageInfo is to be used by more than one thread then access
--- a/jdk/src/share/classes/com/sun/nio/sctp/Notification.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/com/sun/nio/sctp/Notification.java	Wed Jul 05 19:11:53 2017 +0200
@@ -40,6 +40,8 @@
 public interface Notification {
     /**
      * Returns the association that this notification is applicable to.
+     *
+     * @return  The association
      */
     public Association association();
 }
--- a/jdk/src/share/classes/com/sun/nio/sctp/SctpChannel.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/com/sun/nio/sctp/SctpChannel.java	Wed Jul 05 19:11:53 2017 +0200
@@ -59,7 +59,7 @@
  * {@link #setOption(SctpSocketOption,Object) setOption} method. An SCTP
  * channel support the following options:
  * <blockquote>
- * <table border>
+ * <table border summary="Socket options">
  *   <tr>
  *     <th>Option Name</th>
  *     <th>Description</th>
@@ -636,6 +636,9 @@
     /**
      * Returns the value of a socket option.
      *
+     * @param   <T>
+     *          The type of the socket option value
+     *
      * @param   name
      *          The socket option
      *
@@ -659,6 +662,9 @@
     /**
      * Sets the value of a socket option.
      *
+     * @param   <T>
+     *          The type of the socket option value
+     *
      * @param   name
      *          The socket option
      *
@@ -752,6 +758,9 @@
      * the {@code receive} method of this channel, if it does an
      * {@link IllegalReceiveException} will be thrown.
      *
+     * @param  <T>
+     *         The type of the attachment
+     *
      * @param  dst
      *         The buffer into which message bytes are to be transferred
      *
@@ -831,7 +840,7 @@
      *          there was insufficient room for the message in the underlying
      *          output buffer
      *
-     * @throws  InvalidStreamExcepton
+     * @throws  InvalidStreamException
      *          If {@code streamNumner} is negative or greater than or equal to
      *          the maximum number of outgoing streams
      *
--- a/jdk/src/share/classes/com/sun/nio/sctp/SctpMultiChannel.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/com/sun/nio/sctp/SctpMultiChannel.java	Wed Jul 05 19:11:53 2017 +0200
@@ -63,7 +63,7 @@
  * {@link #setOption(SctpSocketOption,Object,Association) setOption} method. An
  * {@code SctpMultiChannel} supports the following options:
  * <blockquote>
- * <table border>
+ * <table border summary="Socket options">
  *   <tr>
  *     <th>Option Name</th>
  *     <th>Description</th>
@@ -394,6 +394,9 @@
      * Returns all of the remote addresses to which the given association on
      * this channel's socket is connected.
      *
+     * @param  association
+     *         The association
+     *
      * @return  All of the remote addresses for the given association, or
      *          an empty {@code Set} if the association has been shutdown
      *
@@ -431,6 +434,9 @@
      * ignored if given. However, if the option is association specific then the
      * association must be given.
      *
+     * @param  <T>
+     *         The type of the socket option value
+     *
      * @param  name
      *         The socket option
      *
@@ -464,6 +470,9 @@
      * ignored if given. However, if the option is association specific then the
      * association must be given.
      *
+     * @param   <T>
+     *          The type of the socket option value
+     *
      * @param   name
      *          The socket option
      *
@@ -567,6 +576,9 @@
      * the {@code receive} method of this channel, if it does an
      * {@link IllegalReceiveException} will be thrown.
      *
+     * @param  <T>
+     *         The type of the attachment
+     *
      * @param  buffer
      *         The buffer into which bytes are to be transferred
      *
@@ -673,7 +685,7 @@
      *          there was insufficient room for the message in the underlying
      *          output buffer
      *
-     * @throws  InvalidStreamExcepton
+     * @throws  InvalidStreamException
      *          If {@code streamNumber} is negative, or if an association already
      *          exists and {@code streamNumber} is greater than the maximum number
      *          of outgoing streams
--- a/jdk/src/share/classes/com/sun/nio/sctp/SctpServerChannel.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/com/sun/nio/sctp/SctpServerChannel.java	Wed Jul 05 19:11:53 2017 +0200
@@ -47,7 +47,7 @@
  * {@link #setOption(SctpSocketOption,Object) setOption} method. SCTP server socket
  * channels support the following options:
  * <blockquote>
- * <table border>
+ * <table border summary="Socket options">
  *   <tr>
  *     <th>Option Name</th>
  *     <th>Description</th>
@@ -345,6 +345,9 @@
     /**
      * Returns the value of a socket option.
      *
+     * @param   <T>
+     *          The type of the socket option value
+     *
      * @param   name
      *          The socket option
      *
@@ -367,6 +370,9 @@
     /**
      * Sets the value of a socket option.
      *
+     * @param   <T>
+     *          The type of the socket option value
+     *
      * @param   name
      *          The socket option
      *
--- a/jdk/src/share/classes/java/awt/TextComponent.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/awt/TextComponent.java	Wed Jul 05 19:11:53 2017 +0200
@@ -35,6 +35,7 @@
 import javax.swing.text.AttributeSet;
 import javax.accessibility.*;
 import java.awt.im.InputMethodRequests;
+import sun.security.util.SecurityConstants;
 
 /**
  * The <code>TextComponent</code> class is the superclass of
@@ -728,7 +729,7 @@
         SecurityManager sm = System.getSecurityManager();
         if (sm == null) return true;
         try {
-            sm.checkSystemClipboardAccess();
+            sm.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
             return true;
         } catch (SecurityException e) {}
         return false;
--- a/jdk/src/share/classes/java/awt/Toolkit.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/awt/Toolkit.java	Wed Jul 05 19:11:53 2017 +0200
@@ -1270,12 +1270,8 @@
      * <p>
      * Each actual implementation of this method should first check if there
      * is a security manager installed. If there is, the method should call
-     * the security manager's <code>checkSystemClipboardAccess</code> method
-     * to ensure it's ok to to access the system clipboard. If the default
-     * implementation of <code>checkSystemClipboardAccess</code> is used (that
-     * is, that method is not overriden), then this results in a call to the
-     * security manager's <code>checkPermission</code> method with an <code>
-     * AWTPermission("accessClipboard")</code> permission.
+     * the security manager's {@link SecurityManager#checkPermission
+     * checkPermission} method to check {@code AWTPermission("accessClipboard")}.
      *
      * @return    the system Clipboard
      * @exception HeadlessException if GraphicsEnvironment.isHeadless()
@@ -1318,14 +1314,9 @@
      * system selection <code>Clipboard</code> as described above.
      * <p>
      * Each actual implementation of this method should first check if there
-     * is a <code>SecurityManager</code> installed. If there is, the method
-     * should call the <code>SecurityManager</code>'s
-     * <code>checkSystemClipboardAccess</code> method to ensure that client
-     * code has access the system selection. If the default implementation of
-     * <code>checkSystemClipboardAccess</code> is used (that is, if the method
-     * is not overridden), then this results in a call to the
-     * <code>SecurityManager</code>'s <code>checkPermission</code> method with
-     * an <code>AWTPermission("accessClipboard")</code> permission.
+     * is a security manager installed. If there is, the method should call
+     * the security manager's {@link SecurityManager#checkPermission
+     * checkPermission} method to check {@code AWTPermission("accessClipboard")}.
      *
      * @return the system selection as a <code>Clipboard</code>, or
      *         <code>null</code> if the native platform does not support a
@@ -1699,25 +1690,20 @@
      * therefore not assume that the EventQueue instance returned
      * by this method will be shared by other applets or the system.
      *
-     * <p>First, if there is a security manager, its
-     * <code>checkAwtEventQueueAccess</code>
-     * method is called.
-     * If  the default implementation of <code>checkAwtEventQueueAccess</code>
-     * is used (that is, that method is not overriden), then this results in
-     * a call to the security manager's <code>checkPermission</code> method
-     * with an <code>AWTPermission("accessEventQueue")</code> permission.
+     * <p> If there is a security manager then its
+     * {@link SecurityManager#checkPermission checkPermission} method
+     * is called to check {@code AWTPermission("accessEventQueue")}.
      *
      * @return    the <code>EventQueue</code> object
      * @throws  SecurityException
-     *          if a security manager exists and its <code>{@link
-     *          java.lang.SecurityManager#checkAwtEventQueueAccess}</code>
-     *          method denies access to the <code>EventQueue</code>
+     *          if a security manager is set and it denies access to
+     *          the {@code EventQueue}
      * @see     java.awt.AWTPermission
     */
     public final EventQueue getSystemEventQueue() {
         SecurityManager security = System.getSecurityManager();
         if (security != null) {
-          security.checkAwtEventQueueAccess();
+            security.checkPermission(SecurityConstants.AWT.CHECK_AWT_EVENTQUEUE_PERMISSION);
         }
         return getSystemEventQueueImpl();
     }
--- a/jdk/src/share/classes/java/awt/Window.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/awt/Window.java	Wed Jul 05 19:11:53 2017 +0200
@@ -195,10 +195,9 @@
     /**
      * This represents the warning message that is
      * to be displayed in a non secure window. ie :
-     * a window that has a security manager installed for
-     * which calling SecurityManager.checkTopLevelWindow()
-     * is false.  This message can be displayed anywhere in
-     * the window.
+     * a window that has a security manager installed that denies
+     * {@code AWTPermission("showWindowWithoutWarningBanner")}.
+     * This message can be displayed anywhere in the window.
      *
      * @serial
      * @see #getWarningString
@@ -417,11 +416,10 @@
      * Constructs a new, initially invisible window in default size with the
      * specified {@code GraphicsConfiguration}.
      * <p>
-     * If there is a security manager, this method first calls
-     * the security manager's {@code checkTopLevelWindow}
-     * method with {@code this}
-     * as its argument to determine whether or not the window
-     * must be displayed with a warning banner.
+     * If there is a security manager, then it is invoked to check
+     * {@code AWTPermission("showWindowWithoutWarningBanner")}
+     * to determine whether or not the window must be displayed with
+     * a warning banner.
      *
      * @param gc the {@code GraphicsConfiguration} of the target screen
      *     device. If {@code gc} is {@code null}, the system default
@@ -432,7 +430,6 @@
      *     {@code GraphicsEnvironment.isHeadless()} returns {@code true}
      *
      * @see java.awt.GraphicsEnvironment#isHeadless
-     * @see java.lang.SecurityManager#checkTopLevelWindow
      */
     Window(GraphicsConfiguration gc) {
         init(gc);
@@ -511,25 +508,16 @@
 
     /**
      * Constructs a new, initially invisible window in the default size.
-     *
-     * <p>First, if there is a security manager, its
-     * {@code checkTopLevelWindow}
-     * method is called with {@code this}
-     * as its argument
-     * to see if it's ok to display the window without a warning banner.
-     * If the default implementation of {@code checkTopLevelWindow}
-     * is used (that is, that method is not overriden), then this results in
-     * a call to the security manager's {@code checkPermission} method
-     * with an {@code AWTPermission("showWindowWithoutWarningBanner")}
-     * permission. It that method raises a SecurityException,
-     * {@code checkTopLevelWindow} returns false, otherwise it
-     * returns true. If it returns false, a warning banner is created.
+     * <p>
+     * If there is a security manager set, it is invoked to check
+     * {@code AWTPermission("showWindowWithoutWarningBanner")}.
+     * If that check fails with a {@code SecurityException} then a warning
+     * banner is created.
      *
      * @exception HeadlessException when
      *     {@code GraphicsEnvironment.isHeadless()} returns {@code true}
      *
      * @see java.awt.GraphicsEnvironment#isHeadless
-     * @see java.lang.SecurityManager#checkTopLevelWindow
      */
     Window() throws HeadlessException {
         GraphicsEnvironment.checkHeadless();
@@ -541,11 +529,10 @@
      * {@code Frame} as its owner. The window will not be focusable
      * unless its owner is showing on the screen.
      * <p>
-     * If there is a security manager, this method first calls
-     * the security manager's {@code checkTopLevelWindow}
-     * method with {@code this}
-     * as its argument to determine whether or not the window
-     * must be displayed with a warning banner.
+     * If there is a security manager set, it is invoked to check
+     * {@code AWTPermission("showWindowWithoutWarningBanner")}.
+     * If that check fails with a {@code SecurityException} then a warning
+     * banner is created.
      *
      * @param owner the {@code Frame} to act as owner or {@code null}
      *    if this window has no owner
@@ -555,7 +542,6 @@
      *    {@code GraphicsEnvironment.isHeadless} returns {@code true}
      *
      * @see java.awt.GraphicsEnvironment#isHeadless
-     * @see java.lang.SecurityManager#checkTopLevelWindow
      * @see #isShowing
      */
     public Window(Frame owner) {
@@ -570,11 +556,10 @@
      * unless its nearest owning {@code Frame} or {@code Dialog}
      * is showing on the screen.
      * <p>
-     * If there is a security manager, this method first calls
-     * the security manager's {@code checkTopLevelWindow}
-     * method with {@code this}
-     * as its argument to determine whether or not the window
-     * must be displayed with a warning banner.
+     * If there is a security manager set, it is invoked to check
+     * {@code AWTPermission("showWindowWithoutWarningBanner")}.
+     * If that check fails with a {@code SecurityException} then a
+     * warning banner is created.
      *
      * @param owner the {@code Window} to act as owner or
      *     {@code null} if this window has no owner
@@ -585,7 +570,6 @@
      *     {@code true}
      *
      * @see       java.awt.GraphicsEnvironment#isHeadless
-     * @see       java.lang.SecurityManager#checkTopLevelWindow
      * @see       #isShowing
      *
      * @since     1.2
@@ -603,11 +587,10 @@
      * its nearest owning {@code Frame} or {@code Dialog}
      * is showing on the screen.
      * <p>
-     * If there is a security manager, this method first calls
-     * the security manager's {@code checkTopLevelWindow}
-     * method with {@code this}
-     * as its argument to determine whether or not the window
-     * must be displayed with a warning banner.
+     * If there is a security manager set, it is invoked to check
+     * {@code AWTPermission("showWindowWithoutWarningBanner")}. If that
+     * check fails with a {@code SecurityException} then a warning banner
+     * is created.
      *
      * @param owner the window to act as owner or {@code null}
      *     if this window has no owner
@@ -621,7 +604,6 @@
      *     {@code true}
      *
      * @see       java.awt.GraphicsEnvironment#isHeadless
-     * @see       java.lang.SecurityManager#checkTopLevelWindow
      * @see       GraphicsConfiguration#getBounds
      * @see       #isShowing
      * @since     1.3
@@ -1362,10 +1344,9 @@
      * Gets the warning string that is displayed with this window.
      * If this window is insecure, the warning string is displayed
      * somewhere in the visible area of the window. A window is
-     * insecure if there is a security manager, and the security
-     * manager's {@code checkTopLevelWindow} method returns
-     * {@code false} when this window is passed to it as an
-     * argument.
+     * insecure if there is a security manager and the security
+     * manager denies
+     * {@code AWTPermission("showWindowWithoutWarningBanner")}.
      * <p>
      * If the window is secure, then {@code getWarningString}
      * returns {@code null}. If the window is insecure, this
@@ -1373,7 +1354,6 @@
      * {@code awt.appletWarning}
      * and returns the string value of that property.
      * @return    the warning string for this window.
-     * @see       java.lang.SecurityManager#checkTopLevelWindow(java.lang.Object)
      */
     public final String getWarningString() {
         return warningString;
@@ -1383,10 +1363,12 @@
         warningString = null;
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            if (!sm.checkTopLevelWindow(this)) {
+            try {
+                sm.checkPermission(SecurityConstants.AWT.TOPLEVEL_WINDOW_PERMISSION);
+            } catch (SecurityException se) {
                 // make sure the privileged action is only
                 // for getting the property! We don't want the
-                // above checkTopLevelWindow call to always succeed!
+                // above checkPermission call to always succeed!
                 warningString = AccessController.doPrivileged(
                       new GetPropertyAction("awt.appletWarning",
                                             "Java Applet Window"));
--- a/jdk/src/share/classes/java/awt/color/ICC_Profile.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/awt/color/ICC_Profile.java	Wed Jul 05 19:11:53 2017 +0200
@@ -37,6 +37,7 @@
 
 import sun.java2d.cmm.PCMM;
 import sun.java2d.cmm.CMSManager;
+import sun.java2d.cmm.Profile;
 import sun.java2d.cmm.ProfileDataVerifier;
 import sun.java2d.cmm.ProfileDeferralMgr;
 import sun.java2d.cmm.ProfileDeferralInfo;
@@ -94,7 +95,7 @@
 
     private static final long serialVersionUID = -3938515861990936766L;
 
-    transient long ID;
+    private transient Profile cmmProfile;
 
     private transient ProfileDeferralInfo deferralInfo;
     private transient ProfileActivator profileActivator;
@@ -727,8 +728,8 @@
     /**
      * Constructs an ICC_Profile object with a given ID.
      */
-    ICC_Profile(long ID) {
-        this.ID = ID;
+    ICC_Profile(Profile p) {
+        this.cmmProfile = p;
     }
 
 
@@ -751,8 +752,8 @@
      * Frees the resources associated with an ICC_Profile object.
      */
     protected void finalize () {
-        if (ID != 0) {
-            CMSManager.getModule().freeProfile(ID);
+        if (cmmProfile != null) {
+            CMSManager.getModule().freeProfile(cmmProfile);
         } else if (profileActivator != null) {
             ProfileDeferralMgr.unregisterDeferral(profileActivator);
         }
@@ -770,7 +771,7 @@
     public static ICC_Profile getInstance(byte[] data) {
     ICC_Profile thisProfile;
 
-        long theID;
+        Profile p = null;
 
         if (ProfileDeferralMgr.deferring) {
             ProfileDeferralMgr.activateProfiles();
@@ -779,32 +780,32 @@
         ProfileDataVerifier.verify(data);
 
         try {
-            theID = CMSManager.getModule().loadProfile(data);
+            p = CMSManager.getModule().loadProfile(data);
         } catch (CMMException c) {
             throw new IllegalArgumentException("Invalid ICC Profile Data");
         }
 
         try {
-            if ((getColorSpaceType (theID) == ColorSpace.TYPE_GRAY) &&
-                (getData (theID, icSigMediaWhitePointTag) != null) &&
-                (getData (theID, icSigGrayTRCTag) != null)) {
-                thisProfile = new ICC_ProfileGray (theID);
+            if ((getColorSpaceType (p) == ColorSpace.TYPE_GRAY) &&
+                (getData (p, icSigMediaWhitePointTag) != null) &&
+                (getData (p, icSigGrayTRCTag) != null)) {
+                thisProfile = new ICC_ProfileGray (p);
             }
-            else if ((getColorSpaceType (theID) == ColorSpace.TYPE_RGB) &&
-                (getData (theID, icSigMediaWhitePointTag) != null) &&
-                (getData (theID, icSigRedColorantTag) != null) &&
-                (getData (theID, icSigGreenColorantTag) != null) &&
-                (getData (theID, icSigBlueColorantTag) != null) &&
-                (getData (theID, icSigRedTRCTag) != null) &&
-                (getData (theID, icSigGreenTRCTag) != null) &&
-                (getData (theID, icSigBlueTRCTag) != null)) {
-                thisProfile = new ICC_ProfileRGB (theID);
+            else if ((getColorSpaceType (p) == ColorSpace.TYPE_RGB) &&
+                (getData (p, icSigMediaWhitePointTag) != null) &&
+                (getData (p, icSigRedColorantTag) != null) &&
+                (getData (p, icSigGreenColorantTag) != null) &&
+                (getData (p, icSigBlueColorantTag) != null) &&
+                (getData (p, icSigRedTRCTag) != null) &&
+                (getData (p, icSigGreenTRCTag) != null) &&
+                (getData (p, icSigBlueTRCTag) != null)) {
+                thisProfile = new ICC_ProfileRGB (p);
             }
             else {
-                thisProfile = new ICC_Profile (theID);
+                thisProfile = new ICC_Profile (p);
             }
         } catch (CMMException c) {
-            thisProfile = new ICC_Profile (theID);
+            thisProfile = new ICC_Profile (p);
         }
         return thisProfile;
     }
@@ -1119,7 +1120,7 @@
                 fileName);
         }
         try {
-            ID = CMSManager.getModule().loadProfile(profileData);
+            cmmProfile = CMSManager.getModule().loadProfile(profileData);
         } catch (CMMException c) {
             ProfileDataException pde = new
                 ProfileDataException("Invalid ICC Profile Data" + fileName);
@@ -1229,14 +1230,14 @@
                                                    causing a deferred profile
                                                    to be loaded */
         }
-        return    getColorSpaceType(ID);
+        return    getColorSpaceType(cmmProfile);
     }
 
-    static int getColorSpaceType(long profileID) {
+    static int getColorSpaceType(Profile p) {
     byte[] theHeader;
     int theColorSpaceSig, theColorSpace;
 
-        theHeader = getData(profileID, icSigHead);
+        theHeader = getData(p, icSigHead);
         theColorSpaceSig = intFromBigEndian(theHeader, icHdrColorSpace);
         theColorSpace = iccCStoJCS (theColorSpaceSig);
         return theColorSpace;
@@ -1258,15 +1259,15 @@
         if (ProfileDeferralMgr.deferring) {
             ProfileDeferralMgr.activateProfiles();
         }
-        return getPCSType(ID);
+        return getPCSType(cmmProfile);
     }
 
 
-    static int getPCSType(long profileID) {
+    static int getPCSType(Profile p) {
     byte[] theHeader;
     int thePCSSig, thePCS;
 
-        theHeader = getData(profileID, icSigHead);
+        theHeader = getData(p, icSigHead);
         thePCSSig = intFromBigEndian(theHeader, icHdrPcs);
         thePCS = iccCStoJCS(thePCSSig);
         return thePCS;
@@ -1326,12 +1327,12 @@
         PCMM mdl = CMSManager.getModule();
 
         /* get the number of bytes needed for this profile */
-        profileSize = mdl.getProfileSize(ID);
+        profileSize = mdl.getProfileSize(cmmProfile);
 
         profileData = new byte [profileSize];
 
         /* get the data for the profile */
-        mdl.getProfileData(ID, profileData);
+        mdl.getProfileData(cmmProfile, profileData);
 
         return profileData;
     }
@@ -1358,11 +1359,11 @@
             ProfileDeferralMgr.activateProfiles();
         }
 
-        return getData(ID, tagSignature);
+        return getData(cmmProfile, tagSignature);
     }
 
 
-    static byte[] getData(long profileID, int tagSignature) {
+    static byte[] getData(Profile p, int tagSignature) {
     int tagSize;
     byte[] tagData;
 
@@ -1370,12 +1371,12 @@
             PCMM mdl = CMSManager.getModule();
 
             /* get the number of bytes needed for this tag */
-            tagSize = mdl.getTagSize(profileID, tagSignature);
+            tagSize = mdl.getTagSize(p, tagSignature);
 
             tagData = new byte[tagSize]; /* get an array for the tag */
 
             /* get the tag's data */
-            mdl.getTagData(profileID, tagSignature, tagData);
+            mdl.getTagData(p, tagSignature, tagData);
         } catch(CMMException c) {
             tagData = null;
         }
@@ -1406,7 +1407,7 @@
             ProfileDeferralMgr.activateProfiles();
         }
 
-        CMSManager.getModule().setTagData(ID, tagSignature, tagData);
+        CMSManager.getModule().setTagData(cmmProfile, tagSignature, tagData);
     }
 
     /**
--- a/jdk/src/share/classes/java/awt/color/ICC_ProfileGray.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/awt/color/ICC_ProfileGray.java	Wed Jul 05 19:11:53 2017 +0200
@@ -35,7 +35,7 @@
 
 package java.awt.color;
 
-import java.awt.image.LookupTable;
+import sun.java2d.cmm.Profile;
 import sun.java2d.cmm.ProfileDeferralInfo;
 
 /**
@@ -76,8 +76,8 @@
     /**
      * Constructs a new ICC_ProfileGray from a CMM ID.
      */
-    ICC_ProfileGray(long ID) {
-        super(ID);
+    ICC_ProfileGray(Profile p) {
+        super(p);
     }
 
     /**
--- a/jdk/src/share/classes/java/awt/color/ICC_ProfileRGB.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/awt/color/ICC_ProfileRGB.java	Wed Jul 05 19:11:53 2017 +0200
@@ -35,7 +35,7 @@
 
 package java.awt.color;
 
-import java.awt.image.LookupTable;
+import sun.java2d.cmm.Profile;
 import sun.java2d.cmm.ProfileDeferralInfo;
 
 /**
@@ -114,8 +114,8 @@
      * @param ID The CMM ID for the profile.
      *
      */
-    ICC_ProfileRGB(long ID) {
-        super(ID);
+    ICC_ProfileRGB(Profile p) {
+        super(p);
     }
 
     /**
--- a/jdk/src/share/classes/java/awt/event/InputEvent.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/awt/event/InputEvent.java	Wed Jul 05 19:11:53 2017 +0200
@@ -33,6 +33,7 @@
 
 import sun.awt.AWTAccessor;
 import sun.util.logging.PlatformLogger;
+import sun.security.util.SecurityConstants;
 
 /**
  * The root event class for all component-level input events.
@@ -350,7 +351,7 @@
             SecurityManager sm = System.getSecurityManager();
             if (sm != null) {
                 try {
-                    sm.checkSystemClipboardAccess();
+                    sm.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
                     b = true;
                 } catch (SecurityException se) {
                     if (logger.isLoggable(PlatformLogger.Level.FINE)) {
--- a/jdk/src/share/classes/java/io/Console.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/io/Console.java	Wed Jul 05 19:11:53 2017 +0200
@@ -124,9 +124,11 @@
     * {@link java.io.Reader#read(java.nio.CharBuffer) read(java.nio.CharBuffer)}
     * on the returned object will not read in characters beyond the line
     * bound for each invocation, even if the destination buffer has space for
-    * more characters. A line bound is considered to be any one of a line feed
-    * (<tt>'\n'</tt>), a carriage return (<tt>'\r'</tt>), a carriage return
-    * followed immediately by a linefeed, or an end of stream.
+    * more characters. The {@code Reader}'s {@code read} methods may block if a
+    * line bound has not been entered or reached on the console's input device.
+    * A line bound is considered to be any one of a line feed (<tt>'\n'</tt>),
+    * a carriage return (<tt>'\r'</tt>), a carriage return followed immediately
+    * by a linefeed, or an end of stream.
     *
     * @return  The reader associated with this console
     */
--- a/jdk/src/share/classes/java/lang/AutoCloseable.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/lang/AutoCloseable.java	Wed Jul 05 19:11:53 2017 +0200
@@ -26,7 +26,24 @@
 package java.lang;
 
 /**
- * A resource that must be closed when it is no longer needed.
+ * An object that may hold resources (such as file or socket handles)
+ * until it is closed. The {@link #close()} method of an {@code AutoCloseable}
+ * object is called automatically when exiting a {@code
+ * try}-with-resources block for which the object has been declared in
+ * the resource specification header. This construction ensures prompt
+ * release, avoiding resource exhaustion exceptions and errors that
+ * may otherwise occur.
+ *
+ * @apiNote
+ * <p>It is possible, and in fact common, for a base class to
+ * implement AutoCloseable even though not all of its subclasses or
+ * instances will hold releasable resources.  For code that must operate
+ * in complete generality, or when it is known that the {@code AutoCloseable}
+ * instance requires resource release, it is recommended to use {@code
+ * try}-with-resources constructions. However, when using facilities such as
+ * {@link java.util.stream.Stream} that support both I/O-based and
+ * non-I/O-based forms, {@code try}-with-resources blocks are in
+ * general unnecessary when using non-I/O-based forms.
  *
  * @author Josh Bloch
  * @since 1.7
--- a/jdk/src/share/classes/java/lang/Class.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/lang/Class.java	Wed Jul 05 19:11:53 2017 +0200
@@ -821,6 +821,10 @@
      * <p> If this object represents a primitive type or void, the method
      * returns an array of length 0.
      *
+     * <p> If this {@code Class} object represents an array type, the
+     * interfaces {@code Cloneable} and {@code java.io.Serializable} are
+     * returned in that order.
+     *
      * @return an array of interfaces implemented by this class.
      */
     public Class<?>[] getInterfaces() {
@@ -1484,22 +1488,24 @@
     /**
      * Returns an array containing {@code Field} objects reflecting all
      * the accessible public fields of the class or interface represented by
-     * this {@code Class} object.  The elements in the array returned are
-     * not sorted and are not in any particular order.  This method returns an
-     * array of length 0 if the class or interface has no accessible public
-     * fields, or if it represents an array class, a primitive type, or void.
+     * this {@code Class} object.
+     *
+     * <p> If this {@code Class} object represents a class or interface with no
+     * no accessible public fields, then this method returns an array of length
+     * 0.
+     *
+     * <p> If this {@code Class} object represents a class, then this method
+     * returns the public fields of the class and of all its superclasses.
      *
-     * <p> Specifically, if this {@code Class} object represents a class,
-     * this method returns the public fields of this class and of all its
-     * superclasses.  If this {@code Class} object represents an
-     * interface, this method returns the fields of this interface and of all
-     * its superinterfaces.
+     * <p> If this {@code Class} object represents an interface, then this
+     * method returns the fields of the interface and of all its
+     * superinterfaces.
      *
-     * <p> The implicit length field for array class is not reflected by this
-     * method. User code should use the methods of class {@code Array} to
-     * manipulate arrays.
+     * <p> If this {@code Class} object represents an array type, a primitive
+     * type, or void, then this method returns an array of length 0.
      *
-     * <p> See <em>The Java Language Specification</em>, sections 8.2 and 8.3.
+     * <p> The elements in the returned array are not sorted and are not in any
+     * particular order.
      *
      * @return the array of {@code Field} objects representing the
      *         public fields
@@ -1512,6 +1518,8 @@
      *         of this class.
      *
      * @since JDK1.1
+     * @jls 8.2 Class Members
+     * @jls 8.3 Field Declarations
      */
     @CallerSensitive
     public Field[] getFields() throws SecurityException {
@@ -1521,23 +1529,33 @@
 
 
     /**
-     * Returns an array containing {@code Method} objects reflecting all
-     * the public <em>member</em> methods of the class or interface represented
-     * by this {@code Class} object, including those declared by the class
-     * or interface and those inherited from superclasses and
-     * superinterfaces.  Array classes return all the (public) member methods
-     * inherited from the {@code Object} class.  The elements in the array
-     * returned are not sorted and are not in any particular order.  This
-     * method returns an array of length 0 if this {@code Class} object
-     * represents a class or interface that has no public member methods, or if
-     * this {@code Class} object represents a primitive type or void.
+     * Returns an array containing {@code Method} objects reflecting all the
+     * public methods of the class or interface represented by this {@code
+     * Class} object, including those declared by the class or interface and
+     * those inherited from superclasses and superinterfaces.
+     *
+     * <p> If this {@code Class} object represents a type that has multiple
+     * public methods with the same name and parameter types, but different
+     * return types, then the returned array has a {@code Method} object for
+     * each such method.
+     *
+     * <p> If this {@code Class} object represents a type with a class
+     * initialization method {@code <clinit>}, then the returned array does
+     * <em>not</em> have a corresponding {@code Method} object.
      *
-     * <p> The class initialization method {@code <clinit>} is not
-     * included in the returned array. If the class declares multiple public
-     * member methods with the same parameter types, they are all included in
-     * the returned array.
+     * <p> If this {@code Class} object represents an array type, then the
+     * returned array has a {@code Method} object for each of the public
+     * methods inherited by the array type from {@code Object}. It does not
+     * contain a {@code Method} object for {@code clone()}.
      *
-     * <p> See <em>The Java Language Specification</em>, sections 8.2 and 8.4.
+     * <p> If this {@code Class} object represents a class or interface with no
+     * public methods, then the returned array has length 0.
+     *
+     * <p> If this {@code Class} object represents a primitive type or void,
+     * then the returned array has length 0.
+     *
+     * <p> The elements in the returned array are not sorted and are not in any
+     * particular order.
      *
      * @return the array of {@code Method} objects representing the
      *         public methods of this class
@@ -1549,6 +1567,8 @@
      *         s.checkPackageAccess()} denies access to the package
      *         of this class.
      *
+     * @jls 8.2 Class Members
+     * @jls 8.4 Method Declarations
      * @since JDK1.1
      */
     @CallerSensitive
@@ -1595,13 +1615,14 @@
 
 
     /**
-     * Returns a {@code Field} object that reflects the specified public
-     * member field of the class or interface represented by this
-     * {@code Class} object. The {@code name} parameter is a
-     * {@code String} specifying the simple name of the desired field.
+     * Returns a {@code Field} object that reflects the specified public member
+     * field of the class or interface represented by this {@code Class}
+     * object. The {@code name} parameter is a {@code String} specifying the
+     * simple name of the desired field.
      *
      * <p> The field to be reflected is determined by the algorithm that
-     * follows.  Let C be the class represented by this object:
+     * follows.  Let C be the class or interface represented by this object:
+     *
      * <OL>
      * <LI> If C declares a public field with the name specified, that is the
      *      field to be reflected.</LI>
@@ -1614,7 +1635,8 @@
      *      is thrown.</LI>
      * </OL>
      *
-     * <p> See <em>The Java Language Specification</em>, sections 8.2 and 8.3.
+     * <p> If this {@code Class} object represents an array type, then this
+     * method does not find the {@code length} field of the array type.
      *
      * @param name the field name
      * @return the {@code Field} object of this class specified by
@@ -1631,6 +1653,8 @@
      *         of this class.
      *
      * @since JDK1.1
+     * @jls 8.2 Class Members
+     * @jls 8.3 Field Declarations
      */
     @CallerSensitive
     public Field getField(String name)
@@ -1685,7 +1709,8 @@
      * method and the method being overridden would have the same
      * signature but different return types.
      *
-     * <p> See <em>The Java Language Specification</em>, sections 8.2 and 8.4.
+     * <p> If this {@code Class} object represents an array type, then this
+     * method does not find the {@code clone()} method.
      *
      * @param name the name of the method
      * @param parameterTypes the list of parameters
@@ -1702,6 +1727,8 @@
      *         s.checkPackageAccess()} denies access to the package
      *         of this class.
      *
+     * @jls 8.2 Class Members
+     * @jls 8.4 Method Declarations
      * @since JDK1.1
      */
     @CallerSensitive
@@ -1800,12 +1827,15 @@
      * declared by the class or interface represented by this
      * {@code Class} object. This includes public, protected, default
      * (package) access, and private fields, but excludes inherited fields.
-     * The elements in the array returned are not sorted and are not in any
-     * particular order.  This method returns an array of length 0 if the class
-     * or interface declares no fields, or if this {@code Class} object
-     * represents a primitive type, an array class, or void.
+     *
+     * <p> If this {@code Class} object represents a class or interface with no
+     * declared fields, then this method returns an array of length 0.
      *
-     * <p> See <em>The Java Language Specification</em>, sections 8.2 and 8.3.
+     * <p> If this {@code Class} object represents an array type, a primitive
+     * type, or void, then this method returns an array of length 0.
+     *
+     * <p> The elements in the returned array are not sorted and are not in any
+     * particular order.
      *
      * @return  the array of {@code Field} objects representing all the
      *          declared fields of this class
@@ -1831,6 +1861,8 @@
      *          </ul>
      *
      * @since JDK1.1
+     * @jls 8.2 Class Members
+     * @jls 8.3 Field Declarations
      */
     @CallerSensitive
     public Field[] getDeclaredFields() throws SecurityException {
@@ -1840,20 +1872,29 @@
 
 
     /**
-     * Returns an array of {@code Method} objects reflecting all the
-     * methods declared by the class or interface represented by this
-     * {@code Class} object. This includes public, protected, default
-     * (package) access, and private methods, but excludes inherited methods.
-     * The elements in the array returned are not sorted and are not in any
-     * particular order.  This method returns an array of length 0 if the class
-     * or interface declares no methods, or if this {@code Class} object
-     * represents a primitive type, an array class, or void.  The class
-     * initialization method {@code <clinit>} is not included in the
-     * returned array. If the class declares multiple public member methods
-     * with the same parameter types, they are all included in the returned
-     * array.
+     *
+     * Returns an array containing {@code Method} objects reflecting all the
+     * declared methods of the class or interface represented by this {@code
+     * Class} object, including public, protected, default (package)
+     * access, and private methods, but excluding inherited methods.
+     *
+     * <p> If this {@code Class} object represents a type that has multiple
+     * declared methods with the same name and parameter types, but different
+     * return types, then the returned array has a {@code Method} object for
+     * each such method.
      *
-     * <p> See <em>The Java Language Specification</em>, section 8.2.
+     * <p> If this {@code Class} object represents a type that has a class
+     * initialization method {@code <clinit>}, then the returned array does
+     * <em>not</em> have a corresponding {@code Method} object.
+     *
+     * <p> If this {@code Class} object represents a class or interface with no
+     * declared methods, then the returned array has length 0.
+     *
+     * <p> If this {@code Class} object represents an array type, a primitive
+     * type, or void, then the returned array has length 0.
+     *
+     * <p> The elements in the returned array are not sorted and are not in any
+     * particular order.
      *
      * @return  the array of {@code Method} objects representing all the
      *          declared methods of this class
@@ -1878,6 +1919,8 @@
      *
      *          </ul>
      *
+     * @jls 8.2 Class Members
+     * @jls 8.4 Method Declarations
      * @since JDK1.1
      */
     @CallerSensitive
@@ -1935,9 +1978,11 @@
     /**
      * Returns a {@code Field} object that reflects the specified declared
      * field of the class or interface represented by this {@code Class}
-     * object. The {@code name} parameter is a {@code String} that
-     * specifies the simple name of the desired field.  Note that this method
-     * will not reflect the {@code length} field of an array class.
+     * object. The {@code name} parameter is a {@code String} that specifies
+     * the simple name of the desired field.
+     *
+     * <p> If this {@code Class} object represents an array type, then this
+     * method does not find the {@code length} field of the array type.
      *
      * @param name the name of the field
      * @return  the {@code Field} object for the specified field in this
@@ -1967,6 +2012,8 @@
      *          </ul>
      *
      * @since JDK1.1
+     * @jls 8.2 Class Members
+     * @jls 8.3 Field Declarations
      */
     @CallerSensitive
     public Field getDeclaredField(String name)
@@ -1994,6 +2041,9 @@
      * name is "&lt;init&gt;"or "&lt;clinit&gt;" a {@code NoSuchMethodException}
      * is raised.
      *
+     * <p> If this {@code Class} object represents an array type, then this
+     * method does not find the {@code clone()} method.
+     *
      * @param name the name of the method
      * @param parameterTypes the parameter array
      * @return  the {@code Method} object for the method of this class
@@ -2021,6 +2071,8 @@
      *
      *          </ul>
      *
+     * @jls 8.2 Class Members
+     * @jls 8.4 Method Declarations
      * @since JDK1.1
      */
     @CallerSensitive
--- a/jdk/src/share/classes/java/lang/Math.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/lang/Math.java	Wed Jul 05 19:11:53 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -646,7 +646,7 @@
 
     /**
      * Returns the closest {@code int} to the argument, with ties
-     * rounding up.
+     * rounding to positive infinity.
      *
      * <p>
      * Special cases:
@@ -665,15 +665,37 @@
      * @see     java.lang.Integer#MIN_VALUE
      */
     public static int round(float a) {
-        if (a != 0x1.fffffep-2f) // greatest float value less than 0.5
-            return (int)floor(a + 0.5f);
-        else
-            return 0;
+        int intBits = Float.floatToRawIntBits(a);
+        int biasedExp = (intBits & FloatConsts.EXP_BIT_MASK)
+                >> (FloatConsts.SIGNIFICAND_WIDTH - 1);
+        int shift = (FloatConsts.SIGNIFICAND_WIDTH - 2
+                + FloatConsts.EXP_BIAS) - biasedExp;
+        if ((shift & -32) == 0) { // shift >= 0 && shift < 32
+            // a is a finite number such that pow(2,-32) <= ulp(a) < 1
+            int r = ((intBits & FloatConsts.SIGNIF_BIT_MASK)
+                    | (FloatConsts.SIGNIF_BIT_MASK + 1));
+            if (intBits < 0) {
+                r = -r;
+            }
+            // In the comments below each Java expression evaluates to the value
+            // the corresponding mathematical expression:
+            // (r) evaluates to a / ulp(a)
+            // (r >> shift) evaluates to floor(a * 2)
+            // ((r >> shift) + 1) evaluates to floor((a + 1/2) * 2)
+            // (((r >> shift) + 1) >> 1) evaluates to floor(a + 1/2)
+            return ((r >> shift) + 1) >> 1;
+        } else {
+            // a is either
+            // - a finite number with abs(a) < exp(2,FloatConsts.SIGNIFICAND_WIDTH-32) < 1/2
+            // - a finite number with ulp(a) >= 1 and hence a is a mathematical integer
+            // - an infinity or NaN
+            return (int) a;
+        }
     }
 
     /**
      * Returns the closest {@code long} to the argument, with ties
-     * rounding up.
+     * rounding to positive infinity.
      *
      * <p>Special cases:
      * <ul><li>If the argument is NaN, the result is 0.
@@ -692,10 +714,32 @@
      * @see     java.lang.Long#MIN_VALUE
      */
     public static long round(double a) {
-        if (a != 0x1.fffffffffffffp-2) // greatest double value less than 0.5
-            return (long)floor(a + 0.5d);
-        else
-            return 0;
+        long longBits = Double.doubleToRawLongBits(a);
+        long biasedExp = (longBits & DoubleConsts.EXP_BIT_MASK)
+                >> (DoubleConsts.SIGNIFICAND_WIDTH - 1);
+        long shift = (DoubleConsts.SIGNIFICAND_WIDTH - 2
+                + DoubleConsts.EXP_BIAS) - biasedExp;
+        if ((shift & -64) == 0) { // shift >= 0 && shift < 64
+            // a is a finite number such that pow(2,-64) <= ulp(a) < 1
+            long r = ((longBits & DoubleConsts.SIGNIF_BIT_MASK)
+                    | (DoubleConsts.SIGNIF_BIT_MASK + 1));
+            if (longBits < 0) {
+                r = -r;
+            }
+            // In the comments below each Java expression evaluates to the value
+            // the corresponding mathematical expression:
+            // (r) evaluates to a / ulp(a)
+            // (r >> shift) evaluates to floor(a * 2)
+            // ((r >> shift) + 1) evaluates to floor((a + 1/2) * 2)
+            // (((r >> shift) + 1) >> 1) evaluates to floor(a + 1/2)
+            return ((r >> shift) + 1) >> 1;
+        } else {
+            // a is either
+            // - a finite number with abs(a) < exp(2,DoubleConsts.SIGNIFICAND_WIDTH-64) < 1/2
+            // - a finite number with ulp(a) >= 1 and hence a is a mathematical integer
+            // - an infinity or NaN
+            return (long) a;
+        }
     }
 
     private static final class RandomNumberGeneratorHolder {
--- a/jdk/src/share/classes/java/lang/SecurityManager.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/lang/SecurityManager.java	Wed Jul 05 19:11:53 2017 +0200
@@ -1336,9 +1336,16 @@
      *             top-level windows; <code>false</code> otherwise.
      * @exception  NullPointerException if the <code>window</code> argument is
      *             <code>null</code>.
+     * @deprecated The dependency on {@code AWTPermission} creates an
+     *             impediment to future modularization of the Java platform.
+     *             Users of this method should instead invoke
+     *             {@link #checkPermission} directly.
+     *             This method will be changed in a future release to check
+     *             the permission {@code java.security.AllPermission}.
      * @see        java.awt.Window
      * @see        #checkPermission(java.security.Permission) checkPermission
      */
+    @Deprecated
     public boolean checkTopLevelWindow(Object window) {
         if (window == null) {
             throw new NullPointerException("window can't be null");
@@ -1398,8 +1405,15 @@
      * @since   JDK1.1
      * @exception  SecurityException  if the calling thread does not have
      *             permission to access the system clipboard.
+     * @deprecated The dependency on {@code AWTPermission} creates an
+     *             impediment to future modularization of the Java platform.
+     *             Users of this method should instead invoke
+     *             {@link #checkPermission} directly.
+     *             This method will be changed in a future release to check
+     *             the permission {@code java.security.AllPermission}.
      * @see        #checkPermission(java.security.Permission) checkPermission
      */
+    @Deprecated
     public void checkSystemClipboardAccess() {
         Permission perm = SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION;
         if (perm == null) {
@@ -1427,8 +1441,15 @@
      * @since   JDK1.1
      * @exception  SecurityException  if the calling thread does not have
      *             permission to access the AWT event queue.
+     * @deprecated The dependency on {@code AWTPermission} creates an
+     *             impediment to future modularization of the Java platform.
+     *             Users of this method should instead invoke
+     *             {@link #checkPermission} directly.
+     *             This method will be changed in a future release to check
+     *             the permission {@code java.security.AllPermission}.
      * @see        #checkPermission(java.security.Permission) checkPermission
      */
+    @Deprecated
     public void checkAwtEventQueueAccess() {
         Permission perm = SecurityConstants.AWT.CHECK_AWT_EVENTQUEUE_PERMISSION;
         if (perm == null) {
--- a/jdk/src/share/classes/java/lang/StrictMath.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/lang/StrictMath.java	Wed Jul 05 19:11:53 2017 +0200
@@ -633,7 +633,7 @@
 
     /**
      * Returns the closest {@code int} to the argument, with ties
-     * rounding up.
+     * rounding to positive infinity.
      *
      * <p>Special cases:
      * <ul><li>If the argument is NaN, the result is 0.
@@ -656,7 +656,7 @@
 
     /**
      * Returns the closest {@code long} to the argument, with ties
-     * rounding up.
+     * rounding to positive infinity.
      *
      * <p>Special cases:
      * <ul><li>If the argument is NaN, the result is 0.
--- a/jdk/src/share/classes/java/lang/String.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/lang/String.java	Wed Jul 05 19:11:53 2017 +0200
@@ -2457,8 +2457,8 @@
      *     String message = String.join(" ", strings);
      *     //message returned is: "Java is cool"
      *
-     *     Set<String> strings = new HashSet<>();
-     *     Strings.add("Java"); strings.add("is");
+     *     Set<String> strings = new LinkedHashSet<>();
+     *     strings.add("Java"); strings.add("is");
      *     strings.add("very"); strings.add("cool");
      *     String message = String.join("-", strings);
      *     //message returned is: "Java-is-very-cool"
@@ -2652,7 +2652,7 @@
      * returns {@code "t\u005Cu0131tle"}, where '\u005Cu0131' is the
      * LATIN SMALL LETTER DOTLESS I character.
      * To obtain correct results for locale insensitive strings, use
-     * {@code toLowerCase(Locale.ENGLISH)}.
+     * {@code toLowerCase(Locale.ROOT)}.
      * <p>
      * @return  the {@code String}, converted to lowercase.
      * @see     java.lang.String#toLowerCase(Locale)
@@ -2815,7 +2815,7 @@
      * returns {@code "T\u005Cu0130TLE"}, where '\u005Cu0130' is the
      * LATIN CAPITAL LETTER I WITH DOT ABOVE character.
      * To obtain correct results for locale insensitive strings, use
-     * {@code toUpperCase(Locale.ENGLISH)}.
+     * {@code toUpperCase(Locale.ROOT)}.
      * <p>
      * @return  the {@code String}, converted to uppercase.
      * @see     java.lang.String#toUpperCase(Locale)
--- a/jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java	Wed Jul 05 19:11:53 2017 +0200
@@ -124,7 +124,7 @@
         this.samMethodType  = samMethodType;
 
         this.implMethod = implMethod;
-        this.implInfo = new MethodHandleInfo(implMethod);
+        this.implInfo = caller.revealDirect(implMethod);
         // @@@ Temporary work-around pending resolution of 8005119
         this.implKind = (implInfo.getReferenceKind() == MethodHandleInfo.REF_invokeSpecial)
                         ? MethodHandleInfo.REF_invokeVirtual
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/lang/invoke/InfoFromMemberName.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+import java.security.*;
+import java.lang.reflect.*;
+import java.lang.invoke.MethodHandleNatives.Constants;
+import java.lang.invoke.MethodHandles.Lookup;
+import static java.lang.invoke.MethodHandleStatics.*;
+
+/*
+ * Auxiliary to MethodHandleInfo, wants to nest in MethodHandleInfo but must be non-public.
+ */
+/*non-public*/
+final
+class InfoFromMemberName implements MethodHandleInfo {
+    private final MemberName member;
+    private final int referenceKind;
+
+    InfoFromMemberName(Lookup lookup, MemberName member, byte referenceKind) {
+        assert(member.isResolved() || member.isMethodHandleInvoke());
+        assert(member.referenceKindIsConsistentWith(referenceKind));
+        this.member = member;
+        this.referenceKind = referenceKind;
+    }
+
+    @Override
+    public Class<?> getDeclaringClass() {
+        return member.getDeclaringClass();
+    }
+
+    @Override
+    public String getName() {
+        return member.getName();
+    }
+
+    @Override
+    public MethodType getMethodType() {
+        return member.getMethodOrFieldType();
+    }
+
+    @Override
+    public int getModifiers() {
+        return member.getModifiers();
+    }
+
+    @Override
+    public int getReferenceKind() {
+        return referenceKind;
+    }
+
+    @Override
+    public String toString() {
+        return MethodHandleInfo.toString(getReferenceKind(), getDeclaringClass(), getName(), getMethodType());
+    }
+
+    @Override
+    public <T extends Member> T reflectAs(Class<T> expected, Lookup lookup) {
+        if (member.isMethodHandleInvoke() && !member.isVarargs()) {
+            // This member is an instance of a signature-polymorphic method, which cannot be reflected
+            // A method handle invoker can come in either of two forms:
+            // A generic placeholder (present in the source code, and varargs)
+            // and a signature-polymorphic instance (synthetic and not varargs).
+            // For more information see comments on {@link MethodHandleNatives#linkMethod}.
+            throw new IllegalArgumentException("cannot reflect signature polymorphic method");
+        }
+        Member mem = AccessController.doPrivileged(new PrivilegedAction<Member>() {
+                public Member run() {
+                    try {
+                        return reflectUnchecked();
+                    } catch (ReflectiveOperationException ex) {
+                        throw new IllegalArgumentException(ex);
+                    }
+                }
+            });
+        try {
+            Class<?> defc = getDeclaringClass();
+            byte refKind = (byte) getReferenceKind();
+            lookup.checkAccess(refKind, defc, convertToMemberName(refKind, mem));
+        } catch (IllegalAccessException ex) {
+            throw new IllegalArgumentException(ex);
+        }
+        return expected.cast(mem);
+    }
+
+    private Member reflectUnchecked() throws ReflectiveOperationException {
+        byte refKind = (byte) getReferenceKind();
+        Class<?> defc = getDeclaringClass();
+        boolean isPublic = Modifier.isPublic(getModifiers());
+        if (MethodHandleNatives.refKindIsMethod(refKind)) {
+            if (isPublic)
+                return defc.getMethod(getName(), getMethodType().parameterArray());
+            else
+                return defc.getDeclaredMethod(getName(), getMethodType().parameterArray());
+        } else if (MethodHandleNatives.refKindIsConstructor(refKind)) {
+            if (isPublic)
+                return defc.getConstructor(getMethodType().parameterArray());
+            else
+                return defc.getDeclaredConstructor(getMethodType().parameterArray());
+        } else if (MethodHandleNatives.refKindIsField(refKind)) {
+            if (isPublic)
+                return defc.getField(getName());
+            else
+                return defc.getDeclaredField(getName());
+        } else {
+            throw new IllegalArgumentException("referenceKind="+refKind);
+        }
+    }
+
+    private static MemberName convertToMemberName(byte refKind, Member mem) throws IllegalAccessException {
+        if (mem instanceof Method) {
+            boolean wantSpecial = (refKind == REF_invokeSpecial);
+            return new MemberName((Method) mem, wantSpecial);
+        } else if (mem instanceof Constructor) {
+            return new MemberName((Constructor) mem);
+        } else if (mem instanceof Field) {
+            boolean isSetter = (refKind == REF_putField || refKind == REF_putStatic);
+            return new MemberName((Field) mem, isSetter);
+        }
+        throw new InternalError(mem.getClass().getName());
+    }
+}
--- a/jdk/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java	Wed Jul 05 19:11:53 2017 +0200
@@ -612,6 +612,12 @@
             return false;  // inner class of some sort
         if (cls.getClassLoader() != MethodHandle.class.getClassLoader())
             return false;  // not on BCP
+        MethodType mtype = member.getMethodOrFieldType();
+        if (!isStaticallyNameable(mtype.returnType()))
+            return false;
+        for (Class<?> ptype : mtype.parameterArray())
+            if (!isStaticallyNameable(ptype))
+                return false;
         if (!member.isPrivate() && VerifyAccess.isSamePackage(MethodHandle.class, cls))
             return true;   // in java.lang.invoke package
         if (member.isPublic() && isStaticallyNameable(cls))
--- a/jdk/src/share/classes/java/lang/invoke/Invokers.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/Invokers.java	Wed Jul 05 19:11:53 2017 +0200
@@ -87,6 +87,7 @@
             lform = invokeForm(mtype, true, MethodTypeForm.LF_EX_INVOKER);
             invoker = SimpleMethodHandle.make(invokerType, lform);
         }
+        invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke("invokeExact", mtype));
         assert(checkInvoker(invoker));
         exactInvoker = invoker;
         return invoker;
@@ -110,6 +111,7 @@
             lform = invokeForm(mtype, true, MethodTypeForm.LF_GEN_INVOKER);
             invoker = SimpleMethodHandle.make(invokerType, lform);
         }
+        invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke("invoke", mtype));
         assert(checkInvoker(invoker));
         generalInvoker = invoker;
         return invoker;
--- a/jdk/src/share/classes/java/lang/invoke/MemberName.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MemberName.java	Wed Jul 05 19:11:53 2017 +0200
@@ -320,14 +320,18 @@
 
     /** Utility method to query if this member is a method handle invocation (invoke or invokeExact). */
     public boolean isMethodHandleInvoke() {
-        final int bits = Modifier.NATIVE | Modifier.FINAL;
+        final int bits = MH_INVOKE_MODS;
         final int negs = Modifier.STATIC;
         if (testFlags(bits | negs, bits) &&
             clazz == MethodHandle.class) {
-            return name.equals("invoke") || name.equals("invokeExact");
+            return isMethodHandleInvokeName(name);
         }
         return false;
     }
+    public static boolean isMethodHandleInvokeName(String name) {
+        return name.equals("invoke") || name.equals("invokeExact");
+    }
+    private static final int MH_INVOKE_MODS = Modifier.NATIVE | Modifier.FINAL | Modifier.PUBLIC;
 
     /** Utility method to query the modifier flags of this member. */
     public boolean isStatic() {
@@ -482,12 +486,27 @@
         m.getClass();  // NPE check
         // fill in vmtarget, vmindex while we have m in hand:
         MethodHandleNatives.init(this, m);
+        if (clazz == null) {  // MHN.init failed
+            if (m.getDeclaringClass() == MethodHandle.class &&
+                isMethodHandleInvokeName(m.getName())) {
+                // The JVM did not reify this signature-polymorphic instance.
+                // Need a special case here.
+                // See comments on MethodHandleNatives.linkMethod.
+                MethodType type = MethodType.methodType(m.getReturnType(), m.getParameterTypes());
+                int flags = flagsMods(IS_METHOD, m.getModifiers(), REF_invokeVirtual);
+                init(MethodHandle.class, m.getName(), type, flags);
+                if (isMethodHandleInvoke())
+                    return;
+            }
+            throw new LinkageError(m.toString());
+        }
         assert(isResolved() && this.clazz != null);
         this.name = m.getName();
         if (this.type == null)
             this.type = new Object[] { m.getReturnType(), m.getParameterTypes() };
         if (wantSpecial) {
-            assert(!isAbstract()) : this;
+            if (isAbstract())
+                throw new AbstractMethodError(this.toString());
             if (getReferenceKind() == REF_invokeVirtual)
                 changeReferenceKind(REF_invokeSpecial, REF_invokeVirtual);
             else if (getReferenceKind() == REF_invokeInterface)
@@ -562,6 +581,22 @@
         initResolved(true);
     }
 
+    /**
+     * Create a name for a signature-polymorphic invoker.
+     * This is a placeholder for a signature-polymorphic instance
+     * (of MH.invokeExact, etc.) that the JVM does not reify.
+     * See comments on {@link MethodHandleNatives#linkMethod}.
+     */
+    static MemberName makeMethodHandleInvoke(String name, MethodType type) {
+        return makeMethodHandleInvoke(name, type, MH_INVOKE_MODS | SYNTHETIC);
+    }
+    static MemberName makeMethodHandleInvoke(String name, MethodType type, int mods) {
+        MemberName mem = new MemberName(MethodHandle.class, name, type, REF_invokeVirtual);
+        mem.flags |= mods;  // it's not resolved, but add these modifiers anyway
+        assert(mem.isMethodHandleInvoke()) : mem;
+        return mem;
+    }
+
     // bare-bones constructor; the JVM will fill it in
     MemberName() { }
 
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandle.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandle.java	Wed Jul 05 19:11:53 2017 +0200
@@ -1285,6 +1285,21 @@
     }
 
     /*non-public*/
+    MethodHandle withInternalMemberName(MemberName member) {
+        if (member != null) {
+            return MethodHandleImpl.makeWrappedMember(this, member);
+        } else if (internalMemberName() == null) {
+            // The required internaMemberName is null, and this MH (like most) doesn't have one.
+            return this;
+        } else {
+            // The following case is rare. Mask the internalMemberName by wrapping the MH in a BMH.
+            MethodHandle result = rebind();
+            assert (result.internalMemberName() == null);
+            return result;
+        }
+    }
+
+    /*non-public*/
     boolean isInvokeSpecial() {
         return false;  // DMH.Special returns true
     }
@@ -1356,7 +1371,7 @@
     MethodHandle rebind() {
         // Bind 'this' into a new invoker, of the known class BMH.
         MethodType type2 = type();
-        LambdaForm form2 = reinvokerForm(type2.basicType());
+        LambdaForm form2 = reinvokerForm(this);
         // form2 = lambda (bmh, arg*) { thismh = bmh[0]; invokeBasic(thismh, arg*) }
         return BoundMethodHandle.bindSingle(type2, form2, this);
     }
@@ -1369,23 +1384,38 @@
     /** Create a LF which simply reinvokes a target of the given basic type.
      *  The target MH must override {@link #reinvokerTarget} to provide the target.
      */
-    static LambdaForm reinvokerForm(MethodType mtype) {
-        mtype = mtype.basicType();
+    static LambdaForm reinvokerForm(MethodHandle target) {
+        MethodType mtype = target.type().basicType();
         LambdaForm reinvoker = mtype.form().cachedLambdaForm(MethodTypeForm.LF_REINVOKE);
         if (reinvoker != null)  return reinvoker;
-        MethodHandle MH_invokeBasic = MethodHandles.basicInvoker(mtype);
+        if (mtype.parameterSlotCount() >= MethodType.MAX_MH_ARITY)
+            return makeReinvokerForm(target.type(), target);  // cannot cache this
+        reinvoker = makeReinvokerForm(mtype, null);
+        return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_REINVOKE, reinvoker);
+    }
+    private static LambdaForm makeReinvokerForm(MethodType mtype, MethodHandle customTargetOrNull) {
+        boolean customized = (customTargetOrNull != null);
+        MethodHandle MH_invokeBasic = customized ? null : MethodHandles.basicInvoker(mtype);
         final int THIS_BMH    = 0;
         final int ARG_BASE    = 1;
         final int ARG_LIMIT   = ARG_BASE + mtype.parameterCount();
         int nameCursor = ARG_LIMIT;
-        final int NEXT_MH     = nameCursor++;
+        final int NEXT_MH     = customized ? -1 : nameCursor++;
         final int REINVOKE    = nameCursor++;
         LambdaForm.Name[] names = LambdaForm.arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
-        names[NEXT_MH] = new LambdaForm.Name(NF_reinvokerTarget, names[THIS_BMH]);
-        Object[] targetArgs = Arrays.copyOfRange(names, THIS_BMH, ARG_LIMIT, Object[].class);
-        targetArgs[0] = names[NEXT_MH];  // overwrite this MH with next MH
-        names[REINVOKE] = new LambdaForm.Name(MH_invokeBasic, targetArgs);
-        return mtype.form().setCachedLambdaForm(MethodTypeForm.LF_REINVOKE, new LambdaForm("BMH.reinvoke", ARG_LIMIT, names));
+        Object[] targetArgs;
+        MethodHandle targetMH;
+        if (customized) {
+            targetArgs = Arrays.copyOfRange(names, ARG_BASE, ARG_LIMIT, Object[].class);
+            targetMH = customTargetOrNull;
+        } else {
+            names[NEXT_MH] = new LambdaForm.Name(NF_reinvokerTarget, names[THIS_BMH]);
+            targetArgs = Arrays.copyOfRange(names, THIS_BMH, ARG_LIMIT, Object[].class);
+            targetArgs[0] = names[NEXT_MH];  // overwrite this MH with next MH
+            targetMH = MethodHandles.basicInvoker(mtype);
+        }
+        names[REINVOKE] = new LambdaForm.Name(targetMH, targetArgs);
+        return new LambdaForm("BMH.reinvoke", ARG_LIMIT, names);
     }
 
     private static final LambdaForm.NamedFunction NF_reinvokerTarget;
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Wed Jul 05 19:11:53 2017 +0200
@@ -317,7 +317,7 @@
         private MethodHandle cache;
 
         AsVarargsCollector(MethodHandle target, MethodType type, Class<?> arrayType) {
-            super(type, reinvokerForm(type));
+            super(type, reinvokerForm(target));
             this.target = target;
             this.arrayType = arrayType;
             this.cache = target.asCollector(arrayType, 0);
@@ -778,16 +778,27 @@
     }
     static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
 
-    static MethodHandle FAKE_METHOD_HANDLE_INVOKE;
-    static
-    MethodHandle fakeMethodHandleInvoke(MemberName method) {
-        MethodType type = method.getInvocationType();
-        assert(type.equals(MethodType.methodType(Object.class, Object[].class)));
-        MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE;
+    static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2];
+    static MethodHandle fakeMethodHandleInvoke(MemberName method) {
+        int idx;
+        assert(method.isMethodHandleInvoke());
+        switch (method.getName()) {
+        case "invoke":       idx = 0; break;
+        case "invokeExact":  idx = 1; break;
+        default:             throw new InternalError(method.getName());
+        }
+        MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE[idx];
         if (mh != null)  return mh;
-        mh = throwException(type.insertParameterTypes(0, UnsupportedOperationException.class));
+        MethodType type = MethodType.methodType(Object.class, UnsupportedOperationException.class,
+                                                MethodHandle.class, Object[].class);
+        mh = throwException(type);
         mh = mh.bindTo(new UnsupportedOperationException("cannot reflectively invoke MethodHandle"));
-        FAKE_METHOD_HANDLE_INVOKE = mh;
+        if (!method.getInvocationType().equals(mh.type()))
+            throw new InternalError(method.toString());
+        mh = mh.withInternalMemberName(method);
+        mh = mh.asVarargsCollector(Object[].class);
+        assert(method.isVarargs());
+        FAKE_METHOD_HANDLE_INVOKE[idx] = mh;
         return mh;
     }
 
@@ -821,7 +832,7 @@
             MethodHandle vamh = prepareForInvoker(mh);
             // Cache the result of makeInjectedInvoker once per argument class.
             MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass);
-            return restoreToType(bccInvoker.bindTo(vamh), mh.type());
+            return restoreToType(bccInvoker.bindTo(vamh), mh.type(), mh.internalMemberName());
         }
 
         private static MethodHandle makeInjectedInvoker(Class<?> hostClass) {
@@ -876,8 +887,11 @@
         }
 
         // Undo the adapter effect of prepareForInvoker:
-        private static MethodHandle restoreToType(MethodHandle vamh, MethodType type) {
-            return vamh.asCollector(Object[].class, type.parameterCount()).asType(type);
+        private static MethodHandle restoreToType(MethodHandle vamh, MethodType type, MemberName member) {
+            MethodHandle mh = vamh.asCollector(Object[].class, type.parameterCount());
+            mh = mh.asType(type);
+            mh = mh.withInternalMemberName(member);
+            return mh;
         }
 
         private static final MethodHandle MH_checkCallerClass;
@@ -939,4 +953,41 @@
             }
         }
     }
+
+
+    /** This subclass allows a wrapped method handle to be re-associated with an arbitrary member name. */
+    static class WrappedMember extends MethodHandle {
+        private final MethodHandle target;
+        private final MemberName member;
+
+        private WrappedMember(MethodHandle target, MethodType type, MemberName member) {
+            super(type, reinvokerForm(target));
+            this.target = target;
+            this.member = member;
+        }
+
+        @Override
+        MethodHandle reinvokerTarget() {
+            return target;
+        }
+        @Override
+        MemberName internalMemberName() {
+            return member;
+        }
+        @Override
+        boolean isInvokeSpecial() {
+            return target.isInvokeSpecial();
+        }
+        @Override
+        MethodHandle viewAsType(MethodType newType) {
+            return new WrappedMember(target, newType, member);
+        }
+    }
+
+    static MethodHandle makeWrappedMember(MethodHandle target, MemberName member) {
+        if (member.equals(target.internalMemberName()))
+            return target;
+        return new WrappedMember(target, target.type(), member);
+    }
+
 }
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleInfo.java	Wed Jul 05 19:11:53 2017 +0200
@@ -24,80 +24,246 @@
  */
 
 package java.lang.invoke;
+
+import java.lang.reflect.*;
+import java.util.*;
 import java.lang.invoke.MethodHandleNatives.Constants;
+import java.lang.invoke.MethodHandles.Lookup;
+import static java.lang.invoke.MethodHandleStatics.*;
 
 /**
- * Cracking (reflecting) method handles back into their constituent symbolic parts.
+ * A symbolic reference obtained by cracking a method handle into its consitutent symbolic parts.
+ * To crack a direct method handle, call {@link Lookup#revealDirect Lookup.revealDirect}.
+ * <p>
+ * A <em>direct method handle</em> represents a method, constructor, or field without
+ * any intervening argument bindings or other transformations.
+ * The method, constructor, or field referred to by a direct method handle is called
+ * its <em>underlying member</em>.
+ * Direct method handles may be obtained in any of these ways:
+ * <ul>
+ * <li>By executing an {@code ldc} instruction on a {@code CONSTANT_MethodHandle} constant.
+ *     (See the Java Virtual Machine Specification, sections 4.4.8 and 5.4.3.)
+ * <li>By calling one of the <a href="MethodHandles.Lookup.html#lookups">Lookup Factory Methods</a>,
+ *     such as {@link Lookup#findVirtual Lookup.findVirtual},
+ *     to resolve a symbolic reference into a method handle.
+ *     A symbolic reference consists of a class, name string, and type.
+ * <li>By calling the factory method {@link Lookup#unreflect Lookup.unreflect}
+ *     or {@link Lookup#unreflectSpecial Lookup.unreflectSpecial}
+ *     to convert a {@link Method} into a method handle.
+ * <li>By calling the factory method {@link Lookup#unreflectConstructor Lookup.unreflectConstructor}
+ *     to convert a {@link Constructor} into a method handle.
+ * <li>By calling the factory method {@link Lookup#unreflectGetter Lookup.unreflectGetter}
+ *     or {@link Lookup#unreflectSetter Lookup.unreflectSetter}
+ *     to convert a {@link Field} into a method handle.
+ * </ul>
+ * In all of these cases, it is possible to crack the resulting direct method handle
+ * to recover a symbolic reference for the underlying method, constructor, or field.
+ * Cracking must be done via a {@code Lookup} object equivalent to that which created
+ * the target method handle, or which has enough access permissions to recreate
+ * an equivalent method handle.
  *
+ * <h1><a name="refkinds"></a>Reference kinds</h1>
+ * The <a href="MethodHandles.Lookup.html#lookups">Lookup Factory Methods</a>
+ * correspond to all major use cases for methods, constructors, and fields.
+ * These use cases may be distinguished using small integers as follows:
+ * <table border=1 cellpadding=5 summary="reference kinds">
+ * <tr><th>reference kind</th><th>descriptive name</th><th>scope</th><th>member</th><th>behavior</th></tr>
+ * <tr>
+ *     <td>{@code 1}</td><td>{@code REF_getField}</td><td>{@code class}</td>
+ *     <td>{@code FT f;}</td><td>{@code (T) this.f;}</td>
+ * </tr>
+ * <tr>
+ *     <td>{@code 2}</td><td>{@code REF_getStatic}</td><td>{@code class} or {@code interface}</td>
+ *     <td>{@code static}<br>{@code FT f;}</td><td>{@code (T) C.f;}</td>
+ * </tr>
+ * <tr>
+ *     <td>{@code 3}</td><td>{@code REF_putField}</td><td>{@code class}</td>
+ *     <td>{@code FT f;}</td><td>{@code this.f = x;}</td>
+ * </tr>
+ * <tr>
+ *     <td>{@code 4}</td><td>{@code REF_putStatic}</td><td>{@code class}</td>
+ *     <td>{@code static}<br>{@code FT f;}</td><td>{@code C.f = arg;}</td>
+ * </tr>
+ * <tr>
+ *     <td>{@code 5}</td><td>{@code REF_invokeVirtual}</td><td>{@code class}</td>
+ *     <td>{@code T m(A*);}</td><td>{@code (T) this.m(arg*);}</td>
+ * </tr>
+ * <tr>
+ *     <td>{@code 6}</td><td>{@code REF_invokeStatic}</td><td>{@code class} or {@code interface}</td>
+ *     <td>{@code static}<br>{@code T m(A*);}</td><td>{@code (T) C.m(arg*);}</td>
+ * </tr>
+ * <tr>
+ *     <td>{@code 7}</td><td>{@code REF_invokeSpecial}</td><td>{@code class} or {@code interface}</td>
+ *     <td>{@code T m(A*);}</td><td>{@code (T) super.m(arg*);}</td>
+ * </tr>
+ * <tr>
+ *     <td>{@code 8}</td><td>{@code REF_newInvokeSpecial}</td><td>{@code class}</td>
+ *     <td>{@code C(A*);}</td><td>{@code new C(arg*);}</td>
+ * </tr>
+ * <tr>
+ *     <td>{@code 9}</td><td>{@code REF_invokeInterface}</td><td>{@code interface}</td>
+ *     <td>{@code T m(A*);}</td><td>{@code (T) this.m(arg*);}</td>
+ * </tr>
+ * </table>
+ * @since 1.8
  */
-final class MethodHandleInfo {
-   public static final int
-       REF_getField                = Constants.REF_getField,
-       REF_getStatic               = Constants.REF_getStatic,
-       REF_putField                = Constants.REF_putField,
-       REF_putStatic               = Constants.REF_putStatic,
-       REF_invokeVirtual           = Constants.REF_invokeVirtual,
-       REF_invokeStatic            = Constants.REF_invokeStatic,
-       REF_invokeSpecial           = Constants.REF_invokeSpecial,
-       REF_newInvokeSpecial        = Constants.REF_newInvokeSpecial,
-       REF_invokeInterface         = Constants.REF_invokeInterface;
-
-   private final Class<?> declaringClass;
-   private final String name;
-   private final MethodType methodType;
-   private final int referenceKind;
-
-   public MethodHandleInfo(MethodHandle mh) {
-       MemberName mn = mh.internalMemberName();
-       if (mn == null)  throw new IllegalArgumentException("not a direct method handle");
-       this.declaringClass = mn.getDeclaringClass();
-       this.name = mn.getName();
-       this.methodType = mn.getMethodOrFieldType();
-       byte refKind = mn.getReferenceKind();
-       if (refKind == REF_invokeSpecial && !mh.isInvokeSpecial())
-           // Devirtualized method invocation is usually formally virtual.
-           refKind = REF_invokeVirtual;
-       this.referenceKind = refKind;
-   }
+public
+interface MethodHandleInfo {
+    /**
+     * A direct method handle reference kind,
+     * as defined in the <a href="MethodHandleInfo.html#refkinds">table above</a>.
+     */
+    public static final int
+        REF_getField                = Constants.REF_getField,
+        REF_getStatic               = Constants.REF_getStatic,
+        REF_putField                = Constants.REF_putField,
+        REF_putStatic               = Constants.REF_putStatic,
+        REF_invokeVirtual           = Constants.REF_invokeVirtual,
+        REF_invokeStatic            = Constants.REF_invokeStatic,
+        REF_invokeSpecial           = Constants.REF_invokeSpecial,
+        REF_newInvokeSpecial        = Constants.REF_newInvokeSpecial,
+        REF_invokeInterface         = Constants.REF_invokeInterface;
 
-   public Class<?> getDeclaringClass() {
-       return declaringClass;
-   }
+    /**
+     * Returns the reference kind of the cracked method handle, which in turn
+     * determines whether the method handle's underlying member was a constructor, method, or field.
+     * See the <a href="MethodHandleInfo.html#refkinds">table above</a> for definitions.
+     * @return the integer code for the kind of reference used to access the underlying member
+     */
+    public int getReferenceKind();
 
-   public String getName() {
-       return name;
-   }
+    /**
+     * Returns the class in which the cracked method handle's underlying member was defined.
+     * @return the declaring class of the underlying member
+     */
+    public Class<?> getDeclaringClass();
+
+    /**
+     * Returns the name of the cracked method handle's underlying member.
+     * This is {@code "&lt;init&gt;"} if the underlying member was a constructor,
+     * else it is a simple method name or field name.
+     * @return the simple name of the underlying member
+     */
+    public String getName();
 
-   public MethodType getMethodType() {
-       return methodType;
-   }
+    /**
+     * Returns the nominal type of the cracked symbolic reference, expressed as a method type.
+     * If the reference is to a constructor, the return type will be {@code void}.
+     * If it is to a non-static method, the method type will not mention the {@code this} parameter.
+     * If it is to a field and the requested access is to read the field,
+     * the method type will have no parameters and return the field type.
+     * If it is to a field and the requested access is to write the field,
+     * the method type will have one parameter of the field type and return {@code void}.
+     * <p>
+     * Note that original direct method handle may include a leading {@code this} parameter,
+     * or (in the case of a constructor) will replace the {@code void} return type
+     * with the constructed class.
+     * The nominal type does not include any {@code this} parameter,
+     * and (in the case of a constructor) will return {@code void}.
+     * @return the type of the underlying member, expressed as a method type
+     */
+    public MethodType getMethodType();
 
-   public int getModifiers() {
-       return -1; //TODO
-   }
+    // Utility methods.
+    // NOTE: class/name/type and reference kind constitute a symbolic reference
+    // member and modifiers are an add-on, derived from Core Reflection (or the equivalent)
 
-   public int getReferenceKind() {
-       return referenceKind;
-   }
+    /**
+     * Reflects the underlying member as a method, constructor, or field object.
+     * If the underlying member is public, it is reflected as if by
+     * {@code getMethod}, {@code getConstructor}, or {@code getField}.
+     * Otherwise, it is reflected as if by
+     * {@code getDeclaredMethod}, {@code getDeclaredConstructor}, or {@code getDeclaredField}.
+     * The underlying member must be accessible to the given lookup object.
+     * @param <T> the desired type of the result, either {@link Member} or a subtype
+     * @param expected a class object representing the desired result type {@code T}
+     * @param lookup the lookup object that created this MethodHandleInfo, or one with equivalent access privileges
+     * @return a reference to the method, constructor, or field object
+     * @exception ClassCastException if the member is not of the expected type
+     * @exception NullPointerException if either argument is {@code null}
+     * @exception IllegalArgumentException if the underlying member is not accessible to the given lookup object
+     */
+    public <T extends Member> T reflectAs(Class<T> expected, Lookup lookup);
 
-   static String getReferenceKindString(int referenceKind) {
-        switch (referenceKind) {
-            case REF_getField: return "getfield";
-            case REF_getStatic: return "getstatic";
-            case REF_putField: return "putfield";
-            case REF_putStatic: return "putstatic";
-            case REF_invokeVirtual: return "invokevirtual";
-            case REF_invokeStatic: return "invokestatic";
-            case REF_invokeSpecial: return "invokespecial";
-            case REF_newInvokeSpecial: return "newinvokespecial";
-            case REF_invokeInterface: return "invokeinterface";
-            default: return "UNKNOWN_REFENCE_KIND" + "[" + referenceKind + "]";
-        }
+    /**
+     * Returns the access modifiers of the underlying member.
+     * @return the Java language modifiers for underlying member,
+     *         or -1 if the member cannot be accessed
+     * @see Modifier
+     * @see reflectAs
+     */
+    public int getModifiers();
+
+    /**
+     * Determines if the underlying member was a variable arity method or constructor.
+     * Such members are represented by method handles that are varargs collectors.
+     * @implSpec
+     * This produces a result equivalent to:
+     * <pre>{@code
+     *     getReferenceKind() >= REF_invokeVirtual && Modifier.isTransient(getModifiers())
+     * }</pre>
+     *
+     *
+     * @return {@code true} if and only if the underlying member was declared with variable arity.
+     */
+    // spelling derived from java.lang.reflect.Executable, not MethodHandle.isVarargsCollector
+    public default boolean isVarArgs()  {
+        // fields are never varargs:
+        if (MethodHandleNatives.refKindIsField((byte) getReferenceKind()))
+            return false;
+        // not in the public API: Modifier.VARARGS
+        final int ACC_VARARGS = 0x00000080;  // from JVMS 4.6 (Table 4.20)
+        assert(ACC_VARARGS == Modifier.TRANSIENT);
+        return Modifier.isTransient(getModifiers());
     }
 
-    @Override
-    public String toString() {
-        return String.format("%s %s.%s:%s", getReferenceKindString(referenceKind),
-                             declaringClass.getName(), name, methodType);
+    /**
+     * Returns the descriptive name of the given reference kind,
+     * as defined in the <a href="MethodHandleInfo.html#refkinds">table above</a>.
+     * The conventional prefix "REF_" is omitted.
+     * @param referenceKind an integer code for a kind of reference used to access a class member
+     * @return a mixed-case string such as {@code "getField"}
+     * @exception IllegalArgumentException if the argument is not a valid
+     *            <a href="MethodHandleInfo.html#refkinds">reference kind number</a>
+     */
+    public static String referenceKindToString(int referenceKind) {
+        if (!MethodHandleNatives.refKindIsValid(referenceKind))
+            throw newIllegalArgumentException("invalid reference kind", referenceKind);
+        return MethodHandleNatives.refKindName((byte)referenceKind);
+    }
+
+    /**
+     * Returns a string representation for a {@code MethodHandleInfo},
+     * given the four parts of its symbolic reference.
+     * This is defined to be of the form {@code "RK C.N:MT"}, where {@code RK} is the
+     * {@linkplain #referenceKindToString reference kind string} for {@code kind},
+     * {@code C} is the {@linkplain java.lang.Class#getName name} of {@code defc}
+     * {@code N} is the {@code name}, and
+     * {@code MT} is the {@code type}.
+     * These four values may be obtained from the
+     * {@linkplain #getReferenceKind reference kind},
+     * {@linkplain #getDeclaringClass declaring class},
+     * {@linkplain #getName member name},
+     * and {@linkplain #getMethodType method type}
+     * of a {@code MethodHandleInfo} object.
+     *
+     * @implSpec
+     * This produces a result equivalent to:
+     * <pre>{@code
+     *     String.format("%s %s.%s:%s", referenceKindToString(kind), defc.getName(), name, type)
+     * }</pre>
+     *
+     * @param kind the {@linkplain #getReferenceKind reference kind} part of the symbolic reference
+     * @param defc the {@linkplain #getDeclaringClass declaring class} part of the symbolic reference
+     * @param name the {@linkplain #getName member name} part of the symbolic reference
+     * @param type the {@linkplain #getMethodType method type} part of the symbolic reference
+     * @return a string of the form {@code "RK C.N:MT"}
+     * @exception IllegalArgumentException if the first argument is not a valid
+     *            <a href="MethodHandleInfo.html#refkinds">reference kind number</a>
+     * @exception NullPointerException if any reference argument is {@code null}
+     */
+    public static String toString(int kind, Class<?> defc, String name, MethodType type) {
+        Objects.requireNonNull(name); Objects.requireNonNull(type);
+        return String.format("%s %s.%s:%s", referenceKindToString(kind), defc.getName(), name, type);
     }
 }
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java	Wed Jul 05 19:11:53 2017 +0200
@@ -205,6 +205,9 @@
     static boolean refKindIsMethod(byte refKind) {
         return !refKindIsField(refKind) && (refKind != REF_newInvokeSpecial);
     }
+    static boolean refKindIsConstructor(byte refKind) {
+        return (refKind == REF_newInvokeSpecial);
+    }
     static boolean refKindHasReceiver(byte refKind) {
         assert(refKindIsValid(refKind));
         return (refKind & 1) != 0;
@@ -313,7 +316,65 @@
      * The method assumes the following arguments on the stack:
      * 0: the method handle being invoked
      * 1-N: the arguments to the method handle invocation
-     * N+1: an implicitly added type argument (the given MethodType)
+     * N+1: an optional, implicitly added argument (typically the given MethodType)
+     * <p>
+     * The nominal method at such a call site is an instance of
+     * a signature-polymorphic method (see @PolymorphicSignature).
+     * Such method instances are user-visible entities which are
+     * "split" from the generic placeholder method in {@code MethodHandle}.
+     * (Note that the placeholder method is not identical with any of
+     * its instances.  If invoked reflectively, is guaranteed to throw an
+     * {@code UnsupportedOperationException}.)
+     * If the signature-polymorphic method instance is ever reified,
+     * it appears as a "copy" of the original placeholder
+     * (a native final member of {@code MethodHandle}) except
+     * that its type descriptor has shape required by the instance,
+     * and the method instance is <em>not</em> varargs.
+     * The method instance is also marked synthetic, since the
+     * method (by definition) does not appear in Java source code.
+     * <p>
+     * The JVM is allowed to reify this method as instance metadata.
+     * For example, {@code invokeBasic} is always reified.
+     * But the JVM may instead call {@code linkMethod}.
+     * If the result is an * ordered pair of a {@code (method, appendix)},
+     * the method gets all the arguments (0..N inclusive)
+     * plus the appendix (N+1), and uses the appendix to complete the call.
+     * In this way, one reusable method (called a "linker method")
+     * can perform the function of any number of polymorphic instance
+     * methods.
+     * <p>
+     * Linker methods are allowed to be weakly typed, with any or
+     * all references rewritten to {@code Object} and any primitives
+     * (except {@code long}/{@code float}/{@code double})
+     * rewritten to {@code int}.
+     * A linker method is trusted to return a strongly typed result,
+     * according to the specific method type descriptor of the
+     * signature-polymorphic instance it is emulating.
+     * This can involve (as necessary) a dynamic check using
+     * data extracted from the appendix argument.
+     * <p>
+     * The JVM does not inspect the appendix, other than to pass
+     * it verbatim to the linker method at every call.
+     * This means that the JDK runtime has wide latitude
+     * for choosing the shape of each linker method and its
+     * corresponding appendix.
+     * Linker methods should be generated from {@code LambdaForm}s
+     * so that they do not become visible on stack traces.
+     * <p>
+     * The {@code linkMethod} call is free to omit the appendix
+     * (returning null) and instead emulate the required function
+     * completely in the linker method.
+     * As a corner case, if N==255, no appendix is possible.
+     * In this case, the method returned must be custom-generated to
+     * to perform any needed type checking.
+     * <p>
+     * If the JVM does not reify a method at a call site, but instead
+     * calls {@code linkMethod}, the corresponding call represented
+     * in the bytecodes may mention a valid method which is not
+     * representable with a {@code MemberName}.
+     * Therefore, use cases for {@code linkMethod} tend to correspond to
+     * special cases in reflective code such as {@code findVirtual}
+     * or {@code revealDirect}.
      */
     static MemberName linkMethod(Class<?> callerClass, int refKind,
                                  Class<?> defc, String name, Object type,
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java	Wed Jul 05 19:11:53 2017 +0200
@@ -26,8 +26,6 @@
 package java.lang.invoke;
 
 import java.lang.reflect.*;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
 import java.util.List;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -54,6 +52,7 @@
  * </ul>
  * <p>
  * @author John Rose, JSR 292 EG
+ * @since 1.7
  */
 public class MethodHandles {
 
@@ -97,6 +96,38 @@
     }
 
     /**
+     * Performs an unchecked "crack" of a direct method handle.
+     * The result is as if the user had obtained a lookup object capable enough
+     * to crack the target method handle, called
+     * {@link java.lang.invoke.MethodHandles.Lookup#revealDirect Lookup.revealDirect}
+     * on the target to obtain its symbolic reference, and then called
+     * {@link java.lang.invoke.MethodHandleInfo#reflectAs MethodHandleInfo.reflectAs}
+     * to resolve the symbolic reference to a member.
+     * <p>
+     * If there is a security manager, its {@code checkPermission} method
+     * is called with a {@code ReflectPermission("suppressAccessChecks")} permission.
+     * @param <T> the desired type of the result, either {@link Member} or a subtype
+     * @param target a direct method handle to crack into symbolic reference components
+     * @param expected a class object representing the desired result type {@code T}
+     * @return a reference to the method, constructor, or field object
+     * @exception SecurityException if the caller is not privileged to call {@code setAccessible}
+     * @exception NullPointerException if either argument is {@code null}
+     * @exception IllegalArgumentException if the target is not a direct method handle
+     * @exception ClassCastException if the member is not of the expected type
+     * @since 1.8
+     */
+    public static <T extends Member> T
+    reflectAs(Class<T> expected, MethodHandle target) {
+        SecurityManager smgr = System.getSecurityManager();
+        if (smgr != null)  smgr.checkPermission(ACCESS_PERMISSION);
+        Lookup lookup = Lookup.IMPL_LOOKUP;  // use maximally privileged lookup
+        return lookup.revealDirect(target).reflectAs(expected, lookup);
+    }
+    // Copied from AccessibleObject, as used by Method.setAccessible, etc.:
+    static final private java.security.Permission ACCESS_PERMISSION =
+        new ReflectPermission("suppressAccessChecks");
+
+    /**
      * A <em>lookup object</em> is a factory for creating method handles,
      * when the creation requires access checking.
      * Method handles do not perform
@@ -647,6 +678,7 @@
                 return invoker(type);
             if ("invokeExact".equals(name))
                 return exactInvoker(type);
+            assert(!MemberName.isMethodHandleInvokeName(name));
             return null;
         }
 
@@ -892,6 +924,10 @@
          * @throws NullPointerException if the argument is null
          */
         public MethodHandle unreflect(Method m) throws IllegalAccessException {
+            if (m.getDeclaringClass() == MethodHandle.class) {
+                MethodHandle mh = unreflectForMH(m);
+                if (mh != null)  return mh;
+            }
             MemberName method = new MemberName(m);
             byte refKind = method.getReferenceKind();
             if (refKind == REF_invokeSpecial)
@@ -900,6 +936,12 @@
             Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
             return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method));
         }
+        private MethodHandle unreflectForMH(Method m) {
+            // these names require special lookups because they throw UnsupportedOperationException
+            if (MemberName.isMethodHandleInvokeName(m.getName()))
+                return MethodHandleImpl.fakeMethodHandleInvoke(new MemberName(m));
+            return null;
+        }
 
         /**
          * Produces a method handle for a reflected method.
@@ -1004,6 +1046,46 @@
             return unreflectField(f, true);
         }
 
+        /**
+         * Cracks a direct method handle created by this lookup object or a similar one.
+         * Security and access checks are performed to ensure that this lookup object
+         * is capable of reproducing the target method handle.
+         * This means that the cracking may fail if target is a direct method handle
+         * but was created by an unrelated lookup object.
+         * @param target a direct method handle to crack into symbolic reference components
+         * @return a symbolic reference which can be used to reconstruct this method handle from this lookup object
+         * @exception SecurityException if a security manager is present and it
+         *                              <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
+         * @throws IllegalArgumentException if the target is not a direct method handle or if access checking fails
+         * @exception NullPointerException if the target is {@code null}
+         * @since 1.8
+         */
+        public MethodHandleInfo revealDirect(MethodHandle target) {
+            MemberName member = target.internalMemberName();
+            if (member == null || (!member.isResolved() && !member.isMethodHandleInvoke()))
+                throw newIllegalArgumentException("not a direct method handle");
+            Class<?> defc = member.getDeclaringClass();
+            byte refKind = member.getReferenceKind();
+            assert(MethodHandleNatives.refKindIsValid(refKind));
+            if (refKind == REF_invokeSpecial && !target.isInvokeSpecial())
+                // Devirtualized method invocation is usually formally virtual.
+                // To avoid creating extra MemberName objects for this common case,
+                // we encode this extra degree of freedom using MH.isInvokeSpecial.
+                refKind = REF_invokeVirtual;
+            if (refKind == REF_invokeVirtual && defc.isInterface())
+                // Symbolic reference is through interface but resolves to Object method (toString, etc.)
+                refKind = REF_invokeInterface;
+            // Check SM permissions and member access before cracking.
+            try {
+                checkSecurityManager(defc, member);
+                checkAccess(refKind, defc, member);
+            } catch (IllegalAccessException ex) {
+                throw new IllegalArgumentException(ex);
+            }
+            // Produce the handle to the results.
+            return new InfoFromMemberName(this, member, refKind);
+        }
+
         /// Helper methods, all package-private.
 
         MemberName resolveOrFail(byte refKind, Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
@@ -1201,12 +1283,12 @@
         private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method,
                                                    boolean doRestrict, Class<?> callerClass) throws IllegalAccessException {
             checkMethod(refKind, refc, method);
-            if (method.isMethodHandleInvoke())
-                return fakeMethodHandleInvoke(method);
+            assert(!method.isMethodHandleInvoke());
 
             Class<?> refcAsSuper;
             if (refKind == REF_invokeSpecial &&
                 refc != lookupClass() &&
+                !refc.isInterface() &&
                 refc != (refcAsSuper = lookupClass().getSuperclass()) &&
                 refc.isAssignableFrom(lookupClass())) {
                 assert(!method.getName().equals("<init>"));  // not this code path
@@ -1234,9 +1316,6 @@
                 mh = restrictReceiver(method, mh, lookupClass());
             return mh;
         }
-        private MethodHandle fakeMethodHandleInvoke(MemberName method) {
-            return throwException(method.getReturnType(), UnsupportedOperationException.class);
-        }
         private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh,
                                              Class<?> callerClass)
                                              throws IllegalAccessException {
--- a/jdk/src/share/classes/java/lang/invoke/SerializedLambda.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/SerializedLambda.java	Wed Jul 05 19:11:53 2017 +0200
@@ -225,7 +225,7 @@
 
     @Override
     public String toString() {
-        String implKind=MethodHandleInfo.getReferenceKindString(implMethodKind);
+        String implKind=MethodHandleInfo.referenceKindToString(implMethodKind);
         return String.format("SerializedLambda[%s=%s, %s=%s.%s:%s, " +
                              "%s=%s %s.%s:%s, %s=%s, %s=%d]",
                              "capturingClass", capturingClass,
--- a/jdk/src/share/classes/java/lang/reflect/Executable.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/lang/reflect/Executable.java	Wed Jul 05 19:11:53 2017 +0200
@@ -428,20 +428,32 @@
     }
 
     /**
-     * Returns an array of arrays that represent the annotations on
-     * the formal parameters, in declaration order, of the executable
-     * represented by this object. (Returns an array of length zero if
-     * the underlying executable is parameterless.  If the executable has
-     * one or more parameters, a nested array of length zero is
-     * returned for each parameter with no annotations.) The
-     * annotation objects contained in the returned arrays are
-     * serializable.  The caller of this method is free to modify the
-     * returned arrays; it will have no effect on the arrays returned
-     * to other callers.
+     * Returns an array of arrays of {@code Annotation}s that
+     * represent the annotations on the formal parameters, in
+     * declaration order, of the {@code Executable} represented by
+     * this object.  Synthetic and mandated parameters (see
+     * explanation below), such as the outer "this" parameter to an
+     * inner class constructor will be represented in the returned
+     * array.  If the executable has no parameters (meaning no formal,
+     * no synthetic, and no mandated parameters), a zero-length array
+     * will be returned.  If the {@code Executable} has one or more
+     * parameters, a nested array of length zero is returned for each
+     * parameter with no annotations. The annotation objects contained
+     * in the returned arrays are serializable.  The caller of this
+     * method is free to modify the returned arrays; it will have no
+     * effect on the arrays returned to other callers.
      *
-     * @return an array of arrays that represent the annotations on the formal
-     *    parameters, in declaration order, of the executable represented by this
-     *    object
+     * A compiler may add extra parameters that are implicitly
+     * declared in source ("mandated"), as well as parameters that
+     * are neither implicitly nor explicitly declared in source
+     * ("synthetic") to the parameter list for a method.  See {@link
+     * java.lang.reflect.Parameter} for more information.
+     *
+     * @see java.lang.reflect.Parameter
+     * @see java.lang.reflect.Parameter#getAnnotations
+     * @return an array of arrays that represent the annotations on
+     *    the formal and implicit parameters, in declaration order, of
+     *    the executable represented by this object
      */
     public abstract Annotation[][] getParameterAnnotations();
 
--- a/jdk/src/share/classes/java/net/AbstractPlainSocketImpl.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/net/AbstractPlainSocketImpl.java	Wed Jul 05 19:11:53 2017 +0200
@@ -719,7 +719,3 @@
     public final static int SHUT_RD = 0;
     public final static int SHUT_WR = 1;
 }
-
-class InetAddressContainer {
-    InetAddress addr;
-}
--- a/jdk/src/share/classes/java/net/IDN.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/net/IDN.java	Wed Jul 05 19:11:53 2017 +0200
@@ -292,13 +292,17 @@
         if (useSTD3ASCIIRules) {
             for (int i = 0; i < dest.length(); i++) {
                 int c = dest.charAt(i);
-                if (!isLDHChar(c)) {
-                    throw new IllegalArgumentException("Contains non-LDH characters");
+                if (isNonLDHAsciiCodePoint(c)) {
+                    throw new IllegalArgumentException(
+                        "Contains non-LDH ASCII characters");
                 }
             }
 
-            if (dest.charAt(0) == '-' || dest.charAt(dest.length() - 1) == '-') {
-                throw new IllegalArgumentException("Has leading or trailing hyphen");
+            if (dest.charAt(0) == '-' ||
+                dest.charAt(dest.length() - 1) == '-') {
+
+                throw new IllegalArgumentException(
+                        "Has leading or trailing hyphen");
             }
         }
 
@@ -401,26 +405,20 @@
     //
     // LDH stands for "letter/digit/hyphen", with characters restricted to the
     // 26-letter Latin alphabet <A-Z a-z>, the digits <0-9>, and the hyphen
-    // <->
-    // non-LDH = 0..0x2C, 0x2E..0x2F, 0x3A..0x40, 0x56..0x60, 0x7B..0x7F
+    // <->.
+    // Non LDH refers to characters in the ASCII range, but which are not
+    // letters, digits or the hypen.
+    //
+    // non-LDH = 0..0x2C, 0x2E..0x2F, 0x3A..0x40, 0x5B..0x60, 0x7B..0x7F
     //
-    private static boolean isLDHChar(int ch){
-        // high runner case
-        if(ch > 0x007A){
-            return false;
-        }
-        //['-' '0'..'9' 'A'..'Z' 'a'..'z']
-        if((ch == 0x002D) ||
-           (0x0030 <= ch && ch <= 0x0039) ||
-           (0x0041 <= ch && ch <= 0x005A) ||
-           (0x0061 <= ch && ch <= 0x007A)
-          ){
-            return true;
-        }
-        return false;
+    private static boolean isNonLDHAsciiCodePoint(int ch){
+        return (0x0000 <= ch && ch <= 0x002C) ||
+               (0x002E <= ch && ch <= 0x002F) ||
+               (0x003A <= ch && ch <= 0x0040) ||
+               (0x005B <= ch && ch <= 0x0060) ||
+               (0x007B <= ch && ch <= 0x007F);
     }
 
-
     //
     // search dots in a string and return the index of that character;
     // or if there is no dots, return the length of input string
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/net/InetAddressContainer.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net;
+
+class InetAddressContainer {
+    InetAddress addr;
+}
--- a/jdk/src/share/classes/java/nio/file/Files.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/nio/file/Files.java	Wed Jul 05 19:11:53 2017 +0200
@@ -25,34 +25,56 @@
 
 package java.nio.file;
 
-import java.nio.file.attribute.*;
-import java.nio.file.spi.FileSystemProvider;
-import java.nio.file.spi.FileTypeDetector;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.UncheckedIOException;
+import java.io.Writer;
 import java.nio.channels.Channels;
 import java.nio.channels.FileChannel;
 import java.nio.channels.SeekableByteChannel;
-import java.io.Closeable;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.Reader;
-import java.io.Writer;
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.util.*;
-import java.util.function.BiPredicate;
-import java.util.stream.CloseableStream;
-import java.util.stream.DelegatingStream;
-import java.util.stream.Stream;
-import java.util.stream.StreamSupport;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
 import java.nio.charset.Charset;
 import java.nio.charset.CharsetDecoder;
 import java.nio.charset.CharsetEncoder;
+import java.nio.file.attribute.BasicFileAttributeView;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.DosFileAttributes;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.attribute.FileAttributeView;
+import java.nio.file.attribute.FileOwnerAttributeView;
+import java.nio.file.attribute.FileStoreAttributeView;
+import java.nio.file.attribute.FileTime;
+import java.nio.file.attribute.PosixFileAttributeView;
+import java.nio.file.attribute.PosixFileAttributes;
+import java.nio.file.attribute.PosixFilePermission;
+import java.nio.file.attribute.UserPrincipal;
+import java.nio.file.spi.FileSystemProvider;
+import java.nio.file.spi.FileTypeDetector;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.ServiceLoader;
+import java.util.Set;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.BiPredicate;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
 
 /**
  * This class consists exclusively of static methods that operate on files,
@@ -74,6 +96,21 @@
         return path.getFileSystem().provider();
     }
 
+    /**
+     * Convert a Closeable to a Runnable by converting checked IOException
+     * to UncheckedIOException
+     */
+    private static Runnable asUncheckedRunnable(Closeable c) {
+        return () -> {
+            try {
+                c.close();
+            }
+            catch (IOException e) {
+                throw new UncheckedIOException(e);
+            }
+        };
+    }
+
     // -- File contents --
 
     /**
@@ -3228,29 +3265,7 @@
     // -- Stream APIs --
 
     /**
-     * Implementation of CloseableStream
-     */
-    private static class DelegatingCloseableStream<T> extends DelegatingStream<T>
-        implements CloseableStream<T>
-    {
-        private final Closeable closeable;
-
-        DelegatingCloseableStream(Closeable c, Stream<T> delegate) {
-            super(delegate);
-            this.closeable = c;
-        }
-
-        public void close() {
-            try {
-                closeable.close();
-            } catch (IOException ex) {
-                throw new UncheckedIOException(ex);
-            }
-        }
-    }
-
-    /**
-     * Return a lazily populated {@code CloseableStream}, the elements of
+     * Return a lazily populated {@code Stream}, the elements of
      * which are the entries in the directory.  The listing is not recursive.
      *
      * <p> The elements of the stream are {@link Path} objects that are
@@ -3264,10 +3279,13 @@
      * reflect updates to the directory that occur after returning from this
      * method.
      *
-     * <p> When not using the try-with-resources construct, then the stream's
-     * {@link CloseableStream#close close} method should be invoked after the
-     * operation is completed so as to free any resources held for the open
-     * directory. Operating on a closed stream behaves as if the end of stream
+     * <p> The returned stream encapsulates a {@link DirectoryStream}.
+     * If timely disposal of file system resources is required, the
+     * {@code try}-with-resources construct should be used to ensure that the
+     * stream's {@link Stream#close close} method is invoked after the stream
+     * operations are completed.
+     *
+     * <p> Operating on a closed stream behaves as if the end of stream
      * has been reached. Due to read-ahead, one or more elements may be
      * returned after the stream has been closed.
      *
@@ -3278,7 +3296,7 @@
      *
      * @param   dir  The path to the directory
      *
-     * @return  The {@code CloseableStream} describing the content of the
+     * @return  The {@code Stream} describing the content of the
      *          directory
      *
      * @throws  NotDirectoryException
@@ -3294,43 +3312,54 @@
      * @see     #newDirectoryStream(Path)
      * @since   1.8
      */
-    public static CloseableStream<Path> list(Path dir) throws IOException {
+    public static Stream<Path> list(Path dir) throws IOException {
         DirectoryStream<Path> ds = Files.newDirectoryStream(dir);
-        final Iterator<Path> delegate = ds.iterator();
+        try {
+            final Iterator<Path> delegate = ds.iterator();
 
-        // Re-wrap DirectoryIteratorException to UncheckedIOException
-        Iterator<Path> it = new Iterator<Path>() {
-            public boolean hasNext() {
+            // Re-wrap DirectoryIteratorException to UncheckedIOException
+            Iterator<Path> it = new Iterator<Path>() {
+                @Override
+                public boolean hasNext() {
+                    try {
+                        return delegate.hasNext();
+                    } catch (DirectoryIteratorException e) {
+                        throw new UncheckedIOException(e.getCause());
+                    }
+                }
+                @Override
+                public Path next() {
+                    try {
+                        return delegate.next();
+                    } catch (DirectoryIteratorException e) {
+                        throw new UncheckedIOException(e.getCause());
+                    }
+                }
+            };
+
+            return StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, Spliterator.DISTINCT), false)
+                                .onClose(asUncheckedRunnable(ds));
+        } catch (Error|RuntimeException e) {
+            try {
+                ds.close();
+            } catch (IOException ex) {
                 try {
-                    return delegate.hasNext();
-                } catch (DirectoryIteratorException e) {
-                    throw new UncheckedIOException(e.getCause());
-                }
+                    e.addSuppressed(ex);
+                } catch (Throwable ignore) {}
             }
-            public Path next() {
-                try {
-                    return delegate.next();
-                } catch (DirectoryIteratorException e) {
-                    throw new UncheckedIOException(e.getCause());
-                }
-            }
-        };
-
-        Stream<Path> s = StreamSupport.stream(
-                Spliterators.spliteratorUnknownSize(it, Spliterator.DISTINCT),
-                false);
-        return new DelegatingCloseableStream<>(ds, s);
+            throw e;
+        }
     }
 
     /**
-     * Return a {@code CloseableStream} that is lazily populated with {@code
+     * Return a {@code Stream} that is lazily populated with {@code
      * Path} by walking the file tree rooted at a given starting file.  The
      * file tree is traversed <em>depth-first</em>, the elements in the stream
      * are {@link Path} objects that are obtained as if by {@link
      * Path#resolve(Path) resolving} the relative path against {@code start}.
      *
      * <p> The {@code stream} walks the file tree as elements are consumed.
-     * The {@code CloseableStream} returned is guaranteed to have at least one
+     * The {@code Stream} returned is guaranteed to have at least one
      * element, the starting file itself. For each file visited, the stream
      * attempts to read its {@link BasicFileAttributes}. If the file is a
      * directory and can be opened successfully, entries in the directory, and
@@ -3370,10 +3399,11 @@
      * <p> When a security manager is installed and it denies access to a file
      * (or directory), then it is ignored and not included in the stream.
      *
-     * <p> When not using the try-with-resources construct, then the stream's
-     * {@link CloseableStream#close close} method should be invoked after the
-     * operation is completed so as to free any resources held for the open
-     * directory. Operate the stream after it is closed will throw an
+     * <p> The returned stream encapsulates one or more {@link DirectoryStream}s.
+     * If timely disposal of file system resources is required, the
+     * {@code try}-with-resources construct should be used to ensure that the
+     * stream's {@link Stream#close close} method is invoked after the stream
+     * operations are completed.  Operating on a closed stream will result in an
      * {@link java.lang.IllegalStateException}.
      *
      * <p> If an {@link IOException} is thrown when accessing the directory
@@ -3388,7 +3418,7 @@
      * @param   options
      *          options to configure the traversal
      *
-     * @return  the {@link CloseableStream} of {@link Path}
+     * @return  the {@link Stream} of {@link Path}
      *
      * @throws  IllegalArgumentException
      *          if the {@code maxDepth} parameter is negative
@@ -3401,21 +3431,22 @@
      *          if an I/O error is thrown when accessing the starting file.
      * @since   1.8
      */
-    public static CloseableStream<Path> walk(Path start, int maxDepth,
-                                             FileVisitOption... options)
-        throws IOException
-    {
+    public static Stream<Path> walk(Path start, int maxDepth,
+                                    FileVisitOption... options)
+            throws IOException {
         FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options);
-
-        Stream<Path> s = StreamSupport.stream(
-                Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT),
-                false).
-                map(entry -> entry.file());
-        return new DelegatingCloseableStream<>(iterator, s);
+        try {
+            return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT), false)
+                                .onClose(iterator::close)
+                                .map(entry -> entry.file());
+        } catch (Error|RuntimeException e) {
+            iterator.close();
+            throw e;
+        }
     }
 
     /**
-     * Return a {@code CloseableStream} that is lazily populated with {@code
+     * Return a {@code Stream} that is lazily populated with {@code
      * Path} by walking the file tree rooted at a given starting file.  The
      * file tree is traversed <em>depth-first</em>, the elements in the stream
      * are {@link Path} objects that are obtained as if by {@link
@@ -3428,12 +3459,19 @@
      * </pre></blockquote>
      * In other words, it visits all levels of the file tree.
      *
+     * <p> The returned stream encapsulates one or more {@link DirectoryStream}s.
+     * If timely disposal of file system resources is required, the
+     * {@code try}-with-resources construct should be used to ensure that the
+     * stream's {@link Stream#close close} method is invoked after the stream
+     * operations are completed.  Operating on a closed stream will result in an
+     * {@link java.lang.IllegalStateException}.
+     *
      * @param   start
      *          the starting file
      * @param   options
      *          options to configure the traversal
      *
-     * @return  the {@link CloseableStream} of {@link Path}
+     * @return  the {@link Stream} of {@link Path}
      *
      * @throws  SecurityException
      *          If the security manager denies access to the starting file.
@@ -3446,15 +3484,14 @@
      * @see     #walk(Path, int, FileVisitOption...)
      * @since   1.8
      */
-    public static CloseableStream<Path> walk(Path start,
-                                             FileVisitOption... options)
-        throws IOException
-    {
+    public static Stream<Path> walk(Path start,
+                                    FileVisitOption... options)
+            throws IOException {
         return walk(start, Integer.MAX_VALUE, options);
     }
 
     /**
-     * Return a {@code CloseableStream} that is lazily populated with {@code
+     * Return a {@code Stream} that is lazily populated with {@code
      * Path} by searching for files in a file tree rooted at a given starting
      * file.
      *
@@ -3463,12 +3500,19 @@
      * {@link BiPredicate} is invoked with its {@link Path} and {@link
      * BasicFileAttributes}. The {@code Path} object is obtained as if by
      * {@link Path#resolve(Path) resolving} the relative path against {@code
-     * start} and is only included in the returned {@link CloseableStream} if
+     * start} and is only included in the returned {@link Stream} if
      * the {@code BiPredicate} returns true. Compare to calling {@link
      * java.util.stream.Stream#filter filter} on the {@code Stream}
      * returned by {@code walk} method, this method may be more efficient by
      * avoiding redundant retrieval of the {@code BasicFileAttributes}.
      *
+     * <p> The returned stream encapsulates one or more {@link DirectoryStream}s.
+     * If timely disposal of file system resources is required, the
+     * {@code try}-with-resources construct should be used to ensure that the
+     * stream's {@link Stream#close close} method is invoked after the stream
+     * operations are completed.  Operating on a closed stream will result in an
+     * {@link java.lang.IllegalStateException}.
+     *
      * <p> If an {@link IOException} is thrown when accessing the directory
      * after returned from this method, it is wrapped in an {@link
      * UncheckedIOException} which will be thrown from the method that caused
@@ -3484,7 +3528,7 @@
      * @param   options
      *          options to configure the traversal
      *
-     * @return  the {@link CloseableStream} of {@link Path}
+     * @return  the {@link Stream} of {@link Path}
      *
      * @throws  IllegalArgumentException
      *          if the {@code maxDepth} parameter is negative
@@ -3499,24 +3543,25 @@
      * @see     #walk(Path, int, FileVisitOption...)
      * @since   1.8
      */
-    public static CloseableStream<Path> find(Path start,
-                                             int maxDepth,
-                                             BiPredicate<Path, BasicFileAttributes> matcher,
-                                             FileVisitOption... options)
-        throws IOException
-    {
+    public static Stream<Path> find(Path start,
+                                    int maxDepth,
+                                    BiPredicate<Path, BasicFileAttributes> matcher,
+                                    FileVisitOption... options)
+            throws IOException {
         FileTreeIterator iterator = new FileTreeIterator(start, maxDepth, options);
-
-        Stream<Path> s = StreamSupport.stream(
-                Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT),
-                false).
-                filter(entry -> matcher.test(entry.file(), entry.attributes())).
-                map(entry -> entry.file());
-        return new DelegatingCloseableStream<>(iterator, s);
+        try {
+            return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.DISTINCT), false)
+                                .onClose(iterator::close)
+                                .filter(entry -> matcher.test(entry.file(), entry.attributes()))
+                                .map(entry -> entry.file());
+        } catch (Error|RuntimeException e) {
+            iterator.close();
+            throw e;
+        }
     }
 
     /**
-     * Read all lines from a file as a {@code CloseableStream}.  Unlike {@link
+     * Read all lines from a file as a {@code Stream}.  Unlike {@link
      * #readAllLines(Path, Charset) readAllLines}, this method does not read
      * all lines into a {@code List}, but instead populates lazily as the stream
      * is consumed.
@@ -3528,22 +3573,24 @@
      * <p> After this method returns, then any subsequent I/O exception that
      * occurs while reading from the file or when a malformed or unmappable byte
      * sequence is read, is wrapped in an {@link UncheckedIOException} that will
-     * be thrown form the
+     * be thrown from the
      * {@link java.util.stream.Stream} method that caused the read to take
      * place. In case an {@code IOException} is thrown when closing the file,
      * it is also wrapped as an {@code UncheckedIOException}.
      *
-     * <p> When not using the try-with-resources construct, then stream's
-     * {@link CloseableStream#close close} method should be invoked after
-     * operation is completed so as to free any resources held for the open
-     * file.
+     * <p> The returned stream encapsulates a {@link Reader}.  If timely
+     * disposal of file system resources is required, the try-with-resources
+     * construct should be used to ensure that the stream's
+     * {@link Stream#close close} method is invoked after the stream operations
+     * are completed.
+     *
      *
      * @param   path
      *          the path to the file
      * @param   cs
      *          the charset to use for decoding
      *
-     * @return  the lines from the file as a {@code CloseableStream}
+     * @return  the lines from the file as a {@code Stream}
      *
      * @throws  IOException
      *          if an I/O error occurs opening the file
@@ -3557,10 +3604,19 @@
      * @see     java.io.BufferedReader#lines()
      * @since   1.8
      */
-    public static CloseableStream<String> lines(Path path, Charset cs)
-        throws IOException
-    {
+    public static Stream<String> lines(Path path, Charset cs) throws IOException {
         BufferedReader br = Files.newBufferedReader(path, cs);
-        return new DelegatingCloseableStream<>(br, br.lines());
+        try {
+            return br.lines().onClose(asUncheckedRunnable(br));
+        } catch (Error|RuntimeException e) {
+            try {
+                br.close();
+            } catch (IOException ex) {
+                try {
+                    e.addSuppressed(ex);
+                } catch (Throwable ignore) {}
+            }
+            throw e;
+        }
     }
 }
--- a/jdk/src/share/classes/java/rmi/activation/Activatable.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/rmi/activation/Activatable.java	Wed Jul 05 19:11:53 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -93,6 +93,8 @@
      * @exception RemoteException if either of the following fails:
      * a) registering the object with the activation system or b) exporting
      * the object to the RMI runtime.
+     * @exception UnsupportedOperationException if and only if activation is
+     * not supported by this implementation.
      * @since 1.2
      **/
     protected Activatable(String location,
@@ -143,6 +145,8 @@
      * @exception RemoteException if either of the following fails:
      * a) registering the object with the activation system or b) exporting
      * the object to the RMI runtime.
+     * @exception UnsupportedOperationException if and only if activation is
+     * not supported by this implementation.
      * @since 1.2
      **/
     protected Activatable(String location,
@@ -175,6 +179,8 @@
      * @param port the port number on which the object is exported
      * @exception RemoteException if exporting the object to the RMI
      * runtime fails
+     * @exception UnsupportedOperationException if and only if activation is
+     * not supported by this implementation
      * @since 1.2
      */
     protected Activatable(ActivationID id, int port)
@@ -206,6 +212,8 @@
      * @param ssf the server-side socket factory for receiving remote calls
      * @exception RemoteException if exporting the object to the RMI
      * runtime fails
+     * @exception UnsupportedOperationException if and only if activation is
+     * not supported by this implementation
      * @since 1.2
      */
     protected Activatable(ActivationID id, int port,
@@ -239,6 +247,8 @@
      * is not registered with the activation system
      * @exception ActivationException if activation system is not running
      * @exception RemoteException if remote call fails
+     * @exception UnsupportedOperationException if and only if activation is
+     * not supported by this implementation
      * @since 1.2
      */
     public static Remote register(ActivationDesc desc)
@@ -273,6 +283,8 @@
      * already be inactive)
      * @exception ActivationException if group is not active
      * @exception RemoteException if call informing monitor fails
+     * @exception UnsupportedOperationException if and only if activation is
+     * not supported by this implementation
      * @since 1.2
      */
     public static boolean inactive(ActivationID id)
@@ -290,6 +302,8 @@
      * @exception UnknownObjectException if object (<code>id</code>) is unknown
      * @exception ActivationException if activation system is not running
      * @exception RemoteException if remote call to activation system fails
+     * @exception UnsupportedOperationException if and only if activation is
+     * not supported by this implementation
      * @since 1.2
      */
     public static void unregister(ActivationID id)
@@ -334,6 +348,8 @@
      * the wrong group
      * @exception ActivationException if activation group is not active
      * @exception RemoteException if object registration or export fails
+     * @exception UnsupportedOperationException if and only if activation is
+     * not supported by this implementation
      * @since 1.2
      **/
     public static ActivationID exportObject(Remote obj,
@@ -407,6 +423,8 @@
      * descriptor with the activation system
      * @exception ActivationException if activation group is not active
      * @exception RemoteException if object registration or export fails
+     * @exception UnsupportedOperationException if and only if activation is
+     * not supported by this implementation
      * @since 1.2
      **/
     public static ActivationID exportObject(Remote obj,
@@ -473,6 +491,8 @@
      * @param port the port on which the object is exported (an anonymous
      * port is used if port=0)
      * @exception RemoteException if object export fails
+     * @exception UnsupportedOperationException if and only if activation is
+     * not supported by this implementation
      * @since 1.2
      */
     public static Remote exportObject(Remote obj,
@@ -503,6 +523,8 @@
      * remote object
      * @param ssf the server-side socket factory for receiving remote calls
      * @exception RemoteException if object export fails
+     * @exception UnsupportedOperationException if and only if activation is
+     * not supported by this implementation
      * @since 1.2
      */
     public static Remote exportObject(Remote obj,
@@ -531,6 +553,8 @@
      * @return true if operation is successful, false otherwise
      * @exception NoSuchObjectException if the remote object is not
      * currently exported
+     * @exception UnsupportedOperationException if and only if activation is
+     * not supported by this implementation
      * @since 1.2
      */
     public static boolean unexportObject(Remote obj, boolean force)
--- a/jdk/src/share/classes/java/rmi/activation/ActivationDesc.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/rmi/activation/ActivationDesc.java	Wed Jul 05 19:11:53 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -105,6 +105,8 @@
      * @param data the object's initialization (activation) data contained
      * in marshalled form.
      * @exception ActivationException if the current group is nonexistent
+     * @exception UnsupportedOperationException if and only if activation is
+     * not supported by this implementation
      * @since 1.2
      */
     public ActivationDesc(String className,
@@ -142,6 +144,8 @@
      * <code>true</code> does not force an initial immediate activation of
      * a newly registered object;  initial activation is lazy.
      * @exception ActivationException if the current group is nonexistent
+     * @exception UnsupportedOperationException if and only if activation is
+     * not supported by this implementation
      * @since 1.2
      */
     public ActivationDesc(String className,
@@ -176,6 +180,8 @@
      * @param data  the object's initialization (activation) data contained
      * in marshalled form.
      * @exception IllegalArgumentException if <code>groupID</code> is null
+     * @exception UnsupportedOperationException if and only if activation is
+     * not supported by this implementation
      * @since 1.2
      */
     public ActivationDesc(ActivationGroupID groupID,
@@ -208,6 +214,8 @@
      * <code>true</code> does not force an initial immediate activation of
      * a newly registered object;  initial activation is lazy.
      * @exception IllegalArgumentException if <code>groupID</code> is null
+     * @exception UnsupportedOperationException if and only if activation is
+     * not supported by this implementation
      * @since 1.2
      */
     public ActivationDesc(ActivationGroupID groupID,
--- a/jdk/src/share/classes/java/rmi/activation/ActivationGroup.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/rmi/activation/ActivationGroup.java	Wed Jul 05 19:11:53 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -133,6 +133,8 @@
      *
      * @param   groupID the group's identifier
      * @throws  RemoteException if this group could not be exported
+     * @throws  UnsupportedOperationException if and only if activation is
+     *          not supported by this implementation
      * @since   1.2
      */
     protected ActivationGroup(ActivationGroupID groupID)
@@ -267,6 +269,8 @@
      * (Note: The default implementation of the security manager
      * <code>checkSetFactory</code>
      * method requires the RuntimePermission "setFactory")
+     * @exception UnsupportedOperationException if and only if activation is
+     * not supported by this implementation
      * @see SecurityManager#checkSetFactory
      * @since 1.2
      */
@@ -345,6 +349,8 @@
     /**
      * Returns the current activation group's identifier.  Returns null
      * if no group is currently active for this VM.
+     * @exception UnsupportedOperationException if and only if activation is
+     * not supported by this implementation
      * @return the activation group's identifier
      * @since 1.2
      */
@@ -394,6 +400,8 @@
      * (Note: The default implementation of the security manager
      * <code>checkSetFactory</code>
      * method requires the RuntimePermission "setFactory")
+     * @exception UnsupportedOperationException if and only if activation is
+     * not supported by this implementation
      * @see #getSystem
      * @see SecurityManager#checkSetFactory
      * @since 1.2
@@ -428,6 +436,8 @@
      * @exception ActivationException if activation system cannot be
      *  obtained or is not bound
      * (means that it is not running)
+     * @exception UnsupportedOperationException if and only if activation is
+     * not supported by this implementation
      * @see #setSystem
      * @since 1.2
      */
--- a/jdk/src/share/classes/java/rmi/activation/ActivationGroupID.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/rmi/activation/ActivationGroupID.java	Wed Jul 05 19:11:53 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 1999, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -63,6 +63,8 @@
      * Constructs a unique group id.
      *
      * @param system the group's activation system
+     * @throws UnsupportedOperationException if and only if activation is
+     *         not supported by this implementation
      * @since 1.2
      */
     public ActivationGroupID(ActivationSystem system) {
--- a/jdk/src/share/classes/java/rmi/activation/ActivationID.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/rmi/activation/ActivationID.java	Wed Jul 05 19:11:53 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -90,6 +90,8 @@
      *
      * @param activator reference to the activator responsible for
      * activating the object
+     * @throws UnsupportedOperationException if and only if activation is
+     *         not supported by this implementation
      * @since 1.2
      */
     public ActivationID(Activator activator) {
--- a/jdk/src/share/classes/java/rmi/activation/package.html	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/rmi/activation/package.html	Wed Jul 05 19:11:53 2017 +0200
@@ -1,5 +1,5 @@
 <!--
- Copyright (c) 1998, 1999, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 
  This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,15 @@
 object's reference can be made ``persistent'' and later activated into a
 ``live'' object using the RMI activation mechanism.
 
+<p>Implementations are not required to support the activation
+mechanism. If activation is not supported by this implementation,
+several specific activation API methods are all required to throw
+{@code UnsupportedOperationException}. If activation is supported by this
+implementation, these methods must never throw {@code
+UnsupportedOperationException}. These methods are denoted by the
+presence of an entry for {@code UnsupportedOperationException} in the
+<strong>Throws</strong> section of each method's specification.
+
 <!--
 <h2>Package Specification</h2>
 
--- a/jdk/src/share/classes/java/security/AccessController.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/security/AccessController.java	Wed Jul 05 19:11:53 2017 +0200
@@ -279,6 +279,9 @@
      * <p> Note that any DomainCombiner associated with the current
      * AccessControlContext will be ignored while the action is performed.
      *
+     * @param <T> the type of the value returned by the PrivilegedAction's
+     *                  {@code run} method.
+     *
      * @param action the action to be performed.
      *
      * @return the value returned by the action's {@code run} method.
@@ -305,6 +308,9 @@
      * <p> This method preserves the current AccessControlContext's
      * DomainCombiner (which may be null) while the action is performed.
      *
+     * @param <T> the type of the value returned by the PrivilegedAction's
+     *                  {@code run} method.
+     *
      * @param action the action to be performed.
      *
      * @return the value returned by the action's {@code run} method.
@@ -344,6 +350,8 @@
      * {@link java.security.SecurityPermission}, then the action is performed
      * with no permissions.
      *
+     * @param <T> the type of the value returned by the PrivilegedAction's
+     *                  {@code run} method.
      * @param action the action to be performed.
      * @param context an <i>access control context</i>
      *                representing the restriction to be applied to the
@@ -377,6 +385,8 @@
      * If the action's {@code run} method throws an (unchecked) exception,
      * it will propagate through this method.
      *
+     * @param <T> the type of the value returned by the PrivilegedAction's
+     *                  {@code run} method.
      * @param action the action to be performed.
      * @param context an <i>access control context</i>
      *                representing the restriction to be applied to the
@@ -429,6 +439,8 @@
      * <p> This method preserves the current AccessControlContext's
      * DomainCombiner (which may be null) while the action is performed.
      *
+     * @param <T> the type of the value returned by the PrivilegedAction's
+     *                  {@code run} method.
      * @param action the action to be performed.
      * @param context an <i>access control context</i>
      *                representing the restriction to be applied to the
@@ -479,6 +491,9 @@
      * <p> Note that any DomainCombiner associated with the current
      * AccessControlContext will be ignored while the action is performed.
      *
+     * @param <T> the type of the value returned by the
+     *                  PrivilegedExceptionAction's {@code run} method.
+     *
      * @param action the action to be performed
      *
      * @return the value returned by the action's {@code run} method
@@ -509,6 +524,9 @@
      * <p> This method preserves the current AccessControlContext's
      * DomainCombiner (which may be null) while the action is performed.
      *
+     * @param <T> the type of the value returned by the
+     *                  PrivilegedExceptionAction's {@code run} method.
+     *
      * @param action the action to be performed.
      *
      * @return the value returned by the action's {@code run} method
@@ -585,6 +603,8 @@
      * {@link java.security.SecurityPermission}, then the action is performed
      * with no permissions.
      *
+     * @param <T> the type of the value returned by the
+     *                  PrivilegedExceptionAction's {@code run} method.
      * @param action the action to be performed
      * @param context an <i>access control context</i>
      *                representing the restriction to be applied to the
@@ -622,6 +642,8 @@
      * If the action's {@code run} method throws an (unchecked) exception,
      * it will propagate through this method.
      *
+     * @param <T> the type of the value returned by the
+     *                  PrivilegedExceptionAction's {@code run} method.
      * @param action the action to be performed.
      * @param context an <i>access control context</i>
      *                representing the restriction to be applied to the
@@ -676,6 +698,8 @@
      * <p> This method preserves the current AccessControlContext's
      * DomainCombiner (which may be null) while the action is performed.
      *
+     * @param <T> the type of the value returned by the
+     *                  PrivilegedExceptionAction's {@code run} method.
      * @param action the action to be performed.
      * @param context an <i>access control context</i>
      *                representing the restriction to be applied to the
--- a/jdk/src/share/classes/java/security/AlgorithmParameters.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/security/AlgorithmParameters.java	Wed Jul 05 19:11:53 2017 +0200
@@ -324,6 +324,7 @@
      * parameters should be returned in an instance of the
      * {@code DSAParameterSpec} class.
      *
+     * @param <T> the type of the parameter specification to be returrned
      * @param paramSpec the specification class in which
      * the parameters should be returned.
      *
--- a/jdk/src/share/classes/java/security/AlgorithmParametersSpi.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/security/AlgorithmParametersSpi.java	Wed Jul 05 19:11:53 2017 +0200
@@ -102,6 +102,8 @@
      * parameters should be returned in an instance of the
      * {@code DSAParameterSpec} class.
      *
+     * @param <T> the type of the parameter specification to be returned
+     *
      * @param paramSpec the specification class in which
      * the parameters should be returned.
      *
--- a/jdk/src/share/classes/java/security/KeyFactory.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/security/KeyFactory.java	Wed Jul 05 19:11:53 2017 +0200
@@ -395,6 +395,8 @@
      * key material should be returned in an instance of the
      * {@code DSAPublicKeySpec} class.
      *
+     * @param <T> the type of the key specification to be returned
+     *
      * @param key the key.
      *
      * @param keySpec the specification class in which
--- a/jdk/src/share/classes/java/security/KeyFactorySpi.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/security/KeyFactorySpi.java	Wed Jul 05 19:11:53 2017 +0200
@@ -106,6 +106,8 @@
      * key material should be returned in an instance of the
      * {@code DSAPublicKeySpec} class.
      *
+     * @param <T> the type of the key specification to be returned
+     *
      * @param key the key.
      *
      * @param keySpec the specification class in which
--- a/jdk/src/share/classes/java/security/KeyStore.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/security/KeyStore.java	Wed Jul 05 19:11:53 2017 +0200
@@ -1753,6 +1753,7 @@
         /**
          * Returns the KeyStore described by this object.
          *
+         * @return the {@code KeyStore} described by this object
          * @exception KeyStoreException if an error occured during the
          *   operation, for example if the KeyStore could not be
          *   instantiated or loaded
--- a/jdk/src/share/classes/java/security/Principal.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/security/Principal.java	Wed Jul 05 19:11:53 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -81,6 +81,7 @@
      * <p>Subclasses may override this with a different implementation, if
      * necessary.
      *
+     * @param subject the {@code Subject}
      * @return true if {@code subject} is non-null and is
      *              implied by this principal, or false otherwise.
      * @since 1.8
--- a/jdk/src/share/classes/java/security/cert/CertPathBuilderSpi.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/security/cert/CertPathBuilderSpi.java	Wed Jul 05 19:11:53 2017 +0200
@@ -87,6 +87,8 @@
      * service providers, this method cannot be abstract and by default throws
      * an {@code UnsupportedOperationException}.
      *
+     * @return a {@code CertPathChecker} that this implementation uses to
+     * check the revocation status of certificates
      * @throws UnsupportedOperationException if this method is not supported
      * @since 1.8
      */
--- a/jdk/src/share/classes/java/security/cert/CertPathValidatorSpi.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/security/cert/CertPathValidatorSpi.java	Wed Jul 05 19:11:53 2017 +0200
@@ -97,6 +97,8 @@
      * service providers, this method cannot be abstract and by default throws
      * an {@code UnsupportedOperationException}.
      *
+     * @return a {@code CertPathChecker} that this implementation uses to
+     * check the revocation status of certificates
      * @throws UnsupportedOperationException if this method is not supported
      * @since 1.8
      */
--- a/jdk/src/share/classes/java/security/cert/PKIXRevocationChecker.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/security/cert/PKIXRevocationChecker.java	Wed Jul 05 19:11:53 2017 +0200
@@ -103,6 +103,9 @@
     private Map<X509Certificate, byte[]> ocspResponses = Collections.emptyMap();
     private Set<Option> options = Collections.emptySet();
 
+    /**
+     * Default constructor.
+     */
     protected PKIXRevocationChecker() {}
 
     /**
@@ -300,8 +303,7 @@
          *  <li>The CRL or OCSP response cannot be obtained because of a
          *      network error.
          *  <li>The OCSP responder returns one of the following errors
-         *      specified in section 2.3 of RFC 2560: internalError, tryLater,
-         *      or unauthorized.
+         *      specified in section 2.3 of RFC 2560: internalError or tryLater.
          * </ul><br>
          * Note that these conditions apply to both OCSP and CRLs, and unless
          * the {@code NO_FALLBACK} option is set, the revocation check is
--- a/jdk/src/share/classes/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/security/interfaces/RSAMultiPrimePrivateCrtKey.java	Wed Jul 05 19:11:53 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -46,6 +46,11 @@
 
 public interface RSAMultiPrimePrivateCrtKey extends RSAPrivateKey {
 
+    /**
+     * The type fingerprint that is set to indicate
+     * serialization compatibility with a previous
+     * version of the type.
+     */
     static final long serialVersionUID = 618058533534628008L;
 
     /**
--- a/jdk/src/share/classes/java/security/interfaces/RSAPrivateCrtKey.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/security/interfaces/RSAPrivateCrtKey.java	Wed Jul 05 19:11:53 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -39,6 +39,11 @@
 
 public interface RSAPrivateCrtKey extends RSAPrivateKey {
 
+    /**
+     * The type fingerprint that is set to indicate
+     * serialization compatibility with a previous
+     * version of the type.
+     */
     static final long serialVersionUID = -5682214253527700368L;
 
     /**
--- a/jdk/src/share/classes/java/security/interfaces/RSAPrivateKey.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/security/interfaces/RSAPrivateKey.java	Wed Jul 05 19:11:53 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -39,6 +39,11 @@
 public interface RSAPrivateKey extends java.security.PrivateKey, RSAKey
 {
 
+    /**
+     * The type fingerprint that is set to indicate
+     * serialization compatibility with a previous
+     * version of the type.
+     */
     static final long serialVersionUID = 5187144804936595022L;
 
     /**
--- a/jdk/src/share/classes/java/security/interfaces/RSAPublicKey.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/security/interfaces/RSAPublicKey.java	Wed Jul 05 19:11:53 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,6 +36,11 @@
 
 public interface RSAPublicKey extends java.security.PublicKey, RSAKey
 {
+    /**
+     * The type fingerprint that is set to indicate
+     * serialization compatibility with a previous
+     * version of the type.
+     */
     static final long serialVersionUID = -8727434096241101194L;
 
     /**
--- a/jdk/src/share/classes/java/sql/DriverManager.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/sql/DriverManager.java	Wed Jul 05 19:11:53 2017 +0200
@@ -326,6 +326,7 @@
      * @param driver the new JDBC Driver that is to be registered with the
      *               {@code DriverManager}
      * @exception SQLException if a database access error occurs
+     * @exception NullPointerException if {@code driver} is null
      */
     public static synchronized void registerDriver(java.sql.Driver driver)
         throws SQLException {
@@ -345,6 +346,7 @@
      * @param da     the {@code DriverAction} implementation to be used when
      *               {@code DriverManager#deregisterDriver} is called
      * @exception SQLException if a database access error occurs
+     * @exception NullPointerException if {@code driver} is null
      */
     public static synchronized void registerDriver(java.sql.Driver driver,
             DriverAction da)
--- a/jdk/src/share/classes/java/sql/PreparedStatement.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/sql/PreparedStatement.java	Wed Jul 05 19:11:53 2017 +0200
@@ -954,7 +954,6 @@
      * the JDBC driver does not support this data type
      * @see Types
      *
-     * @since 1.6
      */
     void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength)
             throws SQLException;
--- a/jdk/src/share/classes/java/time/Duration.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/Duration.java	Wed Jul 05 19:11:53 2017 +0200
@@ -74,7 +74,7 @@
 import java.io.DataOutput;
 import java.io.IOException;
 import java.io.InvalidObjectException;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
 import java.io.Serializable;
 import java.math.BigDecimal;
 import java.math.BigInteger;
@@ -1299,8 +1299,9 @@
     /**
      * Writes the object using a
      * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
      * <pre>
-     *  out.writeByte(1);  // identifies this as a Duration
+     *  out.writeByte(1);  // identifies a Duration
      *  out.writeLong(seconds);
      *  out.writeInt(nanos);
      * </pre>
@@ -1316,7 +1317,7 @@
      * @return never
      * @throws InvalidObjectException always
      */
-    private Object readResolve() throws ObjectStreamException {
+    private Object readResolve() throws InvalidObjectException {
         throw new InvalidObjectException("Deserialization via serialization delegate");
     }
 
--- a/jdk/src/share/classes/java/time/Instant.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/Instant.java	Wed Jul 05 19:11:53 2017 +0200
@@ -76,7 +76,7 @@
 import java.io.DataOutput;
 import java.io.IOException;
 import java.io.InvalidObjectException;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
 import java.io.Serializable;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeParseException;
@@ -1317,8 +1317,9 @@
     /**
      * Writes the object using a
      * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
      * <pre>
-     *  out.writeByte(2);  // identifies this as an Instant
+     *  out.writeByte(2);  // identifies an Instant
      *  out.writeLong(seconds);
      *  out.writeInt(nanos);
      * </pre>
@@ -1334,7 +1335,7 @@
      * @return never
      * @throws InvalidObjectException always
      */
-    private Object readResolve() throws ObjectStreamException {
+    private Object readResolve() throws InvalidObjectException {
         throw new InvalidObjectException("Deserialization via serialization delegate");
     }
 
--- a/jdk/src/share/classes/java/time/LocalDate.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/LocalDate.java	Wed Jul 05 19:11:53 2017 +0200
@@ -78,7 +78,7 @@
 import java.io.DataOutput;
 import java.io.IOException;
 import java.io.InvalidObjectException;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
 import java.io.Serializable;
 import java.time.chrono.ChronoLocalDate;
 import java.time.chrono.Era;
@@ -2019,8 +2019,9 @@
     /**
      * Writes the object using a
      * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
      * <pre>
-     *  out.writeByte(3);  // identifies this as a LocalDate
+     *  out.writeByte(3);  // identifies a LocalDate
      *  out.writeInt(year);
      *  out.writeByte(month);
      *  out.writeByte(day);
@@ -2037,7 +2038,7 @@
      * @return never
      * @throws InvalidObjectException always
      */
-    private Object readResolve() throws ObjectStreamException {
+    private Object readResolve() throws InvalidObjectException {
         throw new InvalidObjectException("Deserialization via serialization delegate");
     }
 
--- a/jdk/src/share/classes/java/time/LocalDateTime.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/LocalDateTime.java	Wed Jul 05 19:11:53 2017 +0200
@@ -76,7 +76,7 @@
 import java.io.DataOutput;
 import java.io.IOException;
 import java.io.InvalidObjectException;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
 import java.io.Serializable;
 import java.time.chrono.ChronoLocalDateTime;
 import java.time.format.DateTimeFormatter;
@@ -1953,8 +1953,9 @@
     /**
      * Writes the object using a
      * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
      * <pre>
-     *  out.writeByte(5);  // identifies this as a LocalDateTime
+     *  out.writeByte(5);  // identifies a LocalDateTime
      *  // the <a href="../../serialized-form.html#java.time.LocalDate">date</a> excluding the one byte header
      *  // the <a href="../../serialized-form.html#java.time.LocalTime">time</a> excluding the one byte header
      * </pre>
@@ -1970,7 +1971,7 @@
      * @return never
      * @throws InvalidObjectException always
      */
-    private Object readResolve() throws ObjectStreamException {
+    private Object readResolve() throws InvalidObjectException {
         throw new InvalidObjectException("Deserialization via serialization delegate");
     }
 
--- a/jdk/src/share/classes/java/time/LocalTime.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/LocalTime.java	Wed Jul 05 19:11:53 2017 +0200
@@ -74,7 +74,7 @@
 import java.io.DataOutput;
 import java.io.IOException;
 import java.io.InvalidObjectException;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
 import java.io.Serializable;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeParseException;
@@ -1595,8 +1595,11 @@
     /**
      * Writes the object using a
      * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
+     * A twos-complement value indicates the remaining values are not in the stream
+     * and should be set to zero.
      * <pre>
-     *  out.writeByte(4);  // identifies this as a LocalTime
+     *  out.writeByte(4);  // identifies a LocalTime
      *  if (nano == 0) {
      *    if (second == 0) {
      *      if (minute == 0) {
@@ -1629,7 +1632,7 @@
      * @return never
      * @throws InvalidObjectException always
      */
-    private Object readResolve() throws ObjectStreamException {
+    private Object readResolve() throws InvalidObjectException {
         throw new InvalidObjectException("Deserialization via serialization delegate");
     }
 
--- a/jdk/src/share/classes/java/time/MonthDay.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/MonthDay.java	Wed Jul 05 19:11:53 2017 +0200
@@ -68,7 +68,7 @@
 import java.io.DataOutput;
 import java.io.IOException;
 import java.io.InvalidObjectException;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
 import java.io.Serializable;
 import java.time.chrono.Chronology;
 import java.time.chrono.IsoChronology;
@@ -744,9 +744,10 @@
     //-----------------------------------------------------------------------
     /**
      * Writes the object using a
-     * <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
      * <pre>
-     *  out.writeByte(13);  // identifies this as a MonthDay
+     *  out.writeByte(13);  // identifies a MonthDay
      *  out.writeByte(month);
      *  out.writeByte(day);
      * </pre>
@@ -762,7 +763,7 @@
      * @return never
      * @throws InvalidObjectException always
      */
-    private Object readResolve() throws ObjectStreamException {
+    private Object readResolve() throws InvalidObjectException {
         throw new InvalidObjectException("Deserialization via serialization delegate");
     }
 
--- a/jdk/src/share/classes/java/time/OffsetDateTime.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/OffsetDateTime.java	Wed Jul 05 19:11:53 2017 +0200
@@ -72,7 +72,7 @@
 import java.io.InvalidObjectException;
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
 import java.io.Serializable;
 import java.time.chrono.IsoChronology;
 import java.time.format.DateTimeFormatter;
@@ -1901,9 +1901,10 @@
     //-----------------------------------------------------------------------
     /**
      * Writes the object using a
-     * <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
      * <pre>
-     *  out.writeByte(10);  // identifies this as a OffsetDateTime
+     *  out.writeByte(10);  // identifies a OffsetDateTime
      *  out.writeObject(dateTime);
      *  out.writeObject(offset);
      * </pre>
@@ -1919,7 +1920,7 @@
      * @return never
      * @throws InvalidObjectException always
      */
-    private Object readResolve() throws ObjectStreamException {
+    private Object readResolve() throws InvalidObjectException {
         throw new InvalidObjectException("Deserialization via serialization delegate");
     }
 
--- a/jdk/src/share/classes/java/time/OffsetTime.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/OffsetTime.java	Wed Jul 05 19:11:53 2017 +0200
@@ -73,7 +73,7 @@
 import java.io.InvalidObjectException;
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
 import java.io.Serializable;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeParseException;
@@ -1372,9 +1372,10 @@
     //-----------------------------------------------------------------------
     /**
      * Writes the object using a
-     * <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
      * <pre>
-     *  out.writeByte(9);  // identifies this as a OffsetTime
+     *  out.writeByte(9);  // identifies a OffsetTime
      *  out.writeObject(time);
      *  out.writeObject(offset);
      * </pre>
@@ -1390,7 +1391,7 @@
      * @return never
      * @throws InvalidObjectException always
      */
-    private Object readResolve() throws ObjectStreamException {
+    private Object readResolve() throws InvalidObjectException {
         throw new InvalidObjectException("Deserialization via serialization delegate");
     }
 
--- a/jdk/src/share/classes/java/time/Period.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/Period.java	Wed Jul 05 19:11:53 2017 +0200
@@ -70,7 +70,7 @@
 import java.io.DataOutput;
 import java.io.IOException;
 import java.io.InvalidObjectException;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
 import java.io.Serializable;
 import java.time.chrono.ChronoLocalDate;
 import java.time.chrono.Chronology;
@@ -993,11 +993,12 @@
     /**
      * Writes the object using a
      * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
      * <pre>
-     *  out.writeByte(14);  // identifies this as a Period
+     *  out.writeByte(14);  // identifies a Period
      *  out.writeInt(years);
      *  out.writeInt(months);
-     *  out.writeInt(seconds);
+     *  out.writeInt(days);
      * </pre>
      *
      * @return the instance of {@code Ser}, not null
@@ -1011,7 +1012,7 @@
      * @return never
      * @throws java.io.InvalidObjectException always
      */
-    private Object readResolve() throws ObjectStreamException {
+    private Object readResolve() throws InvalidObjectException {
         throw new InvalidObjectException("Deserialization via serialization delegate");
     }
 
--- a/jdk/src/share/classes/java/time/Ser.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/Ser.java	Wed Jul 05 19:11:53 2017 +0200
@@ -72,14 +72,14 @@
  * byte flag would be used in order to specify an alternative version of the type format.
  * For example {@code LOCAL_DATE_TYPE_VERSION_2 = 21}.
  * <p>
- * In order to serialise the object it writes its byte and then calls back to the appropriate class where
- * the serialisation is performed.  In order to deserialise the object it read in the type byte, switching
+ * In order to serialize the object it writes its byte and then calls back to the appropriate class where
+ * the serialization is performed.  In order to deserialize the object it read in the type byte, switching
  * in order to select which class to call back into.
  * <p>
- * The serialisation format is determined on a per class basis.  In the case of field based classes each
+ * The serialization format is determined on a per class basis.  In the case of field based classes each
  * of the fields is written out with an appropriate size format in descending order of the field's size.  For
  * example in the case of {@link LocalDate} year is written before month.  Composite classes, such as
- * {@link LocalDateTime} are serialised as one object.
+ * {@link LocalDateTime} are serialized as one object.
  * <p>
  * This class is mutable and should be created once per serialization.
  *
@@ -133,6 +133,27 @@
     //-----------------------------------------------------------------------
     /**
      * Implements the {@code Externalizable} interface to write the object.
+     * @serialData
+     *
+     * Each serializable class is mapped to a type that is the first byte
+     * in the stream.  Refer to each class {@code writeReplace}
+     * serialized form for the value of the type and sequence of values for the type.
+     * <ul>
+     * <li><a href="../../serialized-form.html#java.time.Duration">Duration.writeReplace</a>
+     * <li><a href="../../serialized-form.html#java.time.Instant">Instant.writeReplace</a>
+     * <li><a href="../../serialized-form.html#java.time.LocalDate">LocalDate.writeReplace</a>
+     * <li><a href="../../serialized-form.html#java.time.LocalDateTime">LocalDateTime.writeReplace</a>
+     * <li><a href="../../serialized-form.html#java.time.LocalTime">LocalTime.writeReplace</a>
+     * <li><a href="../../serialized-form.html#java.time.MonthDay">MonthDay.writeReplace</a>
+     * <li><a href="../../serialized-form.html#java.time.OffsetTime">OffsetTime.writeReplace</a>
+     * <li><a href="../../serialized-form.html#java.time.OffsetDateTime">OffsetDateTime.writeReplace</a>
+     * <li><a href="../../serialized-form.html#java.time.Period">Period.writeReplace</a>
+     * <li><a href="../../serialized-form.html#java.time.Year">Year.writeReplace</a>
+     * <li><a href="../../serialized-form.html#java.time.YearMonth">YearMonth.writeReplace</a>
+     * <li><a href="../../serialized-form.html#java.time.ZoneId">ZoneId.writeReplace</a>
+     * <li><a href="../../serialized-form.html#java.time.ZoneOffset">ZoneOffset.writeReplace</a>
+     * <li><a href="../../serialized-form.html#java.time.ZonedDateTime">ZonedDateTime.writeReplace</a>
+     * </ul>
      *
      * @param out  the data stream to write to, not null
      */
@@ -194,6 +215,29 @@
     //-----------------------------------------------------------------------
     /**
      * Implements the {@code Externalizable} interface to read the object.
+     * @serialData
+     *
+     * The streamed type and parameters defined by the type's {@code writeReplace}
+     * method are read and passed to the corresponding static factory for the type
+     * to create a new instance.  That instance is returned as the de-serialized
+     * {@code Ser} object.
+     *
+     * <ul>
+     * <li><a href="../../serialized-form.html#java.time.Duration">Duration</a> - {@code Duration.ofSeconds(seconds, nanos);}
+     * <li><a href="../../serialized-form.html#java.time.Instant">Instant</a> - {@code Instant.ofEpochSecond(seconds, nanos);}
+     * <li><a href="../../serialized-form.html#java.time.LocalDate">LocalDate</a> - {@code LocalDate.of(year, month, day);}
+     * <li><a href="../../serialized-form.html#java.time.LocalDateTime">LocalDateTime</a> - {@code LocalDateTime.of(date, time);}
+     * <li><a href="../../serialized-form.html#java.time.LocalTime">LocalTime</a> - {@code LocalTime.of(hour, minute, second, nano);}
+     * <li><a href="../../serialized-form.html#java.time.MonthDay">MonthDay</a> - {@code MonthDay.of(month, day);}
+     * <li><a href="../../serialized-form.html#java.time.OffsetTime">OffsetTime</a> - {@code OffsetTime.of(time, offset);}
+     * <li><a href="../../serialized-form.html#java.time.OffsetDateTime">OffsetDateTime</a> - {@code OffsetDateTime.of(dateTime, offset);}
+     * <li><a href="../../serialized-form.html#java.time.Period">Period</a> - {@code Period.of(years, months, days);}
+     * <li><a href="../../serialized-form.html#java.time.Year">Year</a> - {@code Year.of(year);}
+     * <li><a href="../../serialized-form.html#java.time.YearMonth">YearMonth</a> - {@code YearMonth.of(year, month);}
+     * <li><a href="../../serialized-form.html#java.time.ZonedDateTime">ZonedDateTime</a> - {@code ZonedDateTime.ofLenient(dateTime, offset, zone);}
+     * <li><a href="../../serialized-form.html#java.time.ZoneId">ZoneId</a> - {@code ZoneId.of(id);}
+     * <li><a href="../../serialized-form.html#java.time.ZoneOffset">ZoneOffset</a> - {@code (offsetByte == 127 ? ZoneOffset.ofTotalSeconds(in.readInt()) : ZoneOffset.ofTotalSeconds(offsetByte * 900));}
+     * </ul>
      *
      * @param in  the data to read, not null
      */
--- a/jdk/src/share/classes/java/time/Year.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/Year.java	Wed Jul 05 19:11:53 2017 +0200
@@ -74,7 +74,7 @@
 import java.io.DataOutput;
 import java.io.IOException;
 import java.io.InvalidObjectException;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
 import java.io.Serializable;
 import java.time.chrono.Chronology;
 import java.time.chrono.IsoChronology;
@@ -1080,9 +1080,10 @@
     //-----------------------------------------------------------------------
     /**
      * Writes the object using a
-     * <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
      * <pre>
-     *  out.writeByte(11);  // identifies this as a Year
+     *  out.writeByte(11);  // identifies a Year
      *  out.writeInt(year);
      * </pre>
      *
@@ -1097,7 +1098,7 @@
      * @return never
      * @throws InvalidObjectException always
      */
-    private Object readResolve() throws ObjectStreamException {
+    private Object readResolve() throws InvalidObjectException {
         throw new InvalidObjectException("Deserialization via serialization delegate");
     }
 
--- a/jdk/src/share/classes/java/time/YearMonth.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/YearMonth.java	Wed Jul 05 19:11:53 2017 +0200
@@ -77,7 +77,7 @@
 import java.io.DataOutput;
 import java.io.IOException;
 import java.io.InvalidObjectException;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
 import java.io.Serializable;
 import java.time.chrono.Chronology;
 import java.time.chrono.IsoChronology;
@@ -1205,9 +1205,10 @@
     //-----------------------------------------------------------------------
     /**
      * Writes the object using a
-     * <a href="../../../serialized-form.html#java.time.temporal.Ser">dedicated serialized form</a>.
+     * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
      * <pre>
-     *  out.writeByte(12);  // identifies this as a YearMonth
+     *  out.writeByte(12);  // identifies a YearMonth
      *  out.writeInt(year);
      *  out.writeByte(month);
      * </pre>
@@ -1223,7 +1224,7 @@
      * @return never
      * @throws InvalidObjectException always
      */
-    private Object readResolve() throws ObjectStreamException {
+    private Object readResolve() throws InvalidObjectException {
         throw new InvalidObjectException("Deserialization via serialization delegate");
     }
 
--- a/jdk/src/share/classes/java/time/ZoneId.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/ZoneId.java	Wed Jul 05 19:11:53 2017 +0200
@@ -63,6 +63,7 @@
 
 import java.io.DataOutput;
 import java.io.IOException;
+import java.io.InvalidObjectException;
 import java.io.Serializable;
 import java.time.format.DateTimeFormatterBuilder;
 import java.time.format.TextStyle;
@@ -662,6 +663,15 @@
 
     //-----------------------------------------------------------------------
     /**
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    /**
      * Outputs this zone as a {@code String}, using the ID.
      *
      * @return a string representation of this time-zone ID, not null
@@ -675,9 +685,10 @@
     /**
      * Writes the object using a
      * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
      * <pre>
-     *  out.writeByte(7);  // identifies this as a ZoneId (not ZoneOffset)
-     *  out.writeUTF(zoneId);
+     *  out.writeByte(7);  // identifies a ZoneId (not ZoneOffset)
+     *  out.writeUTF(getId());
      * </pre>
      * <p>
      * When read back in, the {@code ZoneId} will be created as though using
--- a/jdk/src/share/classes/java/time/ZoneOffset.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/ZoneOffset.java	Wed Jul 05 19:11:53 2017 +0200
@@ -70,7 +70,7 @@
 import java.io.DataOutput;
 import java.io.IOException;
 import java.io.InvalidObjectException;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
 import java.io.Serializable;
 import java.time.temporal.ChronoField;
 import java.time.temporal.Temporal;
@@ -740,12 +740,13 @@
     /**
      * Writes the object using a
      * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
      * <pre>
-     *  out.writeByte(8);  // identifies this as a ZoneOffset
+     *  out.writeByte(8);                  // identifies a ZoneOffset
      *  int offsetByte = totalSeconds % 900 == 0 ? totalSeconds / 900 : 127;
      *  out.writeByte(offsetByte);
      *  if (offsetByte == 127) {
-     *    out.writeInt(totalSeconds);
+     *      out.writeInt(totalSeconds);
      *  }
      * </pre>
      *
@@ -760,7 +761,7 @@
      * @return never
      * @throws InvalidObjectException always
      */
-    private Object readResolve() throws ObjectStreamException {
+    private Object readResolve() throws InvalidObjectException {
         throw new InvalidObjectException("Deserialization via serialization delegate");
     }
 
--- a/jdk/src/share/classes/java/time/ZoneRegion.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/ZoneRegion.java	Wed Jul 05 19:11:53 2017 +0200
@@ -60,7 +60,7 @@
 import java.io.DataOutput;
 import java.io.IOException;
 import java.io.InvalidObjectException;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
 import java.io.Serializable;
 import java.time.zone.ZoneRules;
 import java.time.zone.ZoneRulesException;
@@ -181,8 +181,9 @@
     /**
      * Writes the object using a
      * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
      * <pre>
-     *  out.writeByte(7);  // identifies this as a ZoneId (not ZoneOffset)
+     *  out.writeByte(7);  // identifies a ZoneId (not ZoneOffset)
      *  out.writeUTF(zoneId);
      * </pre>
      *
@@ -197,7 +198,7 @@
      * @return never
      * @throws InvalidObjectException always
      */
-    private Object readResolve() throws ObjectStreamException {
+    private Object readResolve() throws InvalidObjectException {
         throw new InvalidObjectException("Deserialization via serialization delegate");
     }
 
--- a/jdk/src/share/classes/java/time/ZonedDateTime.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/ZonedDateTime.java	Wed Jul 05 19:11:53 2017 +0200
@@ -69,7 +69,7 @@
 import java.io.IOException;
 import java.io.InvalidObjectException;
 import java.io.ObjectInput;
-import java.io.ObjectStreamException;
+import java.io.InvalidObjectException;
 import java.io.Serializable;
 import java.time.chrono.ChronoZonedDateTime;
 import java.time.format.DateTimeFormatter;
@@ -2192,9 +2192,10 @@
     /**
      * Writes the object using a
      * <a href="../../serialized-form.html#java.time.Ser">dedicated serialized form</a>.
+     * @serialData
      * <pre>
-     *  out.writeByte(6);  // identifies this as a ZonedDateTime
-     *  // the <a href="../../serialized-form.html#java.time.LocalDateTime">date-time</a> excluding the one byte header
+     *  out.writeByte(6);  // identifies a ZonedDateTime
+     *  // the <a href="../../serialized-form.html#java.time.LocalDateTime">dateTime</a> excluding the one byte header
      *  // the <a href="../../serialized-form.html#java.time.ZoneOffset">offset</a> excluding the one byte header
      *  // the <a href="../../serialized-form.html#java.time.ZoneId">zone ID</a> excluding the one byte header
      * </pre>
@@ -2210,7 +2211,7 @@
      * @return never
      * @throws InvalidObjectException always
      */
-    private Object readResolve() throws ObjectStreamException {
+    private Object readResolve() throws InvalidObjectException {
         throw new InvalidObjectException("Deserialization via serialization delegate");
     }
 
--- a/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/chrono/ChronoLocalDateTimeImpl.java	Wed Jul 05 19:11:53 2017 +0200
@@ -94,7 +94,7 @@
  *
  * @implSpec
  * This class is immutable and thread-safe.
- *
+ * @serial
  * @param <D> the concrete type for the date of this date-time
  * @since 1.8
  */
@@ -157,11 +157,11 @@
     /**
      * The date part.
      */
-    private final D date;
+    private final transient D date;
     /**
      * The time part.
      */
-    private final LocalTime time;
+    private final transient LocalTime time;
 
     //-----------------------------------------------------------------------
     /**
@@ -402,6 +402,18 @@
     }
 
     //-----------------------------------------------------------------------
+    /**
+     * Writes the ChronoLocalDateTime using a
+     * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(2);              // identifies a ChronoLocalDateTime
+     *  out.writeObject(toLocalDate());
+     *  out.witeObject(toLocalTime());
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
     private Object writeReplace() {
         return new Ser(Ser.CHRONO_LOCAL_DATE_TIME_TYPE, this);
     }
@@ -411,7 +423,7 @@
      * @return never
      * @throws InvalidObjectException always
      */
-    private Object readResolve() throws ObjectStreamException {
+    private Object readResolve() throws InvalidObjectException {
         throw new InvalidObjectException("Deserialization via serialization delegate");
     }
 
--- a/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTimeImpl.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/chrono/ChronoZonedDateTimeImpl.java	Wed Jul 05 19:11:53 2017 +0200
@@ -98,6 +98,7 @@
  * @implSpec
  * This class is immutable and thread-safe.
  *
+ * @serial Document the delegation of this class in the serialized-form specification.
  * @param <D> the concrete type for the date of this date-time
  * @since 1.8
  */
@@ -112,15 +113,15 @@
     /**
      * The local date-time.
      */
-    private final ChronoLocalDateTimeImpl<D> dateTime;
+    private final transient ChronoLocalDateTimeImpl<D> dateTime;
     /**
      * The zone offset.
      */
-    private final ZoneOffset offset;
+    private final transient ZoneOffset offset;
     /**
      * The zone ID.
      */
-    private final ZoneId zone;
+    private final transient ZoneId zone;
 
     //-----------------------------------------------------------------------
     /**
@@ -222,6 +223,7 @@
     }
 
     //-----------------------------------------------------------------------
+    @Override
     public ZoneOffset getOffset() {
         return offset;
     }
@@ -256,10 +258,12 @@
         return dateTime;
     }
 
+    @Override
     public ZoneId getZone() {
         return zone;
     }
 
+    @Override
     public ChronoZonedDateTime<D> withZoneSameLocal(ZoneId zone) {
         return ofBest(dateTime, zone, offset);
     }
@@ -321,6 +325,19 @@
     }
 
     //-----------------------------------------------------------------------
+    /**
+     * Writes the ChronoZonedDateTime using a
+     * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(3);                  // identifies a ChronoZonedDateTime
+     *  out.writeObject(toLocalDateTime());
+     *  out.writeObject(getOffset());
+     *  out.writeObject(getZone());
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
     private Object writeReplace() {
         return new Ser(Ser.CHRONO_ZONE_DATE_TIME_TYPE, this);
     }
@@ -330,7 +347,7 @@
      * @return never
      * @throws InvalidObjectException always
      */
-    private Object readResolve() throws ObjectStreamException {
+    private Object readResolve() throws InvalidObjectException {
         throw new InvalidObjectException("Deserialization via serialization delegate");
     }
 
--- a/jdk/src/share/classes/java/time/chrono/Chronology.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/chrono/Chronology.java	Wed Jul 05 19:11:53 2017 +0200
@@ -1258,14 +1258,15 @@
     /**
      * Writes the Chronology using a
      * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+     * @serialData
      * <pre>
-     *  out.writeByte(1);  // identifies this as a Chronology
+     *  out.writeByte(1);  // identifies a Chronology
      *  out.writeUTF(getId());
      * </pre>
      *
      * @return the instance of {@code Ser}, not null
      */
-    protected Object writeReplace() {
+    Object writeReplace() {
         return new Ser(Ser.CHRONO_TYPE, this);
     }
 
@@ -1274,14 +1275,26 @@
      * @return never
      * @throws InvalidObjectException always
      */
-    private Object readResolve() throws ObjectStreamException {
+    private Object readResolve() throws InvalidObjectException {
         throw new InvalidObjectException("Deserialization via serialization delegate");
     }
 
+    /**
+     * Write the Chronology id to the stream.
+     * @param out the output stream
+     * @throws IOException on any error during the write
+     */
     void writeExternal(DataOutput out) throws IOException {
         out.writeUTF(getId());
     }
 
+    /**
+     * Reads the Chronology id and creates the Chronology.
+     * @param in  the input stream
+     * @return  the Chronology
+     * @throws IOException  on errors during the read
+     * @throws DateTimeException if the Chronology cannot be returned
+     */
     static Chronology readExternal(DataInput in) throws IOException {
         String id = in.readUTF();
         return Chronology.of(id);
--- a/jdk/src/share/classes/java/time/chrono/HijrahChronology.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/chrono/HijrahChronology.java	Wed Jul 05 19:11:53 2017 +0200
@@ -63,6 +63,8 @@
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
 import java.io.Serializable;
 import java.security.AccessController;
 import java.security.PrivilegedActionException;
@@ -217,11 +219,11 @@
     /**
      * The Hijrah Calendar id.
      */
-    private final String typeId;
+    private final transient String typeId;
     /**
      * The Hijrah calendarType.
      */
-    private transient final String calendarType;
+    private final transient String calendarType;
     /**
      * Serialization version.
      */
@@ -236,7 +238,7 @@
      * Flag to indicate the initialization of configuration data is complete.
      * @see #checkCalendarInit()
      */
-    private volatile boolean initComplete;
+    private transient volatile boolean initComplete;
     /**
      * Array of epoch days indexed by Hijrah Epoch month.
      * Computed by {@link #loadCalendarData}.
@@ -281,7 +283,7 @@
      * A reference to the properties stored in
      * ${java.home}/lib/calendars.properties
      */
-    private transient final static Properties calendarProperties;
+    private final transient static Properties calendarProperties;
 
     /**
      * Prefix of property names for Hijrah calendar variants.
@@ -1073,4 +1075,30 @@
             throw new IllegalArgumentException("date must be yyyy-MM-dd", ex);
         }
     }
+
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the Chronology using a
+     * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(1);     // identifies a Chronology
+     *  out.writeUTF(getId());
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    @Override
+    Object writeReplace() {
+        return super.writeReplace();
+    }
+
+    /**
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
 }
--- a/jdk/src/share/classes/java/time/chrono/HijrahDate.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/chrono/HijrahDate.java	Wed Jul 05 19:11:53 2017 +0200
@@ -65,6 +65,7 @@
 import static java.time.temporal.ChronoField.YEAR;
 
 import java.io.IOException;
+import java.io.InvalidObjectException;
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
 import java.io.Serializable;
@@ -118,7 +119,7 @@
     /**
      * The Chronology of this HijrahDate.
      */
-    private final HijrahChronology chrono;
+    private final transient HijrahChronology chrono;
     /**
      * The proleptic year.
      */
@@ -600,29 +601,41 @@
     }
 
     //-----------------------------------------------------------------------
+    /**
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    /**
+     * Writes the object using a
+     * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(6);                 // identifies a HijrahDate
+     *  out.writeObject(chrono);          // the HijrahChronology variant
+     *  out.writeInt(get(YEAR));
+     *  out.writeByte(get(MONTH_OF_YEAR));
+     *  out.writeByte(get(DAY_OF_MONTH));
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
     private Object writeReplace() {
         return new Ser(Ser.HIJRAH_DATE_TYPE, this);
     }
 
     void writeExternal(ObjectOutput out) throws IOException {
         // HijrahChronology is implicit in the Hijrah_DATE_TYPE
-        out.writeObject(chrono);
+        out.writeObject(getChronology());
         out.writeInt(get(YEAR));
         out.writeByte(get(MONTH_OF_YEAR));
         out.writeByte(get(DAY_OF_MONTH));
     }
 
-    /**
-     * Replaces the date instance from the stream with a valid one.
-     * ReadExternal has already read the fields and created a new instance
-     * from the data.
-     *
-     * @return the resolved date, never null
-     */
-    private Object readResolve() {
-        return this;
-    }
-
     static HijrahDate readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
         HijrahChronology chrono = (HijrahChronology) in.readObject();
         int year = in.readInt();
--- a/jdk/src/share/classes/java/time/chrono/HijrahEra.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/chrono/HijrahEra.java	Wed Jul 05 19:11:53 2017 +0200
@@ -63,9 +63,6 @@
 
 import static java.time.temporal.ChronoField.ERA;
 
-import java.io.DataInput;
-import java.io.DataOutput;
-import java.io.IOException;
 import java.time.DateTimeException;
 import java.time.temporal.ChronoField;
 import java.time.temporal.TemporalField;
@@ -158,18 +155,4 @@
         return Era.super.range(field);
     }
 
-    //-----------------------------------------------------------------------
-    private Object writeReplace() {
-        return new Ser(Ser.HIJRAH_ERA_TYPE, this);
-    }
-
-    void writeExternal(DataOutput out) throws IOException {
-        out.writeByte(this.getValue());
-    }
-
-    static HijrahEra readExternal(DataInput in) throws IOException {
-        byte eraValue = in.readByte();
-        return HijrahEra.of(eraValue);
-    }
-
 }
--- a/jdk/src/share/classes/java/time/chrono/IsoChronology.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/chrono/IsoChronology.java	Wed Jul 05 19:11:53 2017 +0200
@@ -61,6 +61,8 @@
  */
 package java.time.chrono;
 
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
 import static java.time.temporal.ChronoField.DAY_OF_MONTH;
 import static java.time.temporal.ChronoField.ERA;
 import static java.time.temporal.ChronoField.MONTH_OF_YEAR;
@@ -563,4 +565,29 @@
         return field.range();
     }
 
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the Chronology using a
+     * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(1);     // identifies a Chronology
+     *  out.writeUTF(getId());
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    @Override
+    Object writeReplace() {
+        return super.writeReplace();
+    }
+
+    /**
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
 }
--- a/jdk/src/share/classes/java/time/chrono/JapaneseChronology.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/chrono/JapaneseChronology.java	Wed Jul 05 19:11:53 2017 +0200
@@ -56,6 +56,8 @@
  */
 package java.time.chrono;
 
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
 import static java.time.temporal.ChronoField.DAY_OF_MONTH;
 import static java.time.temporal.ChronoField.DAY_OF_YEAR;
 import static java.time.temporal.ChronoField.ERA;
@@ -503,4 +505,29 @@
         return dateYearDay(era, yoe, doy);  // smart is same as strict
     }
 
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the Chronology using a
+     * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(1);     // identifies a Chronology
+     *  out.writeUTF(getId());
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    @Override
+    Object writeReplace() {
+        return super.writeReplace();
+    }
+
+    /**
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
 }
--- a/jdk/src/share/classes/java/time/chrono/JapaneseDate.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/chrono/JapaneseDate.java	Wed Jul 05 19:11:53 2017 +0200
@@ -69,6 +69,7 @@
 import java.io.DataInput;
 import java.io.DataOutput;
 import java.io.IOException;
+import java.io.InvalidObjectException;
 import java.io.Serializable;
 import java.time.Clock;
 import java.time.DateTimeException;
@@ -129,7 +130,7 @@
     /**
      * The underlying ISO local date.
      */
-    private transient final LocalDate isoDate;
+    private final transient LocalDate isoDate;
     /**
      * The JapaneseEra of this date.
      */
@@ -689,6 +690,28 @@
     }
 
     //-----------------------------------------------------------------------
+    /**
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    /**
+     * Writes the object using a
+     * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(4);                 // identifies a JapaneseDate
+     *  out.writeInt(get(YEAR));
+     *  out.writeByte(get(MONTH_OF_YEAR));
+     *  out.writeByte(get(DAY_OF_MONTH));
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
     private Object writeReplace() {
         return new Ser(Ser.JAPANESE_DATE_TYPE, this);
     }
--- a/jdk/src/share/classes/java/time/chrono/JapaneseEra.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/chrono/JapaneseEra.java	Wed Jul 05 19:11:53 2017 +0200
@@ -104,7 +104,7 @@
     static final sun.util.calendar.Era[] ERA_CONFIG;
 
     /**
-     * The singleton instance for the 'Meiji' era (1868-09-08 - 1912-07-29)
+     * The singleton instance for the 'Meiji' era (1868-01-01 - 1912-07-29)
      * which has the value -1.
      */
     public static final JapaneseEra MEIJI = new JapaneseEra(-1, LocalDate.of(1868, 1, 1));
@@ -155,7 +155,7 @@
      * The era value.
      * @serial
      */
-    private final int eraValue;
+    private final transient int eraValue;
 
     // the first day of the era
     private final transient LocalDate since;
@@ -371,6 +371,17 @@
     }
 
     //-----------------------------------------------------------------------
+    /**
+     * Writes the object using a
+     * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(5);        // identifies a JapaneseEra
+     *  out.writeInt(getValue());
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
     private Object writeReplace() {
         return new Ser(Ser.JAPANESE_ERA_TYPE, this);
     }
--- a/jdk/src/share/classes/java/time/chrono/MinguoChronology.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/chrono/MinguoChronology.java	Wed Jul 05 19:11:53 2017 +0200
@@ -56,6 +56,8 @@
  */
 package java.time.chrono;
 
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
 import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;
 import static java.time.temporal.ChronoField.YEAR;
 
@@ -333,4 +335,29 @@
         return (MinguoDate) super.resolveDate(fieldValues, resolverStyle);
     }
 
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the Chronology using a
+     * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(1);     // identifies a Chronology
+     *  out.writeUTF(getId());
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    @Override
+    Object writeReplace() {
+        return super.writeReplace();
+    }
+
+    /**
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
 }
--- a/jdk/src/share/classes/java/time/chrono/MinguoDate.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/chrono/MinguoDate.java	Wed Jul 05 19:11:53 2017 +0200
@@ -64,6 +64,7 @@
 import java.io.DataInput;
 import java.io.DataOutput;
 import java.io.IOException;
+import java.io.InvalidObjectException;
 import java.io.Serializable;
 import java.time.Clock;
 import java.time.DateTimeException;
@@ -106,7 +107,7 @@
     /**
      * The underlying date.
      */
-    private final LocalDate isoDate;
+    private final transient LocalDate isoDate;
 
     //-----------------------------------------------------------------------
     /**
@@ -448,6 +449,28 @@
     }
 
     //-----------------------------------------------------------------------
+    /**
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    /**
+     * Writes the object using a
+     * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(8);                 // identifies a MinguoDate
+     *  out.writeInt(get(YEAR));
+     *  out.writeByte(get(MONTH_OF_YEAR));
+     *  out.writeByte(get(DAY_OF_MONTH));
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
     private Object writeReplace() {
         return new Ser(Ser.MINGUO_DATE_TYPE, this);
     }
--- a/jdk/src/share/classes/java/time/chrono/MinguoEra.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/chrono/MinguoEra.java	Wed Jul 05 19:11:53 2017 +0200
@@ -61,9 +61,6 @@
  */
 package java.time.chrono;
 
-import java.io.DataInput;
-import java.io.DataOutput;
-import java.io.IOException;
 import java.time.DateTimeException;
 
 /**
@@ -155,18 +152,4 @@
         return ordinal();
     }
 
-    //-----------------------------------------------------------------------
-    private Object writeReplace() {
-        return new Ser(Ser.MINGUO_ERA_TYPE, this);
-    }
-
-    void writeExternal(DataOutput out) throws IOException {
-        out.writeByte(this.getValue());
-    }
-
-    static MinguoEra readExternal(DataInput in) throws IOException {
-        byte eraValue = in.readByte();
-        return MinguoEra.of(eraValue);
-    }
-
 }
--- a/jdk/src/share/classes/java/time/chrono/Ser.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/chrono/Ser.java	Wed Jul 05 19:11:53 2017 +0200
@@ -74,14 +74,14 @@
  * byte flag would be used in order to specify an alternative version of the type format.
  * For example {@code CHRONO_TYPE_VERSION_2 = 21}
  * <p>
- * In order to serialise the object it writes its byte and then calls back to the appropriate class where
- * the serialisation is performed.  In order to deserialise the object it read in the type byte, switching
+ * In order to serialize the object it writes its byte and then calls back to the appropriate class where
+ * the serialization is performed.  In order to deserialize the object it read in the type byte, switching
  * in order to select which class to call back into.
  * <p>
- * The serialisation format is determined on a per class basis.  In the case of field based classes each
+ * The serialization format is determined on a per class basis.  In the case of field based classes each
  * of the fields is written out with an appropriate size format in descending order of the field's size.  For
  * example in the case of {@link LocalDate} year is written before month.  Composite classes, such as
- * {@link LocalDateTime} are serialised as one object.  Enum classes are serialised using the index of their
+ * {@link LocalDateTime} are serialized as one object.  Enum classes are serialized using the index of their
  * element.
  * <p>
  * This class is mutable and should be created once per serialization.
@@ -102,11 +102,8 @@
     static final byte JAPANESE_DATE_TYPE = 4;
     static final byte JAPANESE_ERA_TYPE = 5;
     static final byte HIJRAH_DATE_TYPE = 6;
-    static final byte HIJRAH_ERA_TYPE = 7;
-    static final byte MINGUO_DATE_TYPE = 8;
-    static final byte MINGUO_ERA_TYPE = 9;
-    static final byte THAIBUDDHIST_DATE_TYPE = 10;
-    static final byte THAIBUDDHIST_ERA_TYPE = 11;
+    static final byte MINGUO_DATE_TYPE = 7;
+    static final byte THAIBUDDHIST_DATE_TYPE = 8;
 
     /** The type being serialized. */
     private byte type;
@@ -133,6 +130,24 @@
     //-----------------------------------------------------------------------
     /**
      * Implements the {@code Externalizable} interface to write the object.
+     * @serialData
+     * Each serializable class is mapped to a type that is the first byte
+     * in the stream.  Refer to each class {@code writeReplace}
+     * serialized form for the value of the type and sequence of values for the type.
+     * <ul>
+     * <li><a href="../../../serialized-form.html#java.time.chrono.HijrahChronology">HijrahChronology.writeReplace</a>
+     * <li><a href="../../../serialized-form.html#java.time.chrono.IsoChronology">IsoChronology.writeReplace</a>
+     * <li><a href="../../../serialized-form.html#java.time.chrono.JapaneseChronology">JapaneseChronology.writeReplace</a>
+     * <li><a href="../../../serialized-form.html#java.time.chrono.MinguoChronology">MinguoChronology.writeReplace</a>
+     * <li><a href="../../../serialized-form.html#java.time.chrono.ThaiBuddhistChronology">ThaiBuddhistChronology.writeReplace</a>
+     * <li><a href="../../../serialized-form.html#java.time.chrono.ChronoLocalDateTimeImpl">ChronoLocalDateTime.writeReplace</a>
+     * <li><a href="../../../serialized-form.html#java.time.chrono.ChronoZonedDateTimeImpl">ChronoZonedDateTime.writeReplace</a>
+     * <li><a href="../../../serialized-form.html#java.time.chrono.JapaneseDate">JapaneseDate.writeReplace</a>
+     * <li><a href="../../../serialized-form.html#java.time.chrono.JapaneseEra">JapaneseEra.writeReplace</a>
+     * <li><a href="../../../serialized-form.html#java.time.chrono.HijrahDate">HijrahDate.writeReplace</a>
+     * <li><a href="../../../serialized-form.html#java.time.chrono.MinguoDate">MinguoDate.writeReplace</a>
+     * <li><a href="../../../serialized-form.html#java.time.chrono.ThaiBuddhistDate">ThaiBuddhistDate.writeReplace</a>
+     * </ul>
      *
      * @param out  the data stream to write to, not null
      */
@@ -162,21 +177,12 @@
             case HIJRAH_DATE_TYPE:
                 ((HijrahDate) object).writeExternal(out);
                 break;
-            case HIJRAH_ERA_TYPE:
-                ((HijrahEra) object).writeExternal(out);
-                break;
             case MINGUO_DATE_TYPE:
                 ((MinguoDate) object).writeExternal(out);
                 break;
-            case MINGUO_ERA_TYPE:
-                ((MinguoEra) object).writeExternal(out);
-                break;
             case THAIBUDDHIST_DATE_TYPE:
                 ((ThaiBuddhistDate) object).writeExternal(out);
                 break;
-            case THAIBUDDHIST_ERA_TYPE:
-                ((ThaiBuddhistEra) object).writeExternal(out);
-                break;
             default:
                 throw new InvalidClassException("Unknown serialized type");
         }
@@ -185,8 +191,28 @@
     //-----------------------------------------------------------------------
     /**
      * Implements the {@code Externalizable} interface to read the object.
+     * @serialData
+     * The streamed type and parameters defined by the type's {@code writeReplace}
+     * method are read and passed to the corresponding static factory for the type
+     * to create a new instance.  That instance is returned as the de-serialized
+     * {@code Ser} object.
      *
-     * @param in  the data to read, not null
+     * <ul>
+     * <li><a href="../../../serialized-form.html#java.time.chrono.HijrahChronology">HijrahChronology</a> - Chronology.of(id)
+     * <li><a href="../../../serialized-form.html#java.time.chrono.IsoChronology">IsoChronology</a> - Chronology.of(id)
+     * <li><a href="../../../serialized-form.html#java.time.chrono.JapaneseChronology">JapaneseChronology</a> - Chronology.of(id)
+     * <li><a href="../../../serialized-form.html#java.time.chrono.MinguoChronology">MinguoChronology</a> - Chronology.of(id)
+     * <li><a href="../../../serialized-form.html#java.time.chrono.ThaiBuddhistChronology">ThaiBuddhistChronology</a> - Chronology.of(id)
+     * <li><a href="../../../serialized-form.html#java.time.chrono.ChronoLocalDateTimeImpl">ChronoLocalDateTime</a> - date.atTime(time)
+     * <li><a href="../../../serialized-form.html#java.time.chrono.ChronoZonedDateTimeImpl">ChronoZonedDateTime</a> - dateTime.atZone(offset).withZoneSameLocal(zone)
+     * <li><a href="../../../serialized-form.html#java.time.chrono.JapaneseDate">JapaneseDate</a> - JapaneseChronology.INSTANCE.date(year, month, dayOfMonth)
+     * <li><a href="../../../serialized-form.html#java.time.chrono.JapaneseEra">JapaneseEra</a> - JapaneseEra.of(eraValue)
+     * <li><a href="../../../serialized-form.html#java.time.chrono.HijrahDate">HijrahDate</a> - HijrahChronology chrono.date(year, month, dayOfMonth)
+     * <li><a href="../../../serialized-form.html#java.time.chrono.MinguoDate">MinguoDate</a> - MinguoChronology.INSTANCE.date(year, month, dayOfMonth)
+     * <li><a href="../../../serialized-form.html#java.time.chrono.ThaiBuddhistDate">ThaiBuddhistDate</a> - ThaiBuddhistChronology.INSTANCE.date(year, month, dayOfMonth)
+     * </ul>
+     *
+     * @param in  the data stream to read from, not null
      */
     @Override
     public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
@@ -207,11 +233,8 @@
             case JAPANESE_DATE_TYPE:  return JapaneseDate.readExternal(in);
             case JAPANESE_ERA_TYPE: return JapaneseEra.readExternal(in);
             case HIJRAH_DATE_TYPE: return HijrahDate.readExternal(in);
-            case HIJRAH_ERA_TYPE: return HijrahEra.readExternal(in);
             case MINGUO_DATE_TYPE: return MinguoDate.readExternal(in);
-            case MINGUO_ERA_TYPE: return MinguoEra.readExternal(in);
             case THAIBUDDHIST_DATE_TYPE: return ThaiBuddhistDate.readExternal(in);
-            case THAIBUDDHIST_ERA_TYPE: return ThaiBuddhistEra.readExternal(in);
             default: throw new StreamCorruptedException("Unknown serialized type");
         }
     }
--- a/jdk/src/share/classes/java/time/chrono/ThaiBuddhistChronology.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/chrono/ThaiBuddhistChronology.java	Wed Jul 05 19:11:53 2017 +0200
@@ -56,6 +56,8 @@
  */
 package java.time.chrono;
 
+import java.io.InvalidObjectException;
+import java.io.ObjectStreamException;
 import static java.time.temporal.ChronoField.PROLEPTIC_MONTH;
 import static java.time.temporal.ChronoField.YEAR;
 
@@ -369,4 +371,29 @@
         return (ThaiBuddhistDate) super.resolveDate(fieldValues, resolverStyle);
     }
 
+    //-----------------------------------------------------------------------
+    /**
+     * Writes the Chronology using a
+     * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(1);     // identifies a Chronology
+     *  out.writeUTF(getId());
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
+    @Override
+    Object writeReplace() {
+        return super.writeReplace();
+    }
+
+    /**
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
 }
--- a/jdk/src/share/classes/java/time/chrono/ThaiBuddhistDate.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/chrono/ThaiBuddhistDate.java	Wed Jul 05 19:11:53 2017 +0200
@@ -64,6 +64,7 @@
 import java.io.DataInput;
 import java.io.DataOutput;
 import java.io.IOException;
+import java.io.InvalidObjectException;
 import java.io.Serializable;
 import java.time.Clock;
 import java.time.DateTimeException;
@@ -106,7 +107,7 @@
     /**
      * The underlying date.
      */
-    private final LocalDate isoDate;
+    private final transient LocalDate isoDate;
 
     //-----------------------------------------------------------------------
     /**
@@ -448,6 +449,28 @@
     }
 
     //-----------------------------------------------------------------------
+    /**
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    /**
+     * Writes the object using a
+     * <a href="../../../serialized-form.html#java.time.chrono.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre>
+     *  out.writeByte(10);                // identifies a ThaiBuddhistDate
+     *  out.writeInt(get(YEAR));
+     *  out.writeByte(get(MONTH_OF_YEAR));
+     *  out.writeByte(get(DAY_OF_MONTH));
+     * </pre>
+     *
+     * @return the instance of {@code Ser}, not null
+     */
     private Object writeReplace() {
         return new Ser(Ser.THAIBUDDHIST_DATE_TYPE, this);
     }
--- a/jdk/src/share/classes/java/time/chrono/ThaiBuddhistEra.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/chrono/ThaiBuddhistEra.java	Wed Jul 05 19:11:53 2017 +0200
@@ -61,9 +61,6 @@
  */
 package java.time.chrono;
 
-import java.io.DataInput;
-import java.io.DataOutput;
-import java.io.IOException;
 import java.time.DateTimeException;
 
 /**
@@ -155,18 +152,4 @@
         return ordinal();
     }
 
-    //-----------------------------------------------------------------------
-    private Object writeReplace() {
-        return new Ser(Ser.THAIBUDDHIST_ERA_TYPE, this);
-    }
-
-    void writeExternal(DataOutput out) throws IOException {
-        out.writeByte(this.getValue());
-    }
-
-    static ThaiBuddhistEra readExternal(DataInput in) throws IOException {
-        byte eraValue = in.readByte();
-        return ThaiBuddhistEra.of(eraValue);
-    }
-
 }
--- a/jdk/src/share/classes/java/time/zone/Ser.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/zone/Ser.java	Wed Jul 05 19:11:53 2017 +0200
@@ -119,9 +119,20 @@
     //-----------------------------------------------------------------------
     /**
      * Implements the {@code Externalizable} interface to write the object.
+     * @serialData
+     * Each serializable class is mapped to a type that is the first byte
+     * in the stream.  Refer to each class {@code writeReplace}
+     * serialized form for the value of the type and sequence of values for the type.
+     *
+     * <ul>
+     * <li><a href="../../../serialized-form.html#java.time.zone.ZoneRules">ZoneRules.writeReplace</a>
+     * <li><a href="../../../serialized-form.html#java.time.zone.ZoneOffsetTransition">ZoneOffsetTransition.writeReplace</a>
+     * <li><a href="../../../serialized-form.html#java.time.zone.ZoneOffsetTransitionRule">ZoneOffsetTransitionRule.writeReplace</a>
+     * </ul>
      *
      * @param out  the data stream to write to, not null
      */
+    @Override
     public void writeExternal(ObjectOutput out) throws IOException {
         writeInternal(type, object, out);
     }
@@ -150,9 +161,23 @@
     //-----------------------------------------------------------------------
     /**
      * Implements the {@code Externalizable} interface to read the object.
+     * @serialData
+     * The streamed type and parameters defined by the type's {@code writeReplace}
+     * method are read and passed to the corresponding static factory for the type
+     * to create a new instance.  That instance is returned as the de-serialized
+     * {@code Ser} object.
      *
+     * <ul>
+     * <li><a href="../../../serialized-form.html#java.time.zone.ZoneRules">ZoneRules</a>
+     * - {@code ZoneRules.of(standardTransitions, standardOffsets, savingsInstantTransitions, wallOffsets, lastRules);}
+     * <li><a href="../../../serialized-form.html#java.time.zone.ZoneOffsetTransition">ZoneOffsetTransition</a>
+     * - {@code ;}
+     * <li><a href="../../../serialized-form.html#java.time.zone.ZoneOffsetTransitionRule">ZoneOffsetTransitionRule</a>
+     * - {@code ;}
+     * </ul>
      * @param in  the data to read, not null
      */
+    @Override
     public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
         type = in.readByte();
         object = readInternal(type, in);
--- a/jdk/src/share/classes/java/time/zone/ZoneOffsetTransition.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/zone/ZoneOffsetTransition.java	Wed Jul 05 19:11:53 2017 +0200
@@ -64,6 +64,7 @@
 import java.io.DataInput;
 import java.io.DataOutput;
 import java.io.IOException;
+import java.io.InvalidObjectException;
 import java.io.Serializable;
 import java.time.Duration;
 import java.time.Instant;
@@ -170,8 +171,29 @@
 
     //-----------------------------------------------------------------------
     /**
-     * Uses a serialization delegate.
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    /**
+     * Writes the object using a
+     * <a href="../../../serialized-form.html#java.time.zone.Ser">dedicated serialized form</a>.
+     * @serialData
+     * Refer to the serialized form of
+     * <a href="../../../serialized-form.html#java.time.zone.ZoneRules">ZoneRules.writeReplace</a>
+     * for the encoding of epoch seconds and offsets.
+     * <pre style="font-size:1.0em">{@code
      *
+     *   out.writeByte(2);                // identifies a ZoneOffsetTransition
+     *   out.writeEpochSec(toEpochSecond);
+     *   out.writeOffset(offsetBefore);
+     *   out.writeOfset(offsetAfter);
+     * }
+     * </pre>
      * @return the replacing object, not null
      */
     private Object writeReplace() {
--- a/jdk/src/share/classes/java/time/zone/ZoneOffsetTransitionRule.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/zone/ZoneOffsetTransitionRule.java	Wed Jul 05 19:11:53 2017 +0200
@@ -67,6 +67,7 @@
 import java.io.DataInput;
 import java.io.DataOutput;
 import java.io.IOException;
+import java.io.InvalidObjectException;
 import java.io.Serializable;
 import java.time.DayOfWeek;
 import java.time.LocalDate;
@@ -231,7 +232,56 @@
 
     //-----------------------------------------------------------------------
     /**
-     * Uses a serialization delegate.
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    /**
+     * Writes the object using a
+     * <a href="../../../serialized-form.html#java.time.zone.Ser">dedicated serialized form</a>.
+     * @serialData
+     * Refer to the serialized form of
+     * <a href="../../../serialized-form.html#java.time.zone.ZoneRules">ZoneRules.writeReplace</a>
+     * for the encoding of epoch seconds and offsets.
+     * <pre style="font-size:1.0em">{@code
+     *
+     *      out.writeByte(3);                // identifies a ZoneOffsetTransition
+     *      final int timeSecs = (timeEndOfDay ? 86400 : time.toSecondOfDay());
+     *      final int stdOffset = standardOffset.getTotalSeconds();
+     *      final int beforeDiff = offsetBefore.getTotalSeconds() - stdOffset;
+     *      final int afterDiff = offsetAfter.getTotalSeconds() - stdOffset;
+     *      final int timeByte = (timeSecs % 3600 == 0 ? (timeEndOfDay ? 24 : time.getHour()) : 31);
+     *      final int stdOffsetByte = (stdOffset % 900 == 0 ? stdOffset / 900 + 128 : 255);
+     *      final int beforeByte = (beforeDiff == 0 || beforeDiff == 1800 || beforeDiff == 3600 ? beforeDiff / 1800 : 3);
+     *      final int afterByte = (afterDiff == 0 || afterDiff == 1800 || afterDiff == 3600 ? afterDiff / 1800 : 3);
+     *      final int dowByte = (dow == null ? 0 : dow.getValue());
+     *      int b = (month.getValue() << 28) +          // 4 bits
+     *              ((dom + 32) << 22) +                // 6 bits
+     *              (dowByte << 19) +                   // 3 bits
+     *              (timeByte << 14) +                  // 5 bits
+     *              (timeDefinition.ordinal() << 12) +  // 2 bits
+     *              (stdOffsetByte << 4) +              // 8 bits
+     *              (beforeByte << 2) +                 // 2 bits
+     *              afterByte;                          // 2 bits
+     *      out.writeInt(b);
+     *      if (timeByte == 31) {
+     *          out.writeInt(timeSecs);
+     *      }
+     *      if (stdOffsetByte == 255) {
+     *          out.writeInt(stdOffset);
+     *      }
+     *      if (beforeByte == 3) {
+     *          out.writeInt(offsetBefore.getTotalSeconds());
+     *      }
+     *      if (afterByte == 3) {
+     *          out.writeInt(offsetAfter.getTotalSeconds());
+     *      }
+     * }
+     * </pre>
      *
      * @return the replacing object, not null
      */
--- a/jdk/src/share/classes/java/time/zone/ZoneRules.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/time/zone/ZoneRules.java	Wed Jul 05 19:11:53 2017 +0200
@@ -64,6 +64,7 @@
 import java.io.DataInput;
 import java.io.DataOutput;
 import java.io.IOException;
+import java.io.InvalidObjectException;
 import java.io.Serializable;
 import java.time.Duration;
 import java.time.Instant;
@@ -145,7 +146,7 @@
     /**
      * The map of recent transitions.
      */
-    private final ConcurrentMap<Integer, ZoneOffsetTransition[]> lastRulesCache =
+    private final transient ConcurrentMap<Integer, ZoneOffsetTransition[]> lastRulesCache =
                 new ConcurrentHashMap<Integer, ZoneOffsetTransition[]>();
     /**
      * The zero-length long array.
@@ -315,8 +316,74 @@
     }
 
     /**
-     * Uses a serialization delegate.
+     * Defend against malicious streams.
+     * @return never
+     * @throws InvalidObjectException always
+     */
+    private Object readResolve() throws InvalidObjectException {
+        throw new InvalidObjectException("Deserialization via serialization delegate");
+    }
+
+    /**
+     * Writes the object using a
+     * <a href="../../../serialized-form.html#java.time.zone.Ser">dedicated serialized form</a>.
+     * @serialData
+     * <pre style="font-size:1.0em">{@code
      *
+     *   out.writeByte(1);  // identifies a ZoneRules
+     *   out.writeInt(standardTransitions.length);
+     *   for (long trans : standardTransitions) {
+     *       Ser.writeEpochSec(trans, out);
+     *   }
+     *   for (ZoneOffset offset : standardOffsets) {
+     *       Ser.writeOffset(offset, out);
+     *   }
+     *   out.writeInt(savingsInstantTransitions.length);
+     *   for (long trans : savingsInstantTransitions) {
+     *       Ser.writeEpochSec(trans, out);
+     *   }
+     *   for (ZoneOffset offset : wallOffsets) {
+     *       Ser.writeOffset(offset, out);
+     *   }
+     *   out.writeByte(lastRules.length);
+     *   for (ZoneOffsetTransitionRule rule : lastRules) {
+     *       rule.writeExternal(out);
+     *   }
+     * }
+     * </pre>
+     * <p>
+     * Epoch second values used for offsets are encoded in a variable
+     * length form to make the common cases put fewer bytes in the stream.
+     * <pre style="font-size:1.0em">{@code
+     *
+     *  static void writeEpochSec(long epochSec, DataOutput out) throws IOException {
+     *     if (epochSec >= -4575744000L && epochSec < 10413792000L && epochSec % 900 == 0) {  // quarter hours between 1825 and 2300
+     *         int store = (int) ((epochSec + 4575744000L) / 900);
+     *         out.writeByte((store >>> 16) & 255);
+     *         out.writeByte((store >>> 8) & 255);
+     *         out.writeByte(store & 255);
+     *      } else {
+     *          out.writeByte(255);
+     *          out.writeLong(epochSec);
+     *      }
+     *  }
+     * }
+     * </pre>
+     * <p>
+     * ZoneOffset values are encoded in a variable length form so the
+     * common cases put fewer bytes in the stream.
+     * <pre style="font-size:1.0em">{@code
+     *
+     *  static void writeOffset(ZoneOffset offset, DataOutput out) throws IOException {
+     *     final int offsetSecs = offset.getTotalSeconds();
+     *     int offsetByte = offsetSecs % 900 == 0 ? offsetSecs / 900 : 127;  // compress to -72 to +72
+     *     out.writeByte(offsetByte);
+     *     if (offsetByte == 127) {
+     *         out.writeInt(offsetSecs);
+     *     }
+     * }
+     *}
+     * </pre>
      * @return the replacing object, not null
      */
     private Object writeReplace() {
--- a/jdk/src/share/classes/java/util/Collection.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/Collection.java	Wed Jul 05 19:11:53 2017 +0200
@@ -549,6 +549,7 @@
      * @return a {@code Spliterator} over the elements in this collection
      * @since 1.8
      */
+    @Override
     default Spliterator<E> spliterator() {
         return Spliterators.spliterator(this, 0);
     }
--- a/jdk/src/share/classes/java/util/Collections.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/Collections.java	Wed Jul 05 19:11:53 2017 +0200
@@ -3900,6 +3900,7 @@
                 return batchRemove(c, true);
             }
             private boolean batchRemove(Collection<?> c, boolean complement) {
+                Objects.requireNonNull(c);
                 boolean modified = false;
                 Iterator<Map.Entry<K,V>> it = iterator();
                 while (it.hasNext()) {
--- a/jdk/src/share/classes/java/util/Comparator.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/Comparator.java	Wed Jul 05 19:11:53 2017 +0200
@@ -230,7 +230,7 @@
      * @param  keyComparator the {@code Comparator} used to compare the sort key
      * @return a lexicographic-order comparator composed of this comparator
      *         and then comparing on the key extracted by the keyExtractor function
-     * @throws NullPointerException if the argument is null.
+     * @throws NullPointerException if either argument is null.
      * @see #comparing(Function, Comparator)
      * @see #thenComparing(Comparator)
      * @since 1.8
--- a/jdk/src/share/classes/java/util/HashMap.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/HashMap.java	Wed Jul 05 19:11:53 2017 +0200
@@ -25,13 +25,14 @@
 
 package java.util;
 
-import java.io.*;
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.io.Serializable;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
-import java.util.concurrent.ThreadLocalRandom;
 import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
 import java.util.function.Consumer;
-import java.util.function.BiFunction;
 import java.util.function.Function;
 
 /**
@@ -63,20 +64,25 @@
  * structures are rebuilt) so that the hash table has approximately twice the
  * number of buckets.
  *
- * <p>As a general rule, the default load factor (.75) offers a good tradeoff
- * between time and space costs.  Higher values decrease the space overhead
- * but increase the lookup cost (reflected in most of the operations of the
- * <tt>HashMap</tt> class, including <tt>get</tt> and <tt>put</tt>).  The
- * expected number of entries in the map and its load factor should be taken
- * into account when setting its initial capacity, so as to minimize the
- * number of rehash operations.  If the initial capacity is greater
- * than the maximum number of entries divided by the load factor, no
- * rehash operations will ever occur.
+ * <p>As a general rule, the default load factor (.75) offers a good
+ * tradeoff between time and space costs.  Higher values decrease the
+ * space overhead but increase the lookup cost (reflected in most of
+ * the operations of the <tt>HashMap</tt> class, including
+ * <tt>get</tt> and <tt>put</tt>).  The expected number of entries in
+ * the map and its load factor should be taken into account when
+ * setting its initial capacity, so as to minimize the number of
+ * rehash operations.  If the initial capacity is greater than the
+ * maximum number of entries divided by the load factor, no rehash
+ * operations will ever occur.
  *
- * <p>If many mappings are to be stored in a <tt>HashMap</tt> instance,
- * creating it with a sufficiently large capacity will allow the mappings to
- * be stored more efficiently than letting it perform automatic rehashing as
- * needed to grow the table.
+ * <p>If many mappings are to be stored in a <tt>HashMap</tt>
+ * instance, creating it with a sufficiently large capacity will allow
+ * the mappings to be stored more efficiently than letting it perform
+ * automatic rehashing as needed to grow the table.  Note that using
+ * many keys with the same {@code hashCode()} is a sure way to slow
+ * down performance of any hash table. To ameliorate impact, when keys
+ * are {@link Comparable}, this class may use comparison order among
+ * keys to help break ties.
  *
  * <p><strong>Note that this implementation is not synchronized.</strong>
  * If multiple threads access a hash map concurrently, and at least one of
@@ -128,11 +134,100 @@
  * @see     Hashtable
  * @since   1.2
  */
+public class HashMap<K,V> extends AbstractMap<K,V>
+    implements Map<K,V>, Cloneable, Serializable {
 
-public class HashMap<K,V>
-        extends AbstractMap<K,V>
-    implements Map<K,V>, Cloneable, Serializable
-{
+    private static final long serialVersionUID = 362498820763181265L;
+
+    /*
+     * Implementation notes.
+     *
+     * This map usually acts as a binned (bucketed) hash table, but
+     * when bins get too large, they are transformed into bins of
+     * TreeNodes, each structured similarly to those in
+     * java.util.TreeMap. Most methods try to use normal bins, but
+     * relay to TreeNode methods when applicable (simply by checking
+     * instanceof a node).  Bins of TreeNodes may be traversed and
+     * used like any others, but additionally support faster lookup
+     * when overpopulated. However, since the vast majority of bins in
+     * normal use are not overpopulated, checking for existence of
+     * tree bins may be delayed in the course of table methods.
+     *
+     * Tree bins (i.e., bins whose elements are all TreeNodes) are
+     * ordered primarily by hashCode, but in the case of ties, if two
+     * elements are of the same "class C implements Comparable<C>",
+     * type then their compareTo method is used for ordering. (We
+     * conservatively check generic types via reflection to validate
+     * this -- see method comparableClassFor).  The added complexity
+     * of tree bins is worthwhile in providing worst-case O(log n)
+     * operations when keys either have distinct hashes or are
+     * orderable, Thus, performance degrades gracefully under
+     * accidental or malicious usages in which hashCode() methods
+     * return values that are poorly distributed, as well as those in
+     * which many keys share a hashCode, so long as they are also
+     * Comparable. (If neither of these apply, we may waste about a
+     * factor of two in time and space compared to taking no
+     * precautions. But the only known cases stem from poor user
+     * programming practices that are already so slow that this makes
+     * little difference.)
+     *
+     * Because TreeNodes are about twice the size of regular nodes, we
+     * use them only when bins contain enough nodes to warrant use
+     * (see TREEIFY_THRESHOLD). And when they become too small (due to
+     * removal or resizing) they are converted back to plain bins.  In
+     * usages with well-distributed user hashCodes, tree bins are
+     * rarely used.  Ideally, under random hashCodes, the frequency of
+     * nodes in bins follows a Poisson distribution
+     * (http://en.wikipedia.org/wiki/Poisson_distribution) with a
+     * parameter of about 0.5 on average for the default resizing
+     * threshold of 0.75, although with a large variance because of
+     * resizing granularity. Ignoring variance, the expected
+     * occurrences of list size k are (exp(-0.5) * pow(0.5, k) /
+     * factorial(k)). The first values are:
+     *
+     * 0:    0.60653066
+     * 1:    0.30326533
+     * 2:    0.07581633
+     * 3:    0.01263606
+     * 4:    0.00157952
+     * 5:    0.00015795
+     * 6:    0.00001316
+     * 7:    0.00000094
+     * 8:    0.00000006
+     * more: less than 1 in ten million
+     *
+     * The root of a tree bin is normally its first node.  However,
+     * sometimes (currently only upon Iterator.remove), the root might
+     * be elsewhere, but can be recovered following parent links
+     * (method TreeNode.root()).
+     *
+     * All applicable internal methods accept a hash code as an
+     * argument (as normally supplied from a public method), allowing
+     * them to call each other without recomputing user hashCodes.
+     * Most internal methods also accept a "tab" argument, that is
+     * normally the current table, but may be a new or old one when
+     * resizing or converting.
+     *
+     * When bin lists are treeified, split, or untreeified, we keep
+     * them in the same relative access/traversal order (i.e., field
+     * Node.next) to better preserve locality, and to slightly
+     * simplify handling of splits and traversals that invoke
+     * iterator.remove. When using comparators on insertion, to keep a
+     * total ordering (or as close as is required here) across
+     * rebalancings, we compare classes and identityHashCodes as
+     * tie-breakers.
+     *
+     * The use and transitions among plain vs tree modes is
+     * complicated by the existence of subclass LinkedHashMap. See
+     * below for hook methods defined to be invoked upon insertion,
+     * removal and access that allow LinkedHashMap internals to
+     * otherwise remain independent of these mechanics. (This also
+     * requires that a map instance be passed to some utility methods
+     * that may create new nodes.)
+     *
+     * The concurrent-programming-like SSA-based coding style helps
+     * avoid aliasing errors amid all of the twisty pointer operations.
+     */
 
     /**
      * The default initial capacity - MUST be a power of two.
@@ -152,14 +247,158 @@
     static final float DEFAULT_LOAD_FACTOR = 0.75f;
 
     /**
-     * An empty table instance to share when the table is not inflated.
+     * The bin count threshold for using a tree rather than list for a
+     * bin.  Bins are converted to trees when adding an element to a
+     * bin with at least this many nodes. The value must be greater
+     * than 2 and should be at least 8 to mesh with assumptions in
+     * tree removal about conversion back to plain bins upon
+     * shrinkage.
+     */
+    static final int TREEIFY_THRESHOLD = 8;
+
+    /**
+     * The bin count threshold for untreeifying a (split) bin during a
+     * resize operation. Should be less than TREEIFY_THRESHOLD, and at
+     * most 6 to mesh with shrinkage detection under removal.
+     */
+    static final int UNTREEIFY_THRESHOLD = 6;
+
+    /**
+     * The smallest table capacity for which bins may be treeified.
+     * (Otherwise the table is resized if too many nodes in a bin.)
+     * Should be at least 4 * TREEIFY_THRESHOLD to avoid conflicts
+     * between resizing and treeification thresholds.
+     */
+    static final int MIN_TREEIFY_CAPACITY = 64;
+
+    /**
+     * Basic hash bin node, used for most entries.  (See below for
+     * TreeNode subclass, and in LinkedHashMap for its Entry subclass.)
      */
-    static final Object[] EMPTY_TABLE = {};
+    static class Node<K,V> implements Map.Entry<K,V> {
+        final int hash;
+        final K key;
+        V value;
+        Node<K,V> next;
+
+        Node(int hash, K key, V value, Node<K,V> next) {
+            this.hash = hash;
+            this.key = key;
+            this.value = value;
+            this.next = next;
+        }
+
+        public final K getKey()        { return key; }
+        public final V getValue()      { return value; }
+        public final String toString() { return key + "=" + value; }
+
+        public final int hashCode() {
+            return Objects.hashCode(key) ^ Objects.hashCode(value);
+        }
+
+        public final V setValue(V newValue) {
+            V oldValue = value;
+            value = newValue;
+            return oldValue;
+        }
+
+        public final boolean equals(Object o) {
+            if (o == this)
+                return true;
+            if (o instanceof Map.Entry) {
+                Map.Entry<?,?> e = (Map.Entry<?,?>)o;
+                if (Objects.equals(key, e.getKey()) &&
+                    Objects.equals(value, e.getValue()))
+                    return true;
+            }
+            return false;
+        }
+    }
+
+    /* ---------------- Static utilities -------------- */
 
     /**
-     * The table, resized as necessary. Length MUST Always be a power of two.
+     * Computes key.hashCode() and spreads (XORs) higher bits of hash
+     * to lower.  Because the table uses power-of-two masking, sets of
+     * hashes that vary only in bits above the current mask will
+     * always collide. (Among known examples are sets of Float keys
+     * holding consecutive whole numbers in small tables.)  So we
+     * apply a transform that spreads the impact of higher bits
+     * downward. There is a tradeoff between speed, utility, and
+     * quality of bit-spreading. Because many common sets of hashes
+     * are already reasonably distributed (so don't benefit from
+     * spreading), and because we use trees to handle large sets of
+     * collisions in bins, we just XOR some shifted bits in the
+     * cheapest possible way to reduce systematic lossage, as well as
+     * to incorporate impact of the highest bits that would otherwise
+     * never be used in index calculations because of table bounds.
+     */
+    static final int hash(Object key) {
+        int h;
+        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
+    }
+
+    /**
+     * Returns x's Class if it is of the form "class C implements
+     * Comparable<C>", else null.
      */
-    transient Object[] table = EMPTY_TABLE;
+    static Class<?> comparableClassFor(Object x) {
+        if (x instanceof Comparable) {
+            Class<?> c; Type[] ts, as; Type t; ParameterizedType p;
+            if ((c = x.getClass()) == String.class) // bypass checks
+                return c;
+            if ((ts = c.getGenericInterfaces()) != null) {
+                for (int i = 0; i < ts.length; ++i) {
+                    if (((t = ts[i]) instanceof ParameterizedType) &&
+                        ((p = (ParameterizedType)t).getRawType() ==
+                         Comparable.class) &&
+                        (as = p.getActualTypeArguments()) != null &&
+                        as.length == 1 && as[0] == c) // type arg is c
+                        return c;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns k.compareTo(x) if x matches kc (k's screened comparable
+     * class), else 0.
+     */
+    @SuppressWarnings({"rawtypes","unchecked"}) // for cast to Comparable
+    static int compareComparables(Class<?> kc, Object k, Object x) {
+        return (x == null || x.getClass() != kc ? 0 :
+                ((Comparable)k).compareTo(x));
+    }
+
+    /**
+     * Returns a power of two size for the given target capacity.
+     */
+    static final int tableSizeFor(int cap) {
+        int n = cap - 1;
+        n |= n >>> 1;
+        n |= n >>> 2;
+        n |= n >>> 4;
+        n |= n >>> 8;
+        n |= n >>> 16;
+        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
+    }
+
+    /* ---------------- Fields -------------- */
+
+    /**
+     * The table, initialized on first use, and resized as
+     * necessary. When allocated, length is always a power of two.
+     * (We also tolerate length zero in some operations to allow
+     * bootstrapping mechanics that are currently not needed.)
+     */
+    transient Node<K,V>[] table;
+
+    /**
+     * Holds cached entrySet(). Note that AbstractMap fields are used
+     * for keySet() and values().
+     */
+    transient Set<Map.Entry<K,V>> entrySet;
 
     /**
      * The number of key-value mappings contained in this map.
@@ -167,21 +406,6 @@
     transient int size;
 
     /**
-     * The next size value at which to resize (capacity * load factor).
-     * @serial
-     */
-    // If table == EMPTY_TABLE then this is the initial capacity at which the
-    // table will be created when inflated.
-    int threshold;
-
-    /**
-     * The load factor for the hash table.
-     *
-     * @serial
-     */
-    final float loadFactor;
-
-    /**
      * The number of times this HashMap has been structurally modified
      * Structural modifications are those that change the number of mappings in
      * the HashMap or otherwise modify its internal structure (e.g.,
@@ -191,627 +415,24 @@
     transient int modCount;
 
     /**
-     * Holds values which can't be initialized until after VM is booted.
+     * The next size value at which to resize (capacity * load factor).
+     *
+     * @serial
      */
-    private static class Holder {
-        static final sun.misc.Unsafe UNSAFE;
-
-        /**
-         * Offset of "final" hashSeed field we must set in
-         * readObject() method.
-         */
-        static final long HASHSEED_OFFSET;
-
-        static final boolean USE_HASHSEED;
-
-        static {
-            String hashSeedProp = java.security.AccessController.doPrivileged(
-                    new sun.security.action.GetPropertyAction(
-                        "jdk.map.useRandomSeed"));
-            boolean localBool = (null != hashSeedProp)
-                    ? Boolean.parseBoolean(hashSeedProp) : false;
-            USE_HASHSEED = localBool;
-
-            if (USE_HASHSEED) {
-                try {
-                    UNSAFE = sun.misc.Unsafe.getUnsafe();
-                    HASHSEED_OFFSET = UNSAFE.objectFieldOffset(
-                        HashMap.class.getDeclaredField("hashSeed"));
-                } catch (NoSuchFieldException | SecurityException e) {
-                    throw new InternalError("Failed to record hashSeed offset", e);
-                }
-            } else {
-                UNSAFE = null;
-                HASHSEED_OFFSET = 0;
-            }
-        }
-    }
-
-    /*
-     * A randomizing value associated with this instance that is applied to
-     * hash code of keys to make hash collisions harder to find.
-     *
-     * Non-final so it can be set lazily, but be sure not to set more than once.
-     */
-    transient final int hashSeed;
-
-    /*
-     * TreeBin/TreeNode code from CHM doesn't handle the null key.  Store the
-     * null key entry here.
-     */
-    transient Entry<K,V> nullKeyEntry = null;
-
-    /*
-     * In order to improve performance under high hash-collision conditions,
-     * HashMap will switch to storing a bin's entries in a balanced tree
-     * (TreeBin) instead of a linked-list once the number of entries in the bin
-     * passes a certain threshold (TreeBin.TREE_THRESHOLD), if at least one of
-     * the keys in the bin implements Comparable.  This technique is borrowed
-     * from ConcurrentHashMap.
-     */
-
-    /*
-     * Code based on CHMv8
-     *
-     * Node type for TreeBin
-     */
-    final static class TreeNode<K,V> {
-        TreeNode parent;  // red-black tree links
-        TreeNode left;
-        TreeNode right;
-        TreeNode prev;    // needed to unlink next upon deletion
-        boolean red;
-        final HashMap.Entry<K,V> entry;
-
-        TreeNode(HashMap.Entry<K,V> entry, Object next, TreeNode parent) {
-            this.entry = entry;
-            this.entry.next = next;
-            this.parent = parent;
-        }
-    }
+    // (The javadoc description is true upon serialization.
+    // Additionally, if the table array has not been allocated, this
+    // field holds the initial array capacity, or zero signifying
+    // DEFAULT_INITIAL_CAPACITY.)
+    int threshold;
 
     /**
-     * Returns a Class for the given object of the form "class C
-     * implements Comparable<C>", if one exists, else null.  See the TreeBin
-     * docs, below, for explanation.
-     */
-    static Class<?> comparableClassFor(Object x) {
-        Class<?> c, s, cmpc; Type[] ts, as; Type t; ParameterizedType p;
-        if ((c = x.getClass()) == String.class) // bypass checks
-            return c;
-        if ((cmpc = Comparable.class).isAssignableFrom(c)) {
-            while (cmpc.isAssignableFrom(s = c.getSuperclass()))
-                c = s; // find topmost comparable class
-            if ((ts  = c.getGenericInterfaces()) != null) {
-                for (int i = 0; i < ts.length; ++i) {
-                    if (((t = ts[i]) instanceof ParameterizedType) &&
-                        ((p = (ParameterizedType)t).getRawType() == cmpc) &&
-                        (as = p.getActualTypeArguments()) != null &&
-                        as.length == 1 && as[0] == c) // type arg is c
-                        return c;
-                }
-            }
-        }
-        return null;
-    }
-
-    /*
-     * Code based on CHMv8
+     * The load factor for the hash table.
      *
-     * A specialized form of red-black tree for use in bins
-     * whose size exceeds a threshold.
-     *
-     * TreeBins use a special form of comparison for search and
-     * related operations (which is the main reason we cannot use
-     * existing collections such as TreeMaps). TreeBins contain
-     * Comparable elements, but may contain others, as well as
-     * elements that are Comparable but not necessarily Comparable<T>
-     * for the same T, so we cannot invoke compareTo among them. To
-     * handle this, the tree is ordered primarily by hash value, then
-     * by Comparable.compareTo order if applicable.  On lookup at a
-     * node, if elements are not comparable or compare as 0 then both
-     * left and right children may need to be searched in the case of
-     * tied hash values. (This corresponds to the full list search
-     * that would be necessary if all elements were non-Comparable and
-     * had tied hashes.)  The red-black balancing code is updated from
-     * pre-jdk-collections
-     * (http://gee.cs.oswego.edu/dl/classes/collections/RBCell.java)
-     * based in turn on Cormen, Leiserson, and Rivest "Introduction to
-     * Algorithms" (CLR).
+     * @serial
      */
-    final class TreeBin {
-        /*
-         * The bin count threshold for using a tree rather than list for a bin. The
-         * value reflects the approximate break-even point for using tree-based
-         * operations.
-         */
-        static final int TREE_THRESHOLD = 16;
-
-        TreeNode<K,V> root;  // root of tree
-        TreeNode<K,V> first; // head of next-pointer list
-
-        /*
-         * Split a TreeBin into lo and hi parts and install in given table.
-         *
-         * Existing Entrys are re-used, which maintains the before/after links for
-         * LinkedHashMap.Entry.
-         *
-         * No check for Comparable, though this is the same as CHM.
-         */
-        final void splitTreeBin(Object[] newTable, int i, TreeBin loTree, TreeBin hiTree) {
-            TreeBin oldTree = this;
-            int bit = newTable.length >>> 1;
-            int loCount = 0, hiCount = 0;
-            TreeNode<K,V> e = oldTree.first;
-            TreeNode<K,V> next;
-
-            // This method is called when the table has just increased capacity,
-            // so indexFor() is now taking one additional bit of hash into
-            // account ("bit").  Entries in this TreeBin now belong in one of
-            // two bins, "i" or "i+bit", depending on if the new top bit of the
-            // hash is set.  The trees for the two bins are loTree and hiTree.
-            // If either tree ends up containing fewer than TREE_THRESHOLD
-            // entries, it is converted back to a linked list.
-            while (e != null) {
-                // Save entry.next - it will get overwritten in putTreeNode()
-                next = (TreeNode<K,V>)e.entry.next;
-
-                int h = e.entry.hash;
-                K k = (K) e.entry.key;
-                V v = e.entry.value;
-                if ((h & bit) == 0) {
-                    ++loCount;
-                    // Re-using e.entry
-                    loTree.putTreeNode(h, k, v, e.entry);
-                } else {
-                    ++hiCount;
-                    hiTree.putTreeNode(h, k, v, e.entry);
-                }
-                // Iterate using the saved 'next'
-                e = next;
-            }
-            if (loCount < TREE_THRESHOLD) { // too small, convert back to list
-                HashMap.Entry loEntry = null;
-                TreeNode<K,V> p = loTree.first;
-                while (p != null) {
-                    @SuppressWarnings("unchecked")
-                    TreeNode<K,V> savedNext = (TreeNode<K,V>) p.entry.next;
-                    p.entry.next = loEntry;
-                    loEntry = p.entry;
-                    p = savedNext;
-                }
-                // assert newTable[i] == null;
-                newTable[i] = loEntry;
-            } else {
-                // assert newTable[i] == null;
-                newTable[i] = loTree;
-            }
-            if (hiCount < TREE_THRESHOLD) { // too small, convert back to list
-                HashMap.Entry hiEntry = null;
-                TreeNode<K,V> p = hiTree.first;
-                while (p != null) {
-                    @SuppressWarnings("unchecked")
-                    TreeNode<K,V> savedNext = (TreeNode<K,V>) p.entry.next;
-                    p.entry.next = hiEntry;
-                    hiEntry = p.entry;
-                    p = savedNext;
-                }
-                // assert newTable[i + bit] == null;
-                newTable[i + bit] = hiEntry;
-            } else {
-                // assert newTable[i + bit] == null;
-                newTable[i + bit] = hiTree;
-            }
-        }
-
-        /*
-         * Popuplate the TreeBin with entries from the linked list e
-         *
-         * Assumes 'this' is a new/empty TreeBin
-         *
-         * Note: no check for Comparable
-         * Note: I believe this changes iteration order
-         */
-        @SuppressWarnings("unchecked")
-        void populate(HashMap.Entry e) {
-            // assert root == null;
-            // assert first == null;
-            HashMap.Entry next;
-            while (e != null) {
-                // Save entry.next - it will get overwritten in putTreeNode()
-                next = (HashMap.Entry)e.next;
-                // Re-using Entry e will maintain before/after in LinkedHM
-                putTreeNode(e.hash, (K)e.key, (V)e.value, e);
-                // Iterate using the saved 'next'
-                e = next;
-            }
-        }
-
-        /**
-         * Copied from CHMv8
-         * From CLR
-         */
-        private void rotateLeft(TreeNode p) {
-            if (p != null) {
-                TreeNode r = p.right, pp, rl;
-                if ((rl = p.right = r.left) != null) {
-                    rl.parent = p;
-                }
-                if ((pp = r.parent = p.parent) == null) {
-                    root = r;
-                } else if (pp.left == p) {
-                    pp.left = r;
-                } else {
-                    pp.right = r;
-                }
-                r.left = p;
-                p.parent = r;
-            }
-        }
-
-        /**
-         * Copied from CHMv8
-         * From CLR
-         */
-        private void rotateRight(TreeNode p) {
-            if (p != null) {
-                TreeNode l = p.left, pp, lr;
-                if ((lr = p.left = l.right) != null) {
-                    lr.parent = p;
-                }
-                if ((pp = l.parent = p.parent) == null) {
-                    root = l;
-                } else if (pp.right == p) {
-                    pp.right = l;
-                } else {
-                    pp.left = l;
-                }
-                l.right = p;
-                p.parent = l;
-            }
-        }
-
-        /**
-         * Returns the TreeNode (or null if not found) for the given
-         * key.  A front-end for recursive version.
-         */
-        final TreeNode getTreeNode(int h, K k) {
-            return getTreeNode(h, k, root, comparableClassFor(k));
-        }
-
-        /**
-         * Returns the TreeNode (or null if not found) for the given key
-         * starting at given root.
-         */
-        @SuppressWarnings("unchecked")
-        final TreeNode getTreeNode (int h, K k, TreeNode p, Class<?> cc) {
-            // assert k != null;
-            while (p != null) {
-                int dir, ph;  Object pk;
-                if ((ph = p.entry.hash) != h)
-                    dir = (h < ph) ? -1 : 1;
-                else if ((pk = p.entry.key) == k || k.equals(pk))
-                    return p;
-                else if (cc == null || comparableClassFor(pk) != cc ||
-                         (dir = ((Comparable<Object>)k).compareTo(pk)) == 0) {
-                    // assert pk != null;
-                    TreeNode r, pl, pr; // check both sides
-                    if ((pr = p.right) != null &&
-                        (r = getTreeNode(h, k, pr, cc)) != null)
-                        return r;
-                    else if ((pl = p.left) != null)
-                        dir = -1;
-                    else // nothing there
-                        break;
-                }
-                p = (dir > 0) ? p.right : p.left;
-            }
-            return null;
-        }
+    final float loadFactor;
 
-        /*
-         * Finds or adds a node.
-         *
-         * 'entry' should be used to recycle an existing Entry (e.g. in the case
-         * of converting a linked-list bin to a TreeBin).
-         * If entry is null, a new Entry will be created for the new TreeNode
-         *
-         * @return the TreeNode containing the mapping, or null if a new
-         * TreeNode was added
-         */
-        @SuppressWarnings("unchecked")
-        TreeNode putTreeNode(int h, K k, V v, HashMap.Entry<K,V> entry) {
-            // assert k != null;
-            //if (entry != null) {
-                // assert h == entry.hash;
-                // assert k == entry.key;
-                // assert v == entry.value;
-            // }
-            Class<?> cc = comparableClassFor(k);
-            TreeNode pp = root, p = null;
-            int dir = 0;
-            while (pp != null) { // find existing node or leaf to insert at
-                int ph;  Object pk;
-                p = pp;
-                if ((ph = p.entry.hash) != h)
-                    dir = (h < ph) ? -1 : 1;
-                else if ((pk = p.entry.key) == k || k.equals(pk))
-                    return p;
-                else if (cc == null || comparableClassFor(pk) != cc ||
-                         (dir = ((Comparable<Object>)k).compareTo(pk)) == 0) {
-                    TreeNode r, pr;
-                    if ((pr = p.right) != null &&
-                        (r = getTreeNode(h, k, pr, cc)) != null)
-                        return r;
-                    else // continue left
-                        dir = -1;
-                }
-                pp = (dir > 0) ? p.right : p.left;
-            }
-
-            // Didn't find the mapping in the tree, so add it
-            TreeNode f = first;
-            TreeNode x;
-            if (entry != null) {
-                x = new TreeNode(entry, f, p);
-            } else {
-                x = new TreeNode(newEntry(h, k, v, null), f, p);
-            }
-            first = x;
-
-            if (p == null) {
-                root = x;
-            } else { // attach and rebalance; adapted from CLR
-                TreeNode xp, xpp;
-                if (f != null) {
-                    f.prev = x;
-                }
-                if (dir <= 0) {
-                    p.left = x;
-                } else {
-                    p.right = x;
-                }
-                x.red = true;
-                while (x != null && (xp = x.parent) != null && xp.red
-                        && (xpp = xp.parent) != null) {
-                    TreeNode xppl = xpp.left;
-                    if (xp == xppl) {
-                        TreeNode y = xpp.right;
-                        if (y != null && y.red) {
-                            y.red = false;
-                            xp.red = false;
-                            xpp.red = true;
-                            x = xpp;
-                        } else {
-                            if (x == xp.right) {
-                                rotateLeft(x = xp);
-                                xpp = (xp = x.parent) == null ? null : xp.parent;
-                            }
-                            if (xp != null) {
-                                xp.red = false;
-                                if (xpp != null) {
-                                    xpp.red = true;
-                                    rotateRight(xpp);
-                                }
-                            }
-                        }
-                    } else {
-                        TreeNode y = xppl;
-                        if (y != null && y.red) {
-                            y.red = false;
-                            xp.red = false;
-                            xpp.red = true;
-                            x = xpp;
-                        } else {
-                            if (x == xp.left) {
-                                rotateRight(x = xp);
-                                xpp = (xp = x.parent) == null ? null : xp.parent;
-                            }
-                            if (xp != null) {
-                                xp.red = false;
-                                if (xpp != null) {
-                                    xpp.red = true;
-                                    rotateLeft(xpp);
-                                }
-                            }
-                        }
-                    }
-                }
-                TreeNode r = root;
-                if (r != null && r.red) {
-                    r.red = false;
-                }
-            }
-            return null;
-        }
-
-        /*
-         * From CHMv8
-         *
-         * Removes the given node, that must be present before this
-         * call.  This is messier than typical red-black deletion code
-         * because we cannot swap the contents of an interior node
-         * with a leaf successor that is pinned by "next" pointers
-         * that are accessible independently of lock. So instead we
-         * swap the tree linkages.
-         */
-        final void deleteTreeNode(TreeNode p) {
-            TreeNode next = (TreeNode) p.entry.next; // unlink traversal pointers
-            TreeNode pred = p.prev;
-            if (pred == null) {
-                first = next;
-            } else {
-                pred.entry.next = next;
-            }
-            if (next != null) {
-                next.prev = pred;
-            }
-            TreeNode replacement;
-            TreeNode pl = p.left;
-            TreeNode pr = p.right;
-            if (pl != null && pr != null) {
-                TreeNode s = pr, sl;
-                while ((sl = s.left) != null) // find successor
-                {
-                    s = sl;
-                }
-                boolean c = s.red;
-                s.red = p.red;
-                p.red = c; // swap colors
-                TreeNode sr = s.right;
-                TreeNode pp = p.parent;
-                if (s == pr) { // p was s's direct parent
-                    p.parent = s;
-                    s.right = p;
-                } else {
-                    TreeNode sp = s.parent;
-                    if ((p.parent = sp) != null) {
-                        if (s == sp.left) {
-                            sp.left = p;
-                        } else {
-                            sp.right = p;
-                        }
-                    }
-                    if ((s.right = pr) != null) {
-                        pr.parent = s;
-                    }
-                }
-                p.left = null;
-                if ((p.right = sr) != null) {
-                    sr.parent = p;
-                }
-                if ((s.left = pl) != null) {
-                    pl.parent = s;
-                }
-                if ((s.parent = pp) == null) {
-                    root = s;
-                } else if (p == pp.left) {
-                    pp.left = s;
-                } else {
-                    pp.right = s;
-                }
-                replacement = sr;
-            } else {
-                replacement = (pl != null) ? pl : pr;
-            }
-            TreeNode pp = p.parent;
-            if (replacement == null) {
-                if (pp == null) {
-                    root = null;
-                    return;
-                }
-                replacement = p;
-            } else {
-                replacement.parent = pp;
-                if (pp == null) {
-                    root = replacement;
-                } else if (p == pp.left) {
-                    pp.left = replacement;
-                } else {
-                    pp.right = replacement;
-                }
-                p.left = p.right = p.parent = null;
-            }
-            if (!p.red) { // rebalance, from CLR
-                TreeNode x = replacement;
-                while (x != null) {
-                    TreeNode xp, xpl;
-                    if (x.red || (xp = x.parent) == null) {
-                        x.red = false;
-                        break;
-                    }
-                    if (x == (xpl = xp.left)) {
-                        TreeNode sib = xp.right;
-                        if (sib != null && sib.red) {
-                            sib.red = false;
-                            xp.red = true;
-                            rotateLeft(xp);
-                            sib = (xp = x.parent) == null ? null : xp.right;
-                        }
-                        if (sib == null) {
-                            x = xp;
-                        } else {
-                            TreeNode sl = sib.left, sr = sib.right;
-                            if ((sr == null || !sr.red)
-                                    && (sl == null || !sl.red)) {
-                                sib.red = true;
-                                x = xp;
-                            } else {
-                                if (sr == null || !sr.red) {
-                                    if (sl != null) {
-                                        sl.red = false;
-                                    }
-                                    sib.red = true;
-                                    rotateRight(sib);
-                                    sib = (xp = x.parent) == null ?
-                                        null : xp.right;
-                                }
-                                if (sib != null) {
-                                    sib.red = (xp == null) ? false : xp.red;
-                                    if ((sr = sib.right) != null) {
-                                        sr.red = false;
-                                    }
-                                }
-                                if (xp != null) {
-                                    xp.red = false;
-                                    rotateLeft(xp);
-                                }
-                                x = root;
-                            }
-                        }
-                    } else { // symmetric
-                        TreeNode sib = xpl;
-                        if (sib != null && sib.red) {
-                            sib.red = false;
-                            xp.red = true;
-                            rotateRight(xp);
-                            sib = (xp = x.parent) == null ? null : xp.left;
-                        }
-                        if (sib == null) {
-                            x = xp;
-                        } else {
-                            TreeNode sl = sib.left, sr = sib.right;
-                            if ((sl == null || !sl.red)
-                                    && (sr == null || !sr.red)) {
-                                sib.red = true;
-                                x = xp;
-                            } else {
-                                if (sl == null || !sl.red) {
-                                    if (sr != null) {
-                                        sr.red = false;
-                                    }
-                                    sib.red = true;
-                                    rotateLeft(sib);
-                                    sib = (xp = x.parent) == null ?
-                                        null : xp.left;
-                                }
-                                if (sib != null) {
-                                    sib.red = (xp == null) ? false : xp.red;
-                                    if ((sl = sib.left) != null) {
-                                        sl.red = false;
-                                    }
-                                }
-                                if (xp != null) {
-                                    xp.red = false;
-                                    rotateRight(xp);
-                                }
-                                x = root;
-                            }
-                        }
-                    }
-                }
-            }
-            if (p == replacement && (pp = p.parent) != null) {
-                if (p == pp.left) // detach pointers
-                {
-                    pp.left = null;
-                } else if (p == pp.right) {
-                    pp.right = null;
-                }
-                p.parent = null;
-            }
-        }
-    }
+    /* ---------------- Public operations -------------- */
 
     /**
      * Constructs an empty <tt>HashMap</tt> with the specified initial
@@ -832,9 +453,7 @@
             throw new IllegalArgumentException("Illegal load factor: " +
                                                loadFactor);
         this.loadFactor = loadFactor;
-        threshold = initialCapacity;
-        hashSeed = initHashSeed();
-        init();
+        this.threshold = tableSizeFor(initialCapacity);
     }
 
     /**
@@ -853,7 +472,7 @@
      * (16) and the default load factor (0.75).
      */
     public HashMap() {
-        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
+        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
     }
 
     /**
@@ -866,79 +485,35 @@
      * @throws  NullPointerException if the specified map is null
      */
     public HashMap(Map<? extends K, ? extends V> m) {
-        this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
-                DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR);
-        inflateTable(threshold);
-
-        putAllForCreate(m);
-        // assert size == m.size();
-    }
-
-    private static int roundUpToPowerOf2(int number) {
-        // assert number >= 0 : "number must be non-negative";
-        return number >= MAXIMUM_CAPACITY
-                ? MAXIMUM_CAPACITY
-                : (number > 1) ? Integer.highestOneBit((number - 1) << 1) : 1;
+        this.loadFactor = DEFAULT_LOAD_FACTOR;
+        putMapEntries(m, false);
     }
 
     /**
-     * Inflates the table.
-     */
-    private void inflateTable(int toSize) {
-        // Find a power of 2 >= toSize
-        int capacity = roundUpToPowerOf2(toSize);
-
-        threshold = (int) Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);
-        table = new Object[capacity];
-    }
-
-    // internal utilities
-
-    /**
-     * Initialization hook for subclasses. This method is called
-     * in all constructors and pseudo-constructors (clone, readObject)
-     * after HashMap has been initialized but before any entries have
-     * been inserted.  (In the absence of this method, readObject would
-     * require explicit knowledge of subclasses.)
-     */
-    void init() {
-    }
-
-    /**
-     * Return an initial value for the hashSeed, or 0 if the random seed is not
-     * enabled.
+     * Implements Map.putAll and Map constructor
+     *
+     * @param m the map
+     * @param evict false when initially constructing this map, else
+     * true (relayed to method afterNodeInsertion).
      */
-    final int initHashSeed() {
-        if (sun.misc.VM.isBooted() && Holder.USE_HASHSEED) {
-            int seed = ThreadLocalRandom.current().nextInt();
-            return (seed != 0) ? seed : 1;
+    final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
+        int s = m.size();
+        if (s > 0) {
+            if (table == null) { // pre-size
+                float ft = ((float)s / loadFactor) + 1.0F;
+                int t = ((ft < (float)MAXIMUM_CAPACITY) ?
+                         (int)ft : MAXIMUM_CAPACITY);
+                if (t > threshold)
+                    threshold = tableSizeFor(t);
+            }
+            else if (s > threshold)
+                resize();
+            for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
+                K key = e.getKey();
+                V value = e.getValue();
+                putVal(hash(key), key, value, false, evict);
+            }
         }
-        return 0;
-    }
-
-    /**
-     * Retrieve object hash code and applies a supplemental hash function to the
-     * result hash, which defends against poor quality hash functions. This is
-     * critical because HashMap uses power-of-two length hash tables, that
-     * otherwise encounter collisions for hashCodes that do not differ
-     * in lower bits.
-     */
-    final int hash(Object k) {
-        int  h = hashSeed ^ k.hashCode();
-
-        // This function ensures that hashCodes that differ only by
-        // constant multiples at each bit position have a bounded
-        // number of collisions (approximately 8 at default load factor).
-        h ^= (h >>> 20) ^ (h >>> 12);
-        return h ^ (h >>> 7) ^ (h >>> 4);
-    }
-
-    /**
-     * Returns index for hash code h.
-     */
-    static int indexFor(int h, int length) {
-        // assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";
-        return h & (length-1);
     }
 
     /**
@@ -976,18 +551,36 @@
      *
      * @see #put(Object, Object)
      */
-    @SuppressWarnings("unchecked")
     public V get(Object key) {
-        Entry<K,V> entry = getEntry(key);
-
-        return null == entry ? null : entry.getValue();
+        Node<K,V> e;
+        return (e = getNode(hash(key), key)) == null ? null : e.value;
     }
 
-    @Override
-    public V getOrDefault(Object key, V defaultValue) {
-        Entry<K,V> entry = getEntry(key);
-
-        return (entry == null) ? defaultValue : entry.getValue();
+    /**
+     * Implements Map.get and related methods
+     *
+     * @param hash hash for key
+     * @param key the key
+     * @return the node, or null if none
+     */
+    final Node<K,V> getNode(int hash, Object key) {
+        Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
+        if ((tab = table) != null && (n = tab.length) > 0 &&
+            (first = tab[(n - 1) & hash]) != null) {
+            if (first.hash == hash && // always check first node
+                ((k = first.key) == key || (key != null && key.equals(k))))
+                return first;
+            if ((e = first.next) != null) {
+                if (first instanceof TreeNode)
+                    return ((TreeNode<K,V>)first).getTreeNode(hash, key);
+                do {
+                    if (e.hash == hash &&
+                        ((k = e.key) == key || (key != null && key.equals(k))))
+                        return e;
+                } while ((e = e.next) != null);
+            }
+        }
+        return null;
     }
 
     /**
@@ -999,49 +592,10 @@
      * key.
      */
     public boolean containsKey(Object key) {
-        return getEntry(key) != null;
+        return getNode(hash(key), key) != null;
     }
 
     /**
-     * Returns the entry associated with the specified key in the
-     * HashMap.  Returns null if the HashMap contains no mapping
-     * for the key.
-     */
-    @SuppressWarnings("unchecked")
-    final Entry<K,V> getEntry(Object key) {
-        if (size == 0) {
-            return null;
-        }
-        if (key == null) {
-            return nullKeyEntry;
-        }
-        int hash = hash(key);
-        int bin = indexFor(hash, table.length);
-
-        if (table[bin] instanceof Entry) {
-            Entry<K,V> e = (Entry<K,V>) table[bin];
-            for (; e != null; e = (Entry<K,V>)e.next) {
-                Object k;
-                if (e.hash == hash &&
-                    ((k = e.key) == key || key.equals(k))) {
-                    return e;
-                }
-            }
-        } else if (table[bin] != null) {
-            TreeBin e = (TreeBin)table[bin];
-            TreeNode p = e.getTreeNode(hash, (K)key);
-            if (p != null) {
-                // assert p.entry.hash == hash && p.entry.key.equals(key);
-                return (Entry<K,V>)p.entry;
-            } else {
-                return null;
-            }
-        }
-        return null;
-    }
-
-
-    /**
      * Associates the specified value with the specified key in this map.
      * If the map previously contained a mapping for the key, the old
      * value is replaced.
@@ -1053,202 +607,169 @@
      *         (A <tt>null</tt> return can also indicate that the map
      *         previously associated <tt>null</tt> with <tt>key</tt>.)
      */
-    @SuppressWarnings("unchecked")
     public V put(K key, V value) {
-        if (table == EMPTY_TABLE) {
-            inflateTable(threshold);
-        }
-       if (key == null)
-            return putForNullKey(value);
-        int hash = hash(key);
-        int i = indexFor(hash, table.length);
-        boolean checkIfNeedTree = false; // Might we convert bin to a TreeBin?
+        return putVal(hash(key), key, value, false, true);
+    }
 
-        if (table[i] instanceof Entry) {
-            // Bin contains ordinary Entries.  Search for key in the linked list
-            // of entries, counting the number of entries.  Only check for
-            // TreeBin conversion if the list size is >= TREE_THRESHOLD.
-            // (The conversion still may not happen if the table gets resized.)
-            int listSize = 0;
-            Entry<K,V> e = (Entry<K,V>) table[i];
-            for (; e != null; e = (Entry<K,V>)e.next) {
-                Object k;
-                if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
-                    V oldValue = e.value;
+    /**
+     * Implements Map.put and related methods
+     *
+     * @param hash hash for key
+     * @param key the key
+     * @param value the value to put
+     * @param onlyIfAbsent if true, don't change existing value
+     * @param evict if false, the table is in creation mode.
+     * @return previous value, or null if none
+     */
+    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
+                   boolean evict) {
+        Node<K,V>[] tab; Node<K,V> p; int n, i;
+        if (size > threshold || (tab = table) == null ||
+            (n = tab.length) == 0)
+            n = (tab = resize()).length;
+        if ((p = tab[i = (n - 1) & hash]) == null)
+            tab[i] = newNode(hash, key, value, null);
+        else {
+            Node<K,V> e; K k;
+            if (p.hash == hash &&
+                ((k = p.key) == key || (key != null && key.equals(k))))
+                e = p;
+            else if (p instanceof TreeNode)
+                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
+            else {
+                for (int binCount = 0; ; ++binCount) {
+                    if ((e = p.next) == null) {
+                        p.next = newNode(hash, key, value, null);
+                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
+                            treeifyBin(tab, hash);
+                        break;
+                    }
+                    if (e.hash == hash &&
+                        ((k = e.key) == key || (key != null && key.equals(k))))
+                        break;
+                    p = e;
+                }
+            }
+            if (e != null) { // existing mapping for key
+                V oldValue = e.value;
+                if (!onlyIfAbsent || oldValue == null)
                     e.value = value;
-                    e.recordAccess(this);
-                    return oldValue;
-                }
-                listSize++;
-            }
-            // Didn't find, so fall through and call addEntry() to add the
-            // Entry and check for TreeBin conversion.
-            checkIfNeedTree = listSize >= TreeBin.TREE_THRESHOLD;
-        } else if (table[i] != null) {
-            TreeBin e = (TreeBin)table[i];
-            TreeNode p = e.putTreeNode(hash, key, value, null);
-            if (p == null) { // putTreeNode() added a new node
-                modCount++;
-                size++;
-                if (size >= threshold) {
-                    resize(2 * table.length);
-                }
-                return null;
-            } else { // putTreeNode() found an existing node
-                Entry<K,V> pEntry = (Entry<K,V>)p.entry;
-                V oldVal = pEntry.value;
-                pEntry.value = value;
-                pEntry.recordAccess(this);
-                return oldVal;
+                afterNodeAccess(e);
+                return oldValue;
             }
         }
-        modCount++;
-        addEntry(hash, key, value, i, checkIfNeedTree);
+        ++modCount;
+        ++size;
+        afterNodeInsertion(evict);
         return null;
     }
 
     /**
-     * Offloaded version of put for null keys
+     * Initializes or doubles table size.  If null, allocates in
+     * accord with initial capacity target held in field threshold.
+     * Otherwise, because we are using power-of-two expansion, the
+     * elements from each bin must either stay at same index, or move
+     * with a power of two offset in the new table.
+     *
+     * @return the table
      */
-    private V putForNullKey(V value) {
-        if (nullKeyEntry != null) {
-            V oldValue = nullKeyEntry.value;
-            nullKeyEntry.value = value;
-            nullKeyEntry.recordAccess(this);
-            return oldValue;
+    final Node<K,V>[] resize() {
+        Node<K,V>[] oldTab = table;
+        int oldCap = (oldTab == null) ? 0 : oldTab.length;
+        int oldThr = threshold;
+        int newCap, newThr = 0;
+        if (oldCap > 0) {
+            if (oldCap >= MAXIMUM_CAPACITY) {
+                threshold = Integer.MAX_VALUE;
+                return oldTab;
+            }
+            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
+                     oldCap >= DEFAULT_INITIAL_CAPACITY)
+                newThr = oldThr << 1; // double threshold
         }
-        modCount++;
-        size++; // newEntry() skips size++
-        nullKeyEntry = newEntry(0, null, value, null);
-        return null;
-    }
-
-    private void putForCreateNullKey(V value) {
-        // Look for preexisting entry for key.  This will never happen for
-        // clone or deserialize.  It will only happen for construction if the
-        // input Map is a sorted map whose ordering is inconsistent w/ equals.
-        if (nullKeyEntry != null) {
-            nullKeyEntry.value = value;
-        } else {
-            nullKeyEntry = newEntry(0, null, value, null);
-            size++;
+        else if (oldThr > 0) // initial capacity was placed in threshold
+            newCap = oldThr;
+        else {               // zero initial threshold signifies using defaults
+            newCap = DEFAULT_INITIAL_CAPACITY;
+            newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
         }
-    }
-
-
-    /**
-     * This method is used instead of put by constructors and
-     * pseudoconstructors (clone, readObject).  It does not resize the table,
-     * check for comodification, etc, though it will convert bins to TreeBins
-     * as needed.  It calls createEntry rather than addEntry.
-     */
-    @SuppressWarnings("unchecked")
-    private void putForCreate(K key, V value) {
-        if (null == key) {
-            putForCreateNullKey(value);
-            return;
+        if (newThr == 0) {
+            float ft = (float)newCap * loadFactor;
+            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
+                      (int)ft : Integer.MAX_VALUE);
         }
-        int hash = hash(key);
-        int i = indexFor(hash, table.length);
-        boolean checkIfNeedTree = false; // Might we convert bin to a TreeBin?
-
-        /**
-         * Look for preexisting entry for key.  This will never happen for
-         * clone or deserialize.  It will only happen for construction if the
-         * input Map is a sorted map whose ordering is inconsistent w/ equals.
-         */
-        if (table[i] instanceof Entry) {
-            int listSize = 0;
-            Entry<K,V> e = (Entry<K,V>) table[i];
-            for (; e != null; e = (Entry<K,V>)e.next) {
-                Object k;
-                if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
-                    e.value = value;
-                    return;
+        threshold = newThr;
+        @SuppressWarnings({"rawtypes","unchecked"})
+            Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
+        table = newTab;
+        if (oldTab != null) {
+            for (int j = 0; j < oldCap; ++j) {
+                Node<K,V> e;
+                if ((e = oldTab[j]) != null) {
+                    oldTab[j] = null;
+                    if (e.next == null)
+                        newTab[e.hash & (newCap - 1)] = e;
+                    else if (e instanceof TreeNode)
+                        ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
+                    else { // preserve order
+                        Node<K,V> loHead = null, loTail = null;
+                        Node<K,V> hiHead = null, hiTail = null;
+                        Node<K,V> next;
+                        do {
+                            next = e.next;
+                            if ((e.hash & oldCap) == 0) {
+                                if (loTail == null)
+                                    loHead = e;
+                                else
+                                    loTail.next = e;
+                                loTail = e;
+                            }
+                            else {
+                                if (hiTail == null)
+                                    hiHead = e;
+                                else
+                                    hiTail.next = e;
+                                hiTail = e;
+                            }
+                        } while ((e = next) != null);
+                        if (loTail != null) {
+                            loTail.next = null;
+                            newTab[j] = loHead;
+                        }
+                        if (hiTail != null) {
+                            hiTail.next = null;
+                            newTab[j + oldCap] = hiHead;
+                        }
+                    }
                 }
-                listSize++;
             }
-            // Didn't find, fall through to createEntry().
-            // Check for conversion to TreeBin done via createEntry().
-            checkIfNeedTree = listSize >= TreeBin.TREE_THRESHOLD;
-        } else if (table[i] != null) {
-            TreeBin e = (TreeBin)table[i];
-            TreeNode p = e.putTreeNode(hash, key, value, null);
-            if (p != null) {
-                p.entry.setValue(value); // Found an existing node, set value
-            } else {
-                size++; // Added a new TreeNode, so update size
-            }
-            // don't need modCount++/check for resize - just return
-            return;
         }
-
-        createEntry(hash, key, value, i, checkIfNeedTree);
-    }
-
-    private void putAllForCreate(Map<? extends K, ? extends V> m) {
-        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
-            putForCreate(e.getKey(), e.getValue());
+        return newTab;
     }
 
     /**
-     * Rehashes the contents of this map into a new array with a
-     * larger capacity.  This method is called automatically when the
-     * number of keys in this map reaches its threshold.
-     *
-     * If current capacity is MAXIMUM_CAPACITY, this method does not
-     * resize the map, but sets threshold to Integer.MAX_VALUE.
-     * This has the effect of preventing future calls.
-     *
-     * @param newCapacity the new capacity, MUST be a power of two;
-     *        must be greater than current capacity unless current
-     *        capacity is MAXIMUM_CAPACITY (in which case value
-     *        is irrelevant).
+     * Replaces all linked nodes in bin at index for given hash unless
+     * table is too small, in which case resizes instead.
      */
-    void resize(int newCapacity) {
-        Object[] oldTable = table;
-        int oldCapacity = oldTable.length;
-        if (oldCapacity == MAXIMUM_CAPACITY) {
-            threshold = Integer.MAX_VALUE;
-            return;
+    final void treeifyBin(Node<K,V>[] tab, int hash) {
+        int n, index; Node<K,V> e;
+        if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
+            resize();
+        else if ((e = tab[index = (n - 1) & hash]) != null) {
+            TreeNode<K,V> hd = null, tl = null;
+            do {
+                TreeNode<K,V> p = replacementTreeNode(e, null);
+                if (tl == null)
+                    hd = p;
+                else {
+                    p.prev = tl;
+                    tl.next = p;
+                }
+                tl = p;
+            } while ((e = e.next) != null);
+            if ((tab[index] = hd) != null)
+                hd.treeify(tab);
         }
-
-        Object[] newTable = new Object[newCapacity];
-        transfer(newTable);
-        table = newTable;
-        threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
-    }
-
-    /**
-     * Transfers all entries from current table to newTable.
-     *
-     * Assumes newTable is larger than table
-     */
-    @SuppressWarnings("unchecked")
-    void transfer(Object[] newTable) {
-        Object[] src = table;
-        // assert newTable.length > src.length : "newTable.length(" +
-        //   newTable.length + ") expected to be > src.length("+src.length+")";
-        int newCapacity = newTable.length;
-        for (int j = 0; j < src.length; j++) {
-             if (src[j] instanceof Entry) {
-                // Assume: since wasn't TreeBin before, won't need TreeBin now
-                Entry<K,V> e = (Entry<K,V>) src[j];
-                while (null != e) {
-                    Entry<K,V> next = (Entry<K,V>)e.next;
-                    int i = indexFor(e.hash, newCapacity);
-                    e.next = (Entry<K,V>) newTable[i];
-                    newTable[i] = e;
-                    e = next;
-                }
-            } else if (src[j] != null) {
-                TreeBin e = (TreeBin) src[j];
-                TreeBin loTree = new TreeBin();
-                TreeBin hiTree = new TreeBin();
-                e.splitTreeBin(newTable, j, loTree, hiTree);
-            }
-        }
-        Arrays.fill(table, null);
     }
 
     /**
@@ -1260,30 +781,8 @@
      * @throws NullPointerException if the specified map is null
      */
     public void putAll(Map<? extends K, ? extends V> m) {
-        int numKeysToBeAdded = m.size();
-        if (numKeysToBeAdded == 0)
-            return;
-
-        if (table == EMPTY_TABLE) {
-            inflateTable((int) Math.max(numKeysToBeAdded * loadFactor, threshold));
-        }
-
-        /*
-         * Expand the map if the map if the number of mappings to be added
-         * is greater than or equal to threshold.  This is conservative; the
-         * obvious condition is (m.size() + size) >= threshold, but this
-         * condition could result in a map with twice the appropriate capacity,
-         * if the keys to be added overlap with the keys already in this map.
-         * By using the conservative calculation, we subject ourself
-         * to at most one extra resize.
-         */
-        if (numKeysToBeAdded > threshold && table.length < MAXIMUM_CAPACITY) {
-            resize(table.length * 2);
-        }
-
-        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
-            put(e.getKey(), e.getValue());
-        }
+        putMapEntries(m, true);
+    }
 
     /**
      * Removes the mapping for the specified key from this map if present.
@@ -1295,834 +794,74 @@
      *         previously associated <tt>null</tt> with <tt>key</tt>.)
      */
     public V remove(Object key) {
-        Entry<K,V> e = removeEntryForKey(key);
-       return (e == null ? null : e.value);
-   }
-
-   // optimized implementations of default methods in Map
-
-    @Override
-    public void forEach(BiConsumer<? super K, ? super V> action) {
-        Objects.requireNonNull(action);
-        final int expectedModCount = modCount;
-        if (nullKeyEntry != null) {
-            forEachNullKey(expectedModCount, action);
-        }
-        Object[] tab = this.table;
-        for (int index = 0; index < tab.length; index++) {
-            Object item = tab[index];
-            if (item == null) {
-                continue;
-            }
-            if (item instanceof HashMap.TreeBin) {
-                eachTreeNode(expectedModCount, ((TreeBin)item).first, action);
-                continue;
-            }
-            @SuppressWarnings("unchecked")
-            Entry<K, V> entry = (Entry<K, V>)item;
-            while (entry != null) {
-                action.accept(entry.key, entry.value);
-                entry = (Entry<K, V>)entry.next;
-
-                if (expectedModCount != modCount) {
-                    throw new ConcurrentModificationException();
-                }
-            }
-        }
-    }
-
-    private void eachTreeNode(int expectedModCount, TreeNode<K, V> node, BiConsumer<? super K, ? super V> action) {
-        while (node != null) {
-            @SuppressWarnings("unchecked")
-            Entry<K, V> entry = (Entry<K, V>)node.entry;
-            action.accept(entry.key, entry.value);
-            node = (TreeNode<K, V>)entry.next;
-
-            if (expectedModCount != modCount) {
-                throw new ConcurrentModificationException();
-            }
-        }
-    }
-
-    private void forEachNullKey(int expectedModCount, BiConsumer<? super K, ? super V> action) {
-        action.accept(null, nullKeyEntry.value);
-
-        if (expectedModCount != modCount) {
-            throw new ConcurrentModificationException();
-        }
-    }
-
-    @Override
-    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
-        Objects.requireNonNull(function);
-        final int expectedModCount = modCount;
-        if (nullKeyEntry != null) {
-            replaceforNullKey(expectedModCount, function);
-        }
-        Object[] tab = this.table;
-        for (int index = 0; index < tab.length; index++) {
-            Object item = tab[index];
-            if (item == null) {
-                continue;
-            }
-            if (item instanceof HashMap.TreeBin) {
-                replaceEachTreeNode(expectedModCount, ((TreeBin)item).first, function);
-                continue;
-            }
-            @SuppressWarnings("unchecked")
-            Entry<K, V> entry = (Entry<K, V>)item;
-            while (entry != null) {
-                entry.value = function.apply(entry.key, entry.value);
-                entry = (Entry<K, V>)entry.next;
-
-                if (expectedModCount != modCount) {
-                    throw new ConcurrentModificationException();
-                }
-            }
-        }
-    }
-
-    private void replaceEachTreeNode(int expectedModCount, TreeNode<K, V> node, BiFunction<? super K, ? super V, ? extends V> function) {
-        while (node != null) {
-            @SuppressWarnings("unchecked")
-            Entry<K, V> entry = (Entry<K, V>)node.entry;
-            entry.value = function.apply(entry.key, entry.value);
-            node = (TreeNode<K, V>)entry.next;
-
-            if (expectedModCount != modCount) {
-                throw new ConcurrentModificationException();
-            }
-        }
-    }
-
-    private void replaceforNullKey(int expectedModCount, BiFunction<? super K, ? super V, ? extends V> function) {
-        nullKeyEntry.value = function.apply(null, nullKeyEntry.value);
-
-        if (expectedModCount != modCount) {
-            throw new ConcurrentModificationException();
-        }
+        Node<K,V> e;
+        return (e = removeNode(hash(key), key, null, false, true)) == null ?
+            null : e.value;
     }
 
-    @Override
-    public V putIfAbsent(K key, V value) {
-        if (table == EMPTY_TABLE) {
-            inflateTable(threshold);
-        }
-        if (key == null) {
-            if (nullKeyEntry == null || nullKeyEntry.value == null) {
-                putForNullKey(value);
-                return null;
-            } else {
-                return nullKeyEntry.value;
-            }
-        }
-        int hash = hash(key);
-        int i = indexFor(hash, table.length);
-        boolean checkIfNeedTree = false; // Might we convert bin to a TreeBin?
-
-        if (table[i] instanceof Entry) {
-            int listSize = 0;
-            Entry<K,V> e = (Entry<K,V>) table[i];
-            for (; e != null; e = (Entry<K,V>)e.next) {
-                if (e.hash == hash && Objects.equals(e.key, key)) {
-                    if (e.value != null) {
-                        return e.value;
-                    }
-                    e.value = value;
-                    e.recordAccess(this);
-                    return null;
-                }
-                listSize++;
-            }
-            // Didn't find, so fall through and call addEntry() to add the
-            // Entry and check for TreeBin conversion.
-            checkIfNeedTree = listSize >= TreeBin.TREE_THRESHOLD;
-        } else if (table[i] != null) {
-            TreeBin e = (TreeBin)table[i];
-            TreeNode p = e.putTreeNode(hash, key, value, null);
-            if (p == null) { // not found, putTreeNode() added a new node
-                modCount++;
-                size++;
-                if (size >= threshold) {
-                    resize(2 * table.length);
-                }
-                return null;
-            } else { // putTreeNode() found an existing node
-                Entry<K,V> pEntry = (Entry<K,V>)p.entry;
-                V oldVal = pEntry.value;
-                if (oldVal == null) { // only replace if maps to null
-                    pEntry.value = value;
-                    pEntry.recordAccess(this);
-                }
-                return oldVal;
-            }
-        }
-        modCount++;
-        addEntry(hash, key, value, i, checkIfNeedTree);
-        return null;
-    }
-
-    @Override
-    public boolean remove(Object key, Object value) {
-        if (size == 0) {
-            return false;
-        }
-        if (key == null) {
-            if (nullKeyEntry != null &&
-                 Objects.equals(nullKeyEntry.value, value)) {
-                removeNullKey();
-                return true;
-            }
-            return false;
-        }
-        int hash = hash(key);
-        int i = indexFor(hash, table.length);
-
-        if (table[i] instanceof Entry) {
-            @SuppressWarnings("unchecked")
-            Entry<K,V> prev = (Entry<K,V>) table[i];
-            Entry<K,V> e = prev;
-            while (e != null) {
-                @SuppressWarnings("unchecked")
-                Entry<K,V> next = (Entry<K,V>) e.next;
-                if (e.hash == hash && Objects.equals(e.key, key)) {
-                    if (!Objects.equals(e.value, value)) {
-                        return false;
-                    }
-                    modCount++;
-                    size--;
-                    if (prev == e)
-                        table[i] = next;
-                    else
-                        prev.next = next;
-                    e.recordRemoval(this);
-                    return true;
-                }
-                prev = e;
-                e = next;
-            }
-        } else if (table[i] != null) {
-            TreeBin tb = ((TreeBin) table[i]);
-            TreeNode p = tb.getTreeNode(hash, (K)key);
-            if (p != null) {
-                Entry<K,V> pEntry = (Entry<K,V>)p.entry;
-                // assert pEntry.key.equals(key);
-                if (Objects.equals(pEntry.value, value)) {
-                    modCount++;
-                    size--;
-                    tb.deleteTreeNode(p);
-                    pEntry.recordRemoval(this);
-                    if (tb.root == null || tb.first == null) {
-                        // assert tb.root == null && tb.first == null :
-                        //         "TreeBin.first and root should both be null";
-                        // TreeBin is now empty, we should blank this bin
-                        table[i] = null;
-                    }
-                    return true;
+    /**
+     * Implements Map.remove and related methods
+     *
+     * @param hash hash for key
+     * @param key the key
+     * @param value the value to match if matchValue, else ignored
+     * @param matchValue if true only remove if value is equal
+     * @param movable if false do not move other nodes while removing
+     * @return the node, or null if none
+     */
+    final Node<K,V> removeNode(int hash, Object key, Object value,
+                               boolean matchValue, boolean movable) {
+        Node<K,V>[] tab; Node<K,V> p; int n, index;
+        if ((tab = table) != null && (n = tab.length) > 0 &&
+            (p = tab[index = (n - 1) & hash]) != null) {
+            Node<K,V> node = null, e; K k; V v;
+            if (p.hash == hash &&
+                ((k = p.key) == key || (key != null && key.equals(k))))
+                node = p;
+            else if ((e = p.next) != null) {
+                if (p instanceof TreeNode)
+                    node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
+                else {
+                    do {
+                        if (e.hash == hash &&
+                            ((k = e.key) == key ||
+                             (key != null && key.equals(k)))) {
+                            node = e;
+                            break;
+                        }
+                        p = e;
+                    } while ((e = e.next) != null);
                 }
             }
-        }
-        return false;
-    }
-
-    @Override
-    public boolean replace(K key, V oldValue, V newValue) {
-        if (size == 0) {
-            return false;
-        }
-        if (key == null) {
-            if (nullKeyEntry != null &&
-                 Objects.equals(nullKeyEntry.value, oldValue)) {
-                putForNullKey(newValue);
-                return true;
-            }
-            return false;
-        }
-        int hash = hash(key);
-        int i = indexFor(hash, table.length);
-
-        if (table[i] instanceof Entry) {
-            @SuppressWarnings("unchecked")
-            Entry<K,V> e = (Entry<K,V>) table[i];
-            for (; e != null; e = (Entry<K,V>)e.next) {
-                if (e.hash == hash && Objects.equals(e.key, key) && Objects.equals(e.value, oldValue)) {
-                    e.value = newValue;
-                    e.recordAccess(this);
-                    return true;
-                }
-            }
-            return false;
-        } else if (table[i] != null) {
-            TreeBin tb = ((TreeBin) table[i]);
-            TreeNode p = tb.getTreeNode(hash, key);
-            if (p != null) {
-                Entry<K,V> pEntry = (Entry<K,V>)p.entry;
-                // assert pEntry.key.equals(key);
-                if (Objects.equals(pEntry.value, oldValue)) {
-                    pEntry.value = newValue;
-                    pEntry.recordAccess(this);
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-   @Override
-    public V replace(K key, V value) {
-        if (size == 0) {
-            return null;
-        }
-        if (key == null) {
-            if (nullKeyEntry != null) {
-                return putForNullKey(value);
-            }
-            return null;
-        }
-        int hash = hash(key);
-        int i = indexFor(hash, table.length);
-        if (table[i] instanceof Entry) {
-            @SuppressWarnings("unchecked")
-            Entry<K,V> e = (Entry<K,V>)table[i];
-            for (; e != null; e = (Entry<K,V>)e.next) {
-                if (e.hash == hash && Objects.equals(e.key, key)) {
-                    V oldValue = e.value;
-                    e.value = value;
-                    e.recordAccess(this);
-                    return oldValue;
-                }
-            }
-
-            return null;
-        } else if (table[i] != null) {
-            TreeBin tb = ((TreeBin) table[i]);
-            TreeNode p = tb.getTreeNode(hash, key);
-            if (p != null) {
-                Entry<K,V> pEntry = (Entry<K,V>)p.entry;
-                // assert pEntry.key.equals(key);
-                V oldValue = pEntry.value;
-                pEntry.value = value;
-                pEntry.recordAccess(this);
-                return oldValue;
+            if (node != null && (!matchValue || (v = node.value) == value ||
+                                 (value != null && value.equals(v)))) {
+                if (node instanceof TreeNode)
+                    ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
+                else if (node == p)
+                    tab[index] = node.next;
+                else
+                    p.next = node.next;
+                ++modCount;
+                --size;
+                afterNodeRemoval(node);
+                return node;
             }
         }
         return null;
     }
 
-    @Override
-    public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
-        if (table == EMPTY_TABLE) {
-            inflateTable(threshold);
-        }
-        if (key == null) {
-            if (nullKeyEntry == null || nullKeyEntry.value == null) {
-                V newValue = mappingFunction.apply(key);
-                if (newValue != null) {
-                    putForNullKey(newValue);
-                }
-                return newValue;
-            }
-            return nullKeyEntry.value;
-        }
-        int hash = hash(key);
-        int i = indexFor(hash, table.length);
-        boolean checkIfNeedTree = false; // Might we convert bin to a TreeBin?
-
-        if (table[i] instanceof Entry) {
-            int listSize = 0;
-            @SuppressWarnings("unchecked")
-            Entry<K,V> e = (Entry<K,V>)table[i];
-            for (; e != null; e = (Entry<K,V>)e.next) {
-                if (e.hash == hash && Objects.equals(e.key, key)) {
-                    V oldValue = e.value;
-                    if (oldValue == null) {
-                        V newValue = mappingFunction.apply(key);
-                        if (newValue != null) {
-                            e.value = newValue;
-                            e.recordAccess(this);
-                        }
-                        return newValue;
-                    }
-                    return oldValue;
-                }
-                listSize++;
-            }
-            // Didn't find, fall through to call the mapping function
-            checkIfNeedTree = listSize >= TreeBin.TREE_THRESHOLD;
-        } else if (table[i] != null) {
-            TreeBin e = (TreeBin)table[i];
-            V value = mappingFunction.apply(key);
-            if (value == null) { // Return the existing value, if any
-                TreeNode p = e.getTreeNode(hash, key);
-                if (p != null) {
-                    return (V) p.entry.value;
-                }
-                return null;
-            } else { // Put the new value into the Tree, if absent
-                TreeNode p = e.putTreeNode(hash, key, value, null);
-                if (p == null) { // not found, new node was added
-                    modCount++;
-                    size++;
-                    if (size >= threshold) {
-                        resize(2 * table.length);
-                    }
-                    return value;
-                } else { // putTreeNode() found an existing node
-                    Entry<K,V> pEntry = (Entry<K,V>)p.entry;
-                    V oldVal = pEntry.value;
-                    if (oldVal == null) { // only replace if maps to null
-                        pEntry.value = value;
-                        pEntry.recordAccess(this);
-                        return value;
-                    }
-                    return oldVal;
-                }
-            }
-        }
-        V newValue = mappingFunction.apply(key);
-        if (newValue != null) { // add Entry and check for TreeBin conversion
-            modCount++;
-            addEntry(hash, key, newValue, i, checkIfNeedTree);
-        }
-
-        return newValue;
-    }
-
-    @Override
-    public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
-        if (size == 0) {
-            return null;
-        }
-        if (key == null) {
-            V oldValue;
-            if (nullKeyEntry != null && (oldValue = nullKeyEntry.value) != null) {
-                V newValue = remappingFunction.apply(key, oldValue);
-                if (newValue != null ) {
-                    putForNullKey(newValue);
-                    return newValue;
-                } else {
-                    removeNullKey();
-                }
-            }
-            return null;
-        }
-        int hash = hash(key);
-        int i = indexFor(hash, table.length);
-        if (table[i] instanceof Entry) {
-            @SuppressWarnings("unchecked")
-            Entry<K,V> prev = (Entry<K,V>)table[i];
-            Entry<K,V> e = prev;
-            while (e != null) {
-                Entry<K,V> next = (Entry<K,V>)e.next;
-                if (e.hash == hash && Objects.equals(e.key, key)) {
-                    V oldValue = e.value;
-                    if (oldValue == null)
-                        break;
-                    V newValue = remappingFunction.apply(key, oldValue);
-                    if (newValue == null) {
-                        modCount++;
-                        size--;
-                        if (prev == e)
-                            table[i] = next;
-                        else
-                            prev.next = next;
-                        e.recordRemoval(this);
-                    } else {
-                        e.value = newValue;
-                        e.recordAccess(this);
-                    }
-                    return newValue;
-                }
-                prev = e;
-                e = next;
-            }
-        } else if (table[i] != null) {
-            TreeBin tb = (TreeBin)table[i];
-            TreeNode p = tb.getTreeNode(hash, key);
-            if (p != null) {
-                Entry<K,V> pEntry = (Entry<K,V>)p.entry;
-                // assert pEntry.key.equals(key);
-                V oldValue = pEntry.value;
-                if (oldValue != null) {
-                    V newValue = remappingFunction.apply(key, oldValue);
-                if (newValue == null) { // remove mapping
-                    modCount++;
-                    size--;
-                    tb.deleteTreeNode(p);
-                    pEntry.recordRemoval(this);
-                    if (tb.root == null || tb.first == null) {
-                        // assert tb.root == null && tb.first == null :
-                        //     "TreeBin.first and root should both be null";
-                        // TreeBin is now empty, we should blank this bin
-                        table[i] = null;
-                    }
-                } else {
-                    pEntry.value = newValue;
-                    pEntry.recordAccess(this);
-                }
-                return newValue;
-            }
-        }
-        }
-        return null;
-    }
-
-    @Override
-    public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
-        if (table == EMPTY_TABLE) {
-            inflateTable(threshold);
-        }
-        if (key == null) {
-            V oldValue = nullKeyEntry == null ? null : nullKeyEntry.value;
-            V newValue = remappingFunction.apply(key, oldValue);
-            if (newValue != oldValue || (oldValue == null && nullKeyEntry != null)) {
-                if (newValue == null) {
-                    removeNullKey();
-                } else {
-                    putForNullKey(newValue);
-                }
-            }
-            return newValue;
-        }
-        int hash = hash(key);
-        int i = indexFor(hash, table.length);
-        boolean checkIfNeedTree = false; // Might we convert bin to a TreeBin?
-
-        if (table[i] instanceof Entry) {
-            int listSize = 0;
-            @SuppressWarnings("unchecked")
-            Entry<K,V> prev = (Entry<K,V>)table[i];
-            Entry<K,V> e = prev;
-
-            while (e != null) {
-                Entry<K,V> next = (Entry<K,V>)e.next;
-                if (e.hash == hash && Objects.equals(e.key, key)) {
-                    V oldValue = e.value;
-                    V newValue = remappingFunction.apply(key, oldValue);
-                    if (newValue != oldValue || oldValue == null) {
-                        if (newValue == null) {
-                            modCount++;
-                            size--;
-                            if (prev == e)
-                                table[i] = next;
-                            else
-                                prev.next = next;
-                            e.recordRemoval(this);
-                        } else {
-                            e.value = newValue;
-                            e.recordAccess(this);
-                        }
-                    }
-                    return newValue;
-                }
-                prev = e;
-                e = next;
-                listSize++;
-            }
-            checkIfNeedTree = listSize >= TreeBin.TREE_THRESHOLD;
-        } else if (table[i] != null) {
-            TreeBin tb = (TreeBin)table[i];
-            TreeNode p = tb.getTreeNode(hash, key);
-            V oldValue = p == null ? null : (V)p.entry.value;
-            V newValue = remappingFunction.apply(key, oldValue);
-            if (newValue != oldValue || (oldValue == null && p != null)) {
-                if (newValue == null) {
-                    Entry<K,V> pEntry = (Entry<K,V>)p.entry;
-                    modCount++;
-                    size--;
-                    tb.deleteTreeNode(p);
-                    pEntry.recordRemoval(this);
-                    if (tb.root == null || tb.first == null) {
-                        // assert tb.root == null && tb.first == null :
-                        //         "TreeBin.first and root should both be null";
-                        // TreeBin is now empty, we should blank this bin
-                        table[i] = null;
-                    }
-                } else {
-                    if (p != null) { // just update the value
-                        Entry<K,V> pEntry = (Entry<K,V>)p.entry;
-                        pEntry.value = newValue;
-                        pEntry.recordAccess(this);
-                    } else { // need to put new node
-                        p = tb.putTreeNode(hash, key, newValue, null);
-                        // assert p == null; // should have added a new node
-                        modCount++;
-                        size++;
-                        if (size >= threshold) {
-                            resize(2 * table.length);
-                        }
-                    }
-                }
-            }
-            return newValue;
-        }
-
-        V newValue = remappingFunction.apply(key, null);
-        if (newValue != null) {
-            modCount++;
-            addEntry(hash, key, newValue, i, checkIfNeedTree);
-        }
-
-        return newValue;
-    }
-
-    @Override
-    public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
-        if (table == EMPTY_TABLE) {
-            inflateTable(threshold);
-        }
-        if (key == null) {
-            V oldValue = nullKeyEntry == null ? null : nullKeyEntry.value;
-            V newValue = oldValue == null ? value : remappingFunction.apply(oldValue, value);
-            if (newValue != null) {
-                putForNullKey(newValue);
-            } else if (nullKeyEntry != null) {
-                removeNullKey();
-            }
-            return newValue;
-        }
-        int hash = hash(key);
-        int i = indexFor(hash, table.length);
-        boolean checkIfNeedTree = false; // Might we convert bin to a TreeBin?
-
-        if (table[i] instanceof Entry) {
-            int listSize = 0;
-            @SuppressWarnings("unchecked")
-            Entry<K,V> prev = (Entry<K,V>)table[i];
-            Entry<K,V> e = prev;
-
-            while (e != null) {
-                Entry<K,V> next = (Entry<K,V>)e.next;
-                if (e.hash == hash && Objects.equals(e.key, key)) {
-                    V oldValue = e.value;
-                    V newValue = (oldValue == null) ? value :
-                                 remappingFunction.apply(oldValue, value);
-                    if (newValue == null) {
-                        modCount++;
-                        size--;
-                        if (prev == e)
-                            table[i] = next;
-                        else
-                            prev.next = next;
-                        e.recordRemoval(this);
-                    } else {
-                        e.value = newValue;
-                        e.recordAccess(this);
-                    }
-                    return newValue;
-                }
-                prev = e;
-                e = next;
-                listSize++;
-            }
-            // Didn't find, so fall through and (maybe) call addEntry() to add
-            // the Entry and check for TreeBin conversion.
-            checkIfNeedTree = listSize >= TreeBin.TREE_THRESHOLD;
-        } else if (table[i] != null) {
-            TreeBin tb = (TreeBin)table[i];
-            TreeNode p = tb.getTreeNode(hash, key);
-            V oldValue = p == null ? null : (V)p.entry.value;
-            V newValue = (oldValue == null) ? value :
-                         remappingFunction.apply(oldValue, value);
-            if (newValue == null) {
-                if (p != null) {
-                    Entry<K,V> pEntry = (Entry<K,V>)p.entry;
-                    modCount++;
-                    size--;
-                    tb.deleteTreeNode(p);
-                    pEntry.recordRemoval(this);
-
-                    if (tb.root == null || tb.first == null) {
-                        // assert tb.root == null && tb.first == null :
-                        //         "TreeBin.first and root should both be null";
-                        // TreeBin is now empty, we should blank this bin
-                        table[i] = null;
-                    }
-                }
-                return null;
-            } else if (newValue != oldValue) {
-                if (p != null) { // just update the value
-                    Entry<K,V> pEntry = (Entry<K,V>)p.entry;
-                    pEntry.value = newValue;
-                    pEntry.recordAccess(this);
-                } else { // need to put new node
-                    p = tb.putTreeNode(hash, key, newValue, null);
-                    // assert p == null; // should have added a new node
-                    modCount++;
-                    size++;
-                    if (size >= threshold) {
-                        resize(2 * table.length);
-                    }
-                }
-            }
-            return newValue;
-        }
-        if (value != null) {
-            modCount++;
-            addEntry(hash, key, value, i, checkIfNeedTree);
-        }
-        return value;
-    }
-
-    // end of optimized implementations of default methods in Map
-
-    /**
-     * Removes and returns the entry associated with the specified key
-     * in the HashMap.  Returns null if the HashMap contains no mapping
-     * for this key.
-     *
-     * We don't bother converting TreeBins back to Entry lists if the bin falls
-     * back below TREE_THRESHOLD, but we do clear bins when removing the last
-     * TreeNode in a TreeBin.
-     */
-    final Entry<K,V> removeEntryForKey(Object key) {
-        if (size == 0) {
-            return null;
-        }
-        if (key == null) {
-            if (nullKeyEntry != null) {
-                return removeNullKey();
-            }
-            return null;
-        }
-        int hash = hash(key);
-        int i = indexFor(hash, table.length);
-
-        if (table[i] instanceof Entry) {
-            @SuppressWarnings("unchecked")
-            Entry<K,V> prev = (Entry<K,V>)table[i];
-            Entry<K,V> e = prev;
-
-            while (e != null) {
-                @SuppressWarnings("unchecked")
-                Entry<K,V> next = (Entry<K,V>) e.next;
-                if (e.hash == hash && Objects.equals(e.key, key)) {
-                    modCount++;
-                    size--;
-                    if (prev == e)
-                        table[i] = next;
-                    else
-                        prev.next = next;
-                    e.recordRemoval(this);
-                    return e;
-                }
-                prev = e;
-                e = next;
-            }
-        } else if (table[i] != null) {
-            TreeBin tb = ((TreeBin) table[i]);
-            TreeNode p = tb.getTreeNode(hash, (K)key);
-            if (p != null) {
-                Entry<K,V> pEntry = (Entry<K,V>)p.entry;
-                // assert pEntry.key.equals(key);
-                modCount++;
-                size--;
-                tb.deleteTreeNode(p);
-                pEntry.recordRemoval(this);
-                if (tb.root == null || tb.first == null) {
-                    // assert tb.root == null && tb.first == null :
-                    //             "TreeBin.first and root should both be null";
-                    // TreeBin is now empty, we should blank this bin
-                    table[i] = null;
-                }
-                return pEntry;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Special version of remove for EntrySet using {@code Map.Entry.equals()}
-     * for matching.
-     */
-    final Entry<K,V> removeMapping(Object o) {
-        if (size == 0 || !(o instanceof Map.Entry))
-            return null;
-
-        Map.Entry<?,?> entry = (Map.Entry<?,?>) o;
-        Object key = entry.getKey();
-
-        if (key == null) {
-            if (entry.equals(nullKeyEntry)) {
-                return removeNullKey();
-            }
-            return null;
-        }
-
-        int hash = hash(key);
-        int i = indexFor(hash, table.length);
-
-        if (table[i] instanceof Entry) {
-            @SuppressWarnings("unchecked")
-                Entry<K,V> prev = (Entry<K,V>)table[i];
-            Entry<K,V> e = prev;
-
-            while (e != null) {
-                @SuppressWarnings("unchecked")
-                Entry<K,V> next = (Entry<K,V>)e.next;
-                if (e.hash == hash && e.equals(entry)) {
-                    modCount++;
-                    size--;
-                    if (prev == e)
-                        table[i] = next;
-                    else
-                        prev.next = next;
-                    e.recordRemoval(this);
-                    return e;
-                }
-                prev = e;
-                e = next;
-            }
-        } else if (table[i] != null) {
-            TreeBin tb = ((TreeBin) table[i]);
-            TreeNode p = tb.getTreeNode(hash, (K)key);
-            if (p != null && p.entry.equals(entry)) {
-                @SuppressWarnings("unchecked")
-                Entry<K,V> pEntry = (Entry<K,V>)p.entry;
-                // assert pEntry.key.equals(key);
-                modCount++;
-                size--;
-                tb.deleteTreeNode(p);
-                pEntry.recordRemoval(this);
-                if (tb.root == null || tb.first == null) {
-                    // assert tb.root == null && tb.first == null :
-                    //             "TreeBin.first and root should both be null";
-                    // TreeBin is now empty, we should blank this bin
-                    table[i] = null;
-                }
-                return pEntry;
-            }
-        }
-        return null;
-    }
-
-    /*
-     * Remove the mapping for the null key, and update internal accounting
-     * (size, modcount, recordRemoval, etc).
-     *
-     * Assumes nullKeyEntry is non-null.
-     */
-    private Entry<K,V> removeNullKey() {
-        // assert nullKeyEntry != null;
-        Entry<K,V> retVal = nullKeyEntry;
-        modCount++;
-        size--;
-        retVal.recordRemoval(this);
-        nullKeyEntry = null;
-        return retVal;
-    }
-
     /**
      * Removes all of the mappings from this map.
      * The map will be empty after this call returns.
      */
     public void clear() {
+        Node<K,V>[] tab;
         modCount++;
-        if (nullKeyEntry != null) {
-            nullKeyEntry = null;
+        if ((tab = table) != null && size > 0) {
+            size = 0;
+            for (int i = 0; i < tab.length; ++i)
+                tab[i] = null;
         }
-        Arrays.fill(table, null);
-        size = 0;
     }
 
     /**
@@ -2134,352 +873,20 @@
      *         specified value
      */
     public boolean containsValue(Object value) {
-        if (value == null) {
-            return containsNullValue();
-        }
-        Object[] tab = table;
-        for (int i = 0; i < tab.length; i++) {
-            if (tab[i] instanceof Entry) {
-                Entry<?,?> e = (Entry<?,?>)tab[i];
-                for (; e != null; e = (Entry<?,?>)e.next) {
-                    if (value.equals(e.value)) {
-                        return true;
-                    }
-                }
-            } else if (tab[i] != null) {
-                TreeBin e = (TreeBin)tab[i];
-                TreeNode p = e.first;
-                for (; p != null; p = (TreeNode) p.entry.next) {
-                    if (value == p.entry.value || value.equals(p.entry.value)) {
+        Node<K,V>[] tab; V v;
+        if ((tab = table) != null && size > 0) {
+            for (int i = 0; i < tab.length; ++i) {
+                for (Node<K,V> e = tab[i]; e != null; e = e.next) {
+                    if ((v = e.value) == value ||
+                        (value != null && value.equals(v)))
                         return true;
-                    }
-                }
-            }
-        }
-        // Didn't find value in table - could be in nullKeyEntry
-        return (nullKeyEntry != null && (value == nullKeyEntry.value ||
-                                         value.equals(nullKeyEntry.value)));
-    }
-
-    /**
-     * Special-case code for containsValue with null argument
-     */
-    private boolean containsNullValue() {
-        Object[] tab = table;
-        for (int i = 0; i < tab.length; i++) {
-            if (tab[i] instanceof Entry) {
-                Entry<K,V> e = (Entry<K,V>)tab[i];
-                for (; e != null; e = (Entry<K,V>)e.next) {
-                    if (e.value == null) {
-                        return true;
-                    }
-                }
-            } else if (tab[i] != null) {
-                TreeBin e = (TreeBin)tab[i];
-                TreeNode p = e.first;
-                for (; p != null; p = (TreeNode) p.entry.next) {
-                    if (p.entry.value == null) {
-                        return true;
-                    }
                 }
             }
         }
-        // Didn't find value in table - could be in nullKeyEntry
-        return (nullKeyEntry != null && nullKeyEntry.value == null);
-    }
-
-    /**
-     * Returns a shallow copy of this <tt>HashMap</tt> instance: the keys and
-     * values themselves are not cloned.
-     *
-     * @return a shallow copy of this map
-     */
-    @SuppressWarnings("unchecked")
-    public Object clone() {
-        HashMap<K,V> result = null;
-        try {
-            result = (HashMap<K,V>)super.clone();
-        } catch (CloneNotSupportedException e) {
-            // assert false;
-        }
-        if (result.table != EMPTY_TABLE) {
-            result.inflateTable(Math.min(
-                (int) Math.min(
-                    size * Math.min(1 / loadFactor, 4.0f),
-                    // we have limits...
-                    HashMap.MAXIMUM_CAPACITY),
-                table.length));
-        }
-        result.entrySet = null;
-        result.modCount = 0;
-        result.size = 0;
-        result.nullKeyEntry = null;
-        result.init();
-        result.putAllForCreate(this);
-
-        return result;
-    }
-
-    static class Entry<K,V> implements Map.Entry<K,V> {
-        final K key;
-        V value;
-        Object next; // an Entry, or a TreeNode
-        final int hash;
-
-        /**
-         * Creates new entry.
-         */
-        Entry(int h, K k, V v, Object n) {
-            value = v;
-            next = n;
-            key = k;
-            hash = h;
-        }
-
-        public final K getKey() {
-            return key;
-        }
-
-        public final V getValue() {
-            return value;
-        }
-
-        public final V setValue(V newValue) {
-            V oldValue = value;
-            value = newValue;
-            return oldValue;
-        }
-
-        public final boolean equals(Object o) {
-            if (!(o instanceof Map.Entry))
-                return false;
-            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
-            Object k1 = getKey();
-            Object k2 = e.getKey();
-            if (k1 == k2 || (k1 != null && k1.equals(k2))) {
-                Object v1 = getValue();
-                Object v2 = e.getValue();
-                if (v1 == v2 || (v1 != null && v1.equals(v2)))
-                    return true;
-                }
-            return false;
-        }
-
-        public final int hashCode() {
-            return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue());
-        }
-
-        public final String toString() {
-            return getKey() + "=" + getValue();
-        }
-
-        /**
-         * This method is invoked whenever the value in an entry is
-         * overwritten for a key that's already in the HashMap.
-         */
-        void recordAccess(HashMap<K,V> m) {
-        }
-
-        /**
-         * This method is invoked whenever the entry is
-         * removed from the table.
-         */
-        void recordRemoval(HashMap<K,V> m) {
-        }
-    }
-
-    void addEntry(int hash, K key, V value, int bucketIndex) {
-        addEntry(hash, key, value, bucketIndex, true);
-    }
-
-    /**
-     * Adds a new entry with the specified key, value and hash code to
-     * the specified bucket.  It is the responsibility of this
-     * method to resize the table if appropriate.  The new entry is then
-     * created by calling createEntry().
-     *
-     * Subclass overrides this to alter the behavior of put method.
-     *
-     * If checkIfNeedTree is false, it is known that this bucket will not need
-     * to be converted to a TreeBin, so don't bothering checking.
-     *
-     * Assumes key is not null.
-     */
-    void addEntry(int hash, K key, V value, int bucketIndex, boolean checkIfNeedTree) {
-        // assert key != null;
-        if ((size >= threshold) && (null != table[bucketIndex])) {
-            resize(2 * table.length);
-            hash = hash(key);
-            bucketIndex = indexFor(hash, table.length);
-        }
-        createEntry(hash, key, value, bucketIndex, checkIfNeedTree);
+        return false;
     }
 
     /**
-     * Called by addEntry(), and also used when creating entries
-     * as part of Map construction or "pseudo-construction" (cloning,
-     * deserialization).  This version does not check for resizing of the table.
-     *
-     * This method is responsible for converting a bucket to a TreeBin once
-     * TREE_THRESHOLD is reached. However if checkIfNeedTree is false, it is known
-     * that this bucket will not need to be converted to a TreeBin, so don't
-     * bother checking.  The new entry is constructed by calling newEntry().
-     *
-     * Assumes key is not null.
-     *
-     * Note: buckets already converted to a TreeBin don't call this method, but
-     * instead call TreeBin.putTreeNode() to create new entries.
-     */
-    void createEntry(int hash, K key, V value, int bucketIndex, boolean checkIfNeedTree) {
-        // assert key != null;
-        @SuppressWarnings("unchecked")
-            Entry<K,V> e = (Entry<K,V>)table[bucketIndex];
-        table[bucketIndex] = newEntry(hash, key, value, e);
-        size++;
-
-        if (checkIfNeedTree) {
-            int listSize = 0;
-            for (e = (Entry<K,V>) table[bucketIndex]; e != null; e = (Entry<K,V>)e.next) {
-                listSize++;
-                if (listSize >= TreeBin.TREE_THRESHOLD) { // Convert to TreeBin
-                    if (comparableClassFor(key) != null) {
-                        TreeBin t = new TreeBin();
-                        t.populate((Entry)table[bucketIndex]);
-                        table[bucketIndex] = t;
-                    }
-                    break;
-                }
-            }
-        }
-    }
-
-    /*
-     * Factory method to create a new Entry object.
-     */
-    Entry<K,V> newEntry(int hash, K key, V value, Object next) {
-        return new HashMap.Entry<>(hash, key, value, next);
-    }
-
-
-    private abstract class HashIterator<E> implements Iterator<E> {
-        Object next;            // next entry to return, an Entry or a TreeNode
-        int expectedModCount;   // For fast-fail
-        int index;              // current slot
-        Object current;         // current entry, an Entry or a TreeNode
-
-        HashIterator() {
-            expectedModCount = modCount;
-            if (size > 0) { // advance to first entry
-                if (nullKeyEntry != null) {
-                    // assert nullKeyEntry.next == null;
-                    // This works with nextEntry(): nullKeyEntry isa Entry, and
-                    // e.next will be null, so we'll hit the findNextBin() call.
-                    next = nullKeyEntry;
-                } else {
-                    findNextBin();
-                }
-            }
-        }
-
-        public final boolean hasNext() {
-            return next != null;
-        }
-
-        @SuppressWarnings("unchecked")
-        final Entry<K,V> nextEntry() {
-            if (modCount != expectedModCount) {
-                throw new ConcurrentModificationException();
-            }
-            Object e = next;
-            Entry<K,V> retVal;
-
-            if (e == null)
-                throw new NoSuchElementException();
-
-            if (e instanceof TreeNode) { // TreeBin
-                retVal = (Entry<K,V>)((TreeNode)e).entry;
-                next = retVal.next;
-            } else {
-                retVal = (Entry<K,V>)e;
-                next = ((Entry<K,V>)e).next;
-            }
-
-            if (next == null) { // Move to next bin
-                findNextBin();
-            }
-            current = e;
-            return retVal;
-        }
-
-        public void remove() {
-            if (current == null)
-                throw new IllegalStateException();
-            if (modCount != expectedModCount)
-                throw new ConcurrentModificationException();
-            K k;
-
-            if (current instanceof Entry) {
-                k = ((Entry<K,V>)current).key;
-            } else {
-                k = ((Entry<K,V>)((TreeNode)current).entry).key;
-
-            }
-            current = null;
-            HashMap.this.removeEntryForKey(k);
-            expectedModCount = modCount;
-        }
-
-        /*
-         * Set 'next' to the first entry of the next non-empty bin in the table
-         */
-        private void findNextBin() {
-            // assert next == null;
-            Object[] t = table;
-
-            while (index < t.length && (next = t[index++]) == null)
-                ;
-            if (next instanceof HashMap.TreeBin) { // Point to the first TreeNode
-                next = ((TreeBin) next).first;
-                // assert next != null; // There should be no empty TreeBins
-            }
-        }
-    }
-
-    private final class ValueIterator extends HashIterator<V> {
-        public V next() {
-            return nextEntry().value;
-        }
-    }
-
-    private final class KeyIterator extends HashIterator<K> {
-        public K next() {
-            return nextEntry().getKey();
-        }
-    }
-
-    private final class EntryIterator extends HashIterator<Map.Entry<K,V>> {
-        public Map.Entry<K,V> next() {
-            return nextEntry();
-        }
-    }
-
-    // Subclass overrides these to alter behavior of views' iterator() method
-    Iterator<K> newKeyIterator()   {
-        return new KeyIterator();
-    }
-    Iterator<V> newValueIterator()   {
-        return new ValueIterator();
-    }
-    Iterator<Map.Entry<K,V>> newEntryIterator()   {
-        return new EntryIterator();
-    }
-
-
-    // Views
-
-    private transient Set<Map.Entry<K,V>> entrySet = null;
-
-    /**
      * Returns a {@link Set} view of the keys contained in this map.
      * The set is backed by the map, so changes to the map are
      * reflected in the set, and vice-versa.  If the map is modified
@@ -2491,35 +898,38 @@
      * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
      * operations.  It does not support the <tt>add</tt> or <tt>addAll</tt>
      * operations.
+     *
+     * @return a set view of the keys contained in this map
      */
     public Set<K> keySet() {
-        Set<K> ks = keySet;
-        return (ks != null ? ks : (keySet = new KeySet()));
+        Set<K> ks;
+        return (ks = keySet) == null ? (keySet = new KeySet()) : ks;
     }
 
-    private final class KeySet extends AbstractSet<K> {
-        public Iterator<K> iterator() {
-            return newKeyIterator();
+    final class KeySet extends AbstractSet<K> {
+        public final int size()                 { return size; }
+        public final void clear()               { HashMap.this.clear(); }
+        public final Iterator<K> iterator()     { return new KeyIterator(); }
+        public final boolean contains(Object o) { return containsKey(o); }
+        public final boolean remove(Object key) {
+            return removeNode(hash(key), key, null, false, true) != null;
         }
-        public int size() {
-            return size;
-        }
-        public boolean contains(Object o) {
-            return containsKey(o);
+        public final Spliterator<K> spliterator() {
+            return new KeySpliterator<K,V>(HashMap.this, 0, -1, 0, 0);
         }
-        public boolean remove(Object o) {
-            return HashMap.this.removeEntryForKey(o) != null;
-        }
-        public void clear() {
-            HashMap.this.clear();
-        }
-
-        public Spliterator<K> spliterator() {
-            if (HashMap.this.getClass() == HashMap.class)
-                return new KeySpliterator<K,V>(HashMap.this, 0, -1, 0, 0);
-            else
-                return Spliterators.spliterator
-                        (this, Spliterator.SIZED | Spliterator.DISTINCT);
+        public final void forEach(Consumer<? super K> action) {
+            Node<K,V>[] tab;
+            if (action == null)
+                throw new NullPointerException();
+            if (size > 0 && (tab = table) != null) {
+                int mc = modCount;
+                for (int i = 0; i < tab.length; ++i) {
+                    for (Node<K,V> e = tab[i]; e != null; e = e.next)
+                        action.accept(e.key);
+                }
+                if (modCount != mc)
+                    throw new ConcurrentModificationException();
+            }
         }
     }
 
@@ -2535,32 +945,35 @@
      * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
      * <tt>retainAll</tt> and <tt>clear</tt> operations.  It does not
      * support the <tt>add</tt> or <tt>addAll</tt> operations.
+     *
+     * @return a view of the values contained in this map
      */
     public Collection<V> values() {
-        Collection<V> vs = values;
-        return (vs != null ? vs : (values = new Values()));
+        Collection<V> vs;
+        return (vs = values) == null ? (values = new Values()) : vs;
     }
 
-    private final class Values extends AbstractCollection<V> {
-        public Iterator<V> iterator() {
-            return newValueIterator();
-        }
-        public int size() {
-            return size;
-        }
-        public boolean contains(Object o) {
-            return containsValue(o);
+    final class Values extends AbstractCollection<V> {
+        public final int size()                 { return size; }
+        public final void clear()               { HashMap.this.clear(); }
+        public final Iterator<V> iterator()     { return new ValueIterator(); }
+        public final boolean contains(Object o) { return containsValue(o); }
+        public final Spliterator<V> spliterator() {
+            return new ValueSpliterator<K,V>(HashMap.this, 0, -1, 0, 0);
         }
-        public void clear() {
-            HashMap.this.clear();
-        }
-
-        public Spliterator<V> spliterator() {
-            if (HashMap.this.getClass() == HashMap.class)
-                return new ValueSpliterator<K,V>(HashMap.this, 0, -1, 0, 0);
-            else
-                return Spliterators.spliterator
-                        (this, Spliterator.SIZED);
+        public final void forEach(Consumer<? super V> action) {
+            Node<K,V>[] tab;
+            if (action == null)
+                throw new NullPointerException();
+            if (size > 0 && (tab = table) != null) {
+                int mc = modCount;
+                for (int i = 0; i < tab.length; ++i) {
+                    for (Node<K,V> e = tab[i]; e != null; e = e.next)
+                        action.accept(e.value);
+                }
+                if (modCount != mc)
+                    throw new ConcurrentModificationException();
+            }
         }
     }
 
@@ -2581,42 +994,324 @@
      * @return a set view of the mappings contained in this map
      */
     public Set<Map.Entry<K,V>> entrySet() {
-        return entrySet0();
+        Set<Map.Entry<K,V>> es;
+        return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
     }
 
-    private Set<Map.Entry<K,V>> entrySet0() {
-        Set<Map.Entry<K,V>> es = entrySet;
-        return es != null ? es : (entrySet = new EntrySet());
-    }
-
-    private final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
-        public Iterator<Map.Entry<K,V>> iterator() {
-            return newEntryIterator();
+    final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
+        public final int size()                 { return size; }
+        public final void clear()               { HashMap.this.clear(); }
+        public final Iterator<Map.Entry<K,V>> iterator() {
+            return new EntryIterator();
         }
-        public boolean contains(Object o) {
+        public final boolean contains(Object o) {
             if (!(o instanceof Map.Entry))
                 return false;
             Map.Entry<?,?> e = (Map.Entry<?,?>) o;
-            Entry<K,V> candidate = getEntry(e.getKey());
+            Object key = e.getKey();
+            Node<K,V> candidate = getNode(hash(key), key);
             return candidate != null && candidate.equals(e);
         }
-        public boolean remove(Object o) {
-            return removeMapping(o) != null;
+        public final boolean remove(Object o) {
+            if (o instanceof Map.Entry) {
+                Map.Entry<?,?> e = (Map.Entry<?,?>) o;
+                Object key = e.getKey();
+                Object value = e.getValue();
+                return removeNode(hash(key), key, value, true, true) != null;
+            }
+            return false;
+        }
+        public final Spliterator<Map.Entry<K,V>> spliterator() {
+            return new EntrySpliterator<K,V>(HashMap.this, 0, -1, 0, 0);
+        }
+        public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
+            Node<K,V>[] tab;
+            if (action == null)
+                throw new NullPointerException();
+            if (size > 0 && (tab = table) != null) {
+                int mc = modCount;
+                for (int i = 0; i < tab.length; ++i) {
+                    for (Node<K,V> e = tab[i]; e != null; e = e.next)
+                        action.accept(e);
+                }
+                if (modCount != mc)
+                    throw new ConcurrentModificationException();
+            }
+        }
+    }
+
+    // Overrides of JDK8 Map extension methods
+
+    public V getOrDefault(Object key, V defaultValue) {
+        Node<K,V> e;
+        return (e = getNode(hash(key), key)) == null ? defaultValue : e.value;
+    }
+
+    public V putIfAbsent(K key, V value) {
+        return putVal(hash(key), key, value, true, true);
+    }
+
+    public boolean remove(Object key, Object value) {
+        return removeNode(hash(key), key, value, true, true) != null;
+    }
+
+    public boolean replace(K key, V oldValue, V newValue) {
+        Node<K,V> e; V v;
+        if ((e = getNode(hash(key), key)) != null &&
+            ((v = e.value) == oldValue || (v != null && v.equals(oldValue)))) {
+            e.value = newValue;
+            afterNodeAccess(e);
+            return true;
+        }
+        return false;
+    }
+
+    public V replace(K key, V value) {
+        Node<K,V> e;
+        if ((e = getNode(hash(key), key)) != null) {
+            V oldValue = e.value;
+            e.value = value;
+            afterNodeAccess(e);
+            return oldValue;
         }
-        public int size() {
-            return size;
+        return null;
+    }
+
+    public V computeIfAbsent(K key,
+                             Function<? super K, ? extends V> mappingFunction) {
+        if (mappingFunction == null)
+            throw new NullPointerException();
+        int hash = hash(key);
+        Node<K,V>[] tab; Node<K,V> first; int n, i;
+        int binCount = 0;
+        TreeNode<K,V> t = null;
+        Node<K,V> old = null;
+        if (size > threshold || (tab = table) == null ||
+            (n = tab.length) == 0)
+            n = (tab = resize()).length;
+        if ((first = tab[i = (n - 1) & hash]) != null) {
+            if (first instanceof TreeNode)
+                old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
+            else {
+                Node<K,V> e = first; K k;
+                do {
+                    if (e.hash == hash &&
+                        ((k = e.key) == key || (key != null && key.equals(k)))) {
+                        old = e;
+                        break;
+                    }
+                    ++binCount;
+                } while ((e = e.next) != null);
+            }
+            V oldValue;
+            if (old != null && (oldValue = old.value) != null) {
+                afterNodeAccess(old);
+                return oldValue;
+            }
         }
-        public void clear() {
-            HashMap.this.clear();
+        V v = mappingFunction.apply(key);
+        if (old != null) {
+            old.value = v;
+            afterNodeAccess(old);
+            return v;
+        }
+        else if (v == null)
+            return null;
+        else if (t != null)
+            t.putTreeVal(this, tab, hash, key, v);
+        else {
+            tab[i] = newNode(hash, key, v, first);
+            if (binCount >= TREEIFY_THRESHOLD - 1)
+                treeifyBin(tab, hash);
+        }
+        ++modCount;
+        ++size;
+        afterNodeInsertion(true);
+        return v;
+    }
+
+    public V computeIfPresent(K key,
+                              BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        Node<K,V> e; V oldValue;
+        int hash = hash(key);
+        if ((e = getNode(hash, key)) != null &&
+            (oldValue = e.value) != null) {
+            V v = remappingFunction.apply(key, oldValue);
+            if (v != null) {
+                e.value = v;
+                afterNodeAccess(e);
+                return v;
+            }
+            else
+                removeNode(hash, key, null, false, true);
         }
+        return null;
+    }
 
-        public Spliterator<Map.Entry<K,V>> spliterator() {
-            if (HashMap.this.getClass() == HashMap.class)
-                return new EntrySpliterator<K,V>(HashMap.this, 0, -1, 0, 0);
+    public V compute(K key,
+                     BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+        if (remappingFunction == null)
+            throw new NullPointerException();
+        int hash = hash(key);
+        Node<K,V>[] tab; Node<K,V> first; int n, i;
+        int binCount = 0;
+        TreeNode<K,V> t = null;
+        Node<K,V> old = null;
+        if (size > threshold || (tab = table) == null ||
+            (n = tab.length) == 0)
+            n = (tab = resize()).length;
+        if ((first = tab[i = (n - 1) & hash]) != null) {
+            if (first instanceof TreeNode)
+                old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
+            else {
+                Node<K,V> e = first; K k;
+                do {
+                    if (e.hash == hash &&
+                        ((k = e.key) == key || (key != null && key.equals(k)))) {
+                        old = e;
+                        break;
+                    }
+                    ++binCount;
+                } while ((e = e.next) != null);
+            }
+        }
+        V oldValue = (old == null) ? null : old.value;
+        V v = remappingFunction.apply(key, oldValue);
+        if (old != null) {
+            if (v != null) {
+                old.value = v;
+                afterNodeAccess(old);
+            }
             else
-                return Spliterators.spliterator
-                        (this, Spliterator.SIZED | Spliterator.DISTINCT);
+                removeNode(hash, key, null, false, true);
+        }
+        else if (v != null) {
+            if (t != null)
+                t.putTreeVal(this, tab, hash, key, v);
+            else {
+                tab[i] = newNode(hash, key, v, first);
+                if (binCount >= TREEIFY_THRESHOLD - 1)
+                    treeifyBin(tab, hash);
+            }
+            ++modCount;
+            ++size;
+            afterNodeInsertion(true);
+        }
+        return v;
+    }
+
+    public V merge(K key, V value,
+                   BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+        if (remappingFunction == null)
+            throw new NullPointerException();
+        int hash = hash(key);
+        Node<K,V>[] tab; Node<K,V> first; int n, i;
+        int binCount = 0;
+        TreeNode<K,V> t = null;
+        Node<K,V> old = null;
+        if (size > threshold || (tab = table) == null ||
+            (n = tab.length) == 0)
+            n = (tab = resize()).length;
+        if ((first = tab[i = (n - 1) & hash]) != null) {
+            if (first instanceof TreeNode)
+                old = (t = (TreeNode<K,V>)first).getTreeNode(hash, key);
+            else {
+                Node<K,V> e = first; K k;
+                do {
+                    if (e.hash == hash &&
+                        ((k = e.key) == key || (key != null && key.equals(k)))) {
+                        old = e;
+                        break;
+                    }
+                    ++binCount;
+                } while ((e = e.next) != null);
+            }
+        }
+        if (old != null) {
+            V v = remappingFunction.apply(old.value, value);
+            if (v != null) {
+                old.value = v;
+                afterNodeAccess(old);
+            }
+            else
+                removeNode(hash, key, null, false, true);
+            return v;
         }
+        if (value != null) {
+            if (t != null)
+                t.putTreeVal(this, tab, hash, key, value);
+            else {
+                tab[i] = newNode(hash, key, value, first);
+                if (binCount >= TREEIFY_THRESHOLD - 1)
+                    treeifyBin(tab, hash);
+            }
+            ++modCount;
+            ++size;
+            afterNodeInsertion(true);
+        }
+        return value;
+    }
+
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        Node<K,V>[] tab;
+        if (action == null)
+            throw new NullPointerException();
+        if (size > 0 && (tab = table) != null) {
+            int mc = modCount;
+            for (int i = 0; i < tab.length; ++i) {
+                for (Node<K,V> e = tab[i]; e != null; e = e.next)
+                    action.accept(e.key, e.value);
+            }
+            if (modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        Node<K,V>[] tab;
+        if (function == null)
+            throw new NullPointerException();
+        if (size > 0 && (tab = table) != null) {
+            int mc = modCount;
+            for (int i = 0; i < tab.length; ++i) {
+                for (Node<K,V> e = tab[i]; e != null; e = e.next) {
+                    e.value = function.apply(e.key, e.value);
+                }
+            }
+            if (modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    // Cloning and serialization
+
+    /**
+     * Returns a shallow copy of this <tt>HashMap</tt> instance: the keys and
+     * values themselves are not cloned.
+     *
+     * @return a shallow copy of this map
+     */
+    @SuppressWarnings("unchecked")
+    public Object clone() {
+        HashMap<K,V> result;
+        try {
+            result = (HashMap<K,V>)super.clone();
+        } catch (CloneNotSupportedException e) {
+            // this shouldn't happen, since we are Cloneable
+            throw new InternalError(e);
+        }
+        result.reinitialize();
+        result.putMapEntries(this, false);
+        return result;
+    }
+
+    // These methods are also used when serializing HashSets
+    final float loadFactor() { return loadFactor; }
+    final int capacity() {
+        return (table != null) ? table.length :
+            (threshold > 0) ? threshold :
+            DEFAULT_INITIAL_CAPACITY;
     }
 
     /**
@@ -2631,118 +1326,143 @@
      *             emitted in no particular order.
      */
     private void writeObject(java.io.ObjectOutputStream s)
-        throws IOException
-    {
+        throws IOException {
+        int buckets = capacity();
         // Write out the threshold, loadfactor, and any hidden stuff
         s.defaultWriteObject();
-
-        // Write out number of buckets
-        if (table==EMPTY_TABLE) {
-            s.writeInt(roundUpToPowerOf2(threshold));
-        } else {
-            s.writeInt(table.length);
-        }
-
-        // Write out size (number of Mappings)
+        s.writeInt(buckets);
         s.writeInt(size);
-
-        // Write out keys and values (alternating)
-        if (size > 0) {
-            for(Map.Entry<K,V> e : entrySet0()) {
-                s.writeObject(e.getKey());
-                s.writeObject(e.getValue());
-            }
-        }
+        internalWriteEntries(s);
     }
 
-    private static final long serialVersionUID = 362498820763181265L;
-
     /**
      * Reconstitute the {@code HashMap} instance from a stream (i.e.,
      * deserialize it).
      */
     private void readObject(java.io.ObjectInputStream s)
-         throws IOException, ClassNotFoundException
-    {
+        throws IOException, ClassNotFoundException {
         // Read in the threshold (ignored), loadfactor, and any hidden stuff
         s.defaultReadObject();
-        if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
+        reinitialize();
+        if (loadFactor <= 0 || Float.isNaN(loadFactor))
             throw new InvalidObjectException("Illegal load factor: " +
-                                               loadFactor);
-        }
-
-        // set other fields that need values
-        if (Holder.USE_HASHSEED) {
-            int seed = ThreadLocalRandom.current().nextInt();
-            Holder.UNSAFE.putIntVolatile(this, Holder.HASHSEED_OFFSET,
-                                         (seed != 0) ? seed : 1);
-        }
-        table = EMPTY_TABLE;
-
-        // Read in number of buckets
-        s.readInt(); // ignored.
-
-        // Read number of mappings
-        int mappings = s.readInt();
+                                             loadFactor);
+        s.readInt();                // Read and ignore number of buckets
+        int mappings = s.readInt(); // Read number of mappings (size)
         if (mappings < 0)
             throw new InvalidObjectException("Illegal mappings count: " +
-                                               mappings);
-
-        // capacity chosen by number of mappings and desired load (if >= 0.25)
-        int capacity = (int) Math.min(
-                mappings * Math.min(1 / loadFactor, 4.0f),
-                // we have limits...
-                HashMap.MAXIMUM_CAPACITY);
+                                             mappings);
+        else if (mappings > 0) { // (if zero, use defaults)
+            // Size the table using given load factor only if within
+            // range of 0.25...4.0
+            float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f);
+            float fc = (float)mappings / lf + 1.0f;
+            int cap = ((fc < DEFAULT_INITIAL_CAPACITY) ?
+                       DEFAULT_INITIAL_CAPACITY :
+                       (fc >= MAXIMUM_CAPACITY) ?
+                       MAXIMUM_CAPACITY :
+                       tableSizeFor((int)fc));
+            float ft = (float)cap * lf;
+            threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?
+                         (int)ft : Integer.MAX_VALUE);
+            @SuppressWarnings({"rawtypes","unchecked"})
+                Node<K,V>[] tab = (Node<K,V>[])new Node[cap];
+            table = tab;
 
-        // allocate the bucket array;
-        if (mappings > 0) {
-            inflateTable(capacity);
-        } else {
-            threshold = capacity;
-        }
-
-        init();  // Give subclass a chance to do its thing.
-
-        // Read the keys and values, and put the mappings in the HashMap
-        for (int i=0; i<mappings; i++) {
-            @SuppressWarnings("unchecked")
-            K key = (K) s.readObject();
-            @SuppressWarnings("unchecked")
-            V value = (V) s.readObject();
-            putForCreate(key, value);
+            // Read the keys and values, and put the mappings in the HashMap
+            for (int i = 0; i < mappings; i++) {
+                @SuppressWarnings("unchecked")
+                    K key = (K) s.readObject();
+                @SuppressWarnings("unchecked")
+                    V value = (V) s.readObject();
+                putVal(hash(key), key, value, false, false);
+            }
         }
     }
 
-    // These methods are used when serializing HashSets
-    int   capacity()     { return table.length; }
-    float loadFactor()   { return loadFactor;   }
+    /* ------------------------------------------------------------ */
+    // iterators
+
+    abstract class HashIterator {
+        Node<K,V> next;        // next entry to return
+        Node<K,V> current;     // current entry
+        int expectedModCount;  // for fast-fail
+        int index;             // current slot
+
+        HashIterator() {
+            expectedModCount = modCount;
+            Node<K,V>[] t = table;
+            current = next = null;
+            index = 0;
+            if (t != null && size > 0) { // advance to first entry
+                do {} while (index < t.length && (next = t[index++]) == null);
+            }
+        }
+
+        public final boolean hasNext() {
+            return next != null;
+        }
 
-    /**
-     * Standin until HM overhaul; based loosely on Weak and Identity HM.
-     */
+        final Node<K,V> nextNode() {
+            Node<K,V>[] t;
+            Node<K,V> e = next;
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            if (e == null)
+                throw new NoSuchElementException();
+            if ((next = (current = e).next) == null && (t = table) != null) {
+                do {} while (index < t.length && (next = t[index++]) == null);
+            }
+            return e;
+        }
+
+        public final void remove() {
+            Node<K,V> p = current;
+            if (p == null)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            current = null;
+            K key = p.key;
+            removeNode(hash(key), key, null, false, false);
+            expectedModCount = modCount;
+        }
+    }
+
+    final class KeyIterator extends HashIterator
+        implements Iterator<K> {
+        public final K next() { return nextNode().key; }
+    }
+
+    final class ValueIterator extends HashIterator
+        implements Iterator<V> {
+        public final V next() { return nextNode().value; }
+    }
+
+    final class EntryIterator extends HashIterator
+        implements Iterator<Map.Entry<K,V>> {
+        public final Map.Entry<K,V> next() { return nextNode(); }
+    }
+
+    /* ------------------------------------------------------------ */
+    // spliterators
+
     static class HashMapSpliterator<K,V> {
         final HashMap<K,V> map;
-        Object current;             // current node, can be Entry or TreeNode
+        Node<K,V> current;          // current node
         int index;                  // current index, modified on advance/split
         int fence;                  // one past last index
         int est;                    // size estimate
         int expectedModCount;       // for comodification checks
-        boolean acceptedNull;       // Have we accepted the null key?
-                                    // Without this, we can't distinguish
-                                    // between being at the very beginning (and
-                                    // needing to accept null), or being at the
-                                    // end of the list in bin 0.  In both cases,
-                                    // current == null && index == 0.
 
         HashMapSpliterator(HashMap<K,V> m, int origin,
-                               int fence, int est,
-                               int expectedModCount) {
+                           int fence, int est,
+                           int expectedModCount) {
             this.map = m;
             this.index = origin;
             this.fence = fence;
             this.est = est;
             this.expectedModCount = expectedModCount;
-            this.acceptedNull = false;
         }
 
         final int getFence() { // initialize fence and size on first use
@@ -2751,7 +1471,8 @@
                 HashMap<K,V> m = map;
                 est = m.size;
                 expectedModCount = m.modCount;
-                hi = fence = m.table.length;
+                Node<K,V>[] tab = m.table;
+                hi = fence = (tab == null) ? 0 : tab.length;
             }
             return hi;
         }
@@ -2772,56 +1493,33 @@
 
         public KeySpliterator<K,V> trySplit() {
             int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
-            if (lo >= mid || current != null) {
-                return null;
-            } else {
-                KeySpliterator<K,V> retVal = new KeySpliterator<K,V>(map, lo,
-                                     index = mid, est >>>= 1, expectedModCount);
-                // Only 'this' Spliterator chould check for null.
-                retVal.acceptedNull = true;
-                return retVal;
-            }
+            return (lo >= mid || current != null) ? null :
+                new KeySpliterator<K,V>(map, lo, index = mid, est >>>= 1,
+                                        expectedModCount);
         }
 
-        @SuppressWarnings("unchecked")
         public void forEachRemaining(Consumer<? super K> action) {
             int i, hi, mc;
             if (action == null)
                 throw new NullPointerException();
             HashMap<K,V> m = map;
-            Object[] tab = m.table;
+            Node<K,V>[] tab = m.table;
             if ((hi = fence) < 0) {
                 mc = expectedModCount = m.modCount;
-                hi = fence = tab.length;
+                hi = fence = (tab == null) ? 0 : tab.length;
             }
             else
                 mc = expectedModCount;
-
-            if (!acceptedNull) {
-                acceptedNull = true;
-                if (m.nullKeyEntry != null) {
-                    action.accept(m.nullKeyEntry.key);
-                }
-            }
-            if (tab.length >= hi && (i = index) >= 0 &&
-                (i < (index = hi) || current != null)) {
-                Object p = current;
+            if (tab != null && tab.length >= hi &&
+                (i = index) >= 0 && (i < (index = hi) || current != null)) {
+                Node<K,V> p = current;
                 current = null;
                 do {
-                    if (p == null) {
+                    if (p == null)
                         p = tab[i++];
-                        if (p instanceof HashMap.TreeBin) {
-                            p = ((HashMap.TreeBin)p).first;
-                        }
-                    } else {
-                        HashMap.Entry<K,V> entry;
-                        if (p instanceof HashMap.Entry) {
-                            entry = (HashMap.Entry<K,V>)p;
-                        } else {
-                            entry = (HashMap.Entry<K,V>)((TreeNode)p).entry;
-                        }
-                        action.accept(entry.key);
-                        p = entry.next;
+                    else {
+                        action.accept(p.key);
+                        p = p.next;
                     }
                 } while (p != null || i < hi);
                 if (m.modCount != mc)
@@ -2829,39 +1527,18 @@
             }
         }
 
-        @SuppressWarnings("unchecked")
         public boolean tryAdvance(Consumer<? super K> action) {
             int hi;
             if (action == null)
                 throw new NullPointerException();
-            Object[] tab = map.table;
-            hi = getFence();
-
-            if (!acceptedNull) {
-                acceptedNull = true;
-                if (map.nullKeyEntry != null) {
-                    action.accept(map.nullKeyEntry.key);
-                    if (map.modCount != expectedModCount)
-                        throw new ConcurrentModificationException();
-                    return true;
-                }
-            }
-            if (tab.length >= hi && index >= 0) {
+            Node<K,V>[] tab = map.table;
+            if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
                 while (current != null || index < hi) {
-                    if (current == null) {
+                    if (current == null)
                         current = tab[index++];
-                        if (current instanceof HashMap.TreeBin) {
-                            current = ((HashMap.TreeBin)current).first;
-                        }
-                    } else {
-                        HashMap.Entry<K,V> entry;
-                        if (current instanceof HashMap.Entry) {
-                            entry = (HashMap.Entry<K,V>)current;
-                        } else {
-                            entry = (HashMap.Entry<K,V>)((TreeNode)current).entry;
-                        }
-                        K k = entry.key;
-                        current = entry.next;
+                    else {
+                        K k = current.key;
+                        current = current.next;
                         action.accept(k);
                         if (map.modCount != expectedModCount)
                             throw new ConcurrentModificationException();
@@ -2888,56 +1565,33 @@
 
         public ValueSpliterator<K,V> trySplit() {
             int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
-            if (lo >= mid || current != null) {
-                return null;
-            } else {
-                ValueSpliterator<K,V> retVal = new ValueSpliterator<K,V>(map,
-                                 lo, index = mid, est >>>= 1, expectedModCount);
-                // Only 'this' Spliterator chould check for null.
-                retVal.acceptedNull = true;
-                return retVal;
-            }
+            return (lo >= mid || current != null) ? null :
+                new ValueSpliterator<K,V>(map, lo, index = mid, est >>>= 1,
+                                          expectedModCount);
         }
 
-        @SuppressWarnings("unchecked")
         public void forEachRemaining(Consumer<? super V> action) {
             int i, hi, mc;
             if (action == null)
                 throw new NullPointerException();
             HashMap<K,V> m = map;
-            Object[] tab = m.table;
+            Node<K,V>[] tab = m.table;
             if ((hi = fence) < 0) {
                 mc = expectedModCount = m.modCount;
-                hi = fence = tab.length;
+                hi = fence = (tab == null) ? 0 : tab.length;
             }
             else
                 mc = expectedModCount;
-
-            if (!acceptedNull) {
-                acceptedNull = true;
-                if (m.nullKeyEntry != null) {
-                    action.accept(m.nullKeyEntry.value);
-                }
-            }
-            if (tab.length >= hi && (i = index) >= 0 &&
-                (i < (index = hi) || current != null)) {
-                Object p = current;
+            if (tab != null && tab.length >= hi &&
+                (i = index) >= 0 && (i < (index = hi) || current != null)) {
+                Node<K,V> p = current;
                 current = null;
                 do {
-                    if (p == null) {
+                    if (p == null)
                         p = tab[i++];
-                        if (p instanceof HashMap.TreeBin) {
-                            p = ((HashMap.TreeBin)p).first;
-                        }
-                    } else {
-                        HashMap.Entry<K,V> entry;
-                        if (p instanceof HashMap.Entry) {
-                            entry = (HashMap.Entry<K,V>)p;
-                        } else {
-                            entry = (HashMap.Entry<K,V>)((TreeNode)p).entry;
-                        }
-                        action.accept(entry.value);
-                        p = entry.next;
+                    else {
+                        action.accept(p.value);
+                        p = p.next;
                     }
                 } while (p != null || i < hi);
                 if (m.modCount != mc)
@@ -2945,39 +1599,18 @@
             }
         }
 
-        @SuppressWarnings("unchecked")
         public boolean tryAdvance(Consumer<? super V> action) {
             int hi;
             if (action == null)
                 throw new NullPointerException();
-            Object[] tab = map.table;
-            hi = getFence();
-
-            if (!acceptedNull) {
-                acceptedNull = true;
-                if (map.nullKeyEntry != null) {
-                    action.accept(map.nullKeyEntry.value);
-                    if (map.modCount != expectedModCount)
-                        throw new ConcurrentModificationException();
-                    return true;
-                }
-            }
-            if (tab.length >= hi && index >= 0) {
+            Node<K,V>[] tab = map.table;
+            if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
                 while (current != null || index < hi) {
-                    if (current == null) {
+                    if (current == null)
                         current = tab[index++];
-                        if (current instanceof HashMap.TreeBin) {
-                            current = ((HashMap.TreeBin)current).first;
-                        }
-                    } else {
-                        HashMap.Entry<K,V> entry;
-                        if (current instanceof HashMap.Entry) {
-                            entry = (Entry<K,V>)current;
-                        } else {
-                            entry = (Entry<K,V>)((TreeNode)current).entry;
-                        }
-                        V v = entry.value;
-                        current = entry.next;
+                    else {
+                        V v = current.value;
+                        current = current.next;
                         action.accept(v);
                         if (map.modCount != expectedModCount)
                             throw new ConcurrentModificationException();
@@ -3003,57 +1636,33 @@
 
         public EntrySpliterator<K,V> trySplit() {
             int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
-            if (lo >= mid || current != null) {
-                return null;
-            } else {
-                EntrySpliterator<K,V> retVal = new EntrySpliterator<K,V>(map,
-                                 lo, index = mid, est >>>= 1, expectedModCount);
-                // Only 'this' Spliterator chould check for null.
-                retVal.acceptedNull = true;
-                return retVal;
-            }
+            return (lo >= mid || current != null) ? null :
+                new EntrySpliterator<K,V>(map, lo, index = mid, est >>>= 1,
+                                          expectedModCount);
         }
 
-        @SuppressWarnings("unchecked")
         public void forEachRemaining(Consumer<? super Map.Entry<K,V>> action) {
             int i, hi, mc;
             if (action == null)
                 throw new NullPointerException();
             HashMap<K,V> m = map;
-            Object[] tab = m.table;
+            Node<K,V>[] tab = m.table;
             if ((hi = fence) < 0) {
                 mc = expectedModCount = m.modCount;
-                hi = fence = tab.length;
+                hi = fence = (tab == null) ? 0 : tab.length;
             }
             else
                 mc = expectedModCount;
-
-            if (!acceptedNull) {
-                acceptedNull = true;
-                if (m.nullKeyEntry != null) {
-                    action.accept(m.nullKeyEntry);
-                }
-            }
-            if (tab.length >= hi && (i = index) >= 0 &&
-                (i < (index = hi) || current != null)) {
-                Object p = current;
+            if (tab != null && tab.length >= hi &&
+                (i = index) >= 0 && (i < (index = hi) || current != null)) {
+                Node<K,V> p = current;
                 current = null;
                 do {
-                    if (p == null) {
+                    if (p == null)
                         p = tab[i++];
-                        if (p instanceof HashMap.TreeBin) {
-                            p = ((HashMap.TreeBin)p).first;
-                        }
-                    } else {
-                        HashMap.Entry<K,V> entry;
-                        if (p instanceof HashMap.Entry) {
-                            entry = (HashMap.Entry<K,V>)p;
-                        } else {
-                            entry = (HashMap.Entry<K,V>)((TreeNode)p).entry;
-                        }
-                        action.accept(entry);
-                        p = entry.next;
-
+                    else {
+                        action.accept(p);
+                        p = p.next;
                     }
                 } while (p != null || i < hi);
                 if (m.modCount != mc)
@@ -3061,38 +1670,18 @@
             }
         }
 
-        @SuppressWarnings("unchecked")
         public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
             int hi;
             if (action == null)
                 throw new NullPointerException();
-            Object[] tab = map.table;
-            hi = getFence();
-
-            if (!acceptedNull) {
-                acceptedNull = true;
-                if (map.nullKeyEntry != null) {
-                    action.accept(map.nullKeyEntry);
-                    if (map.modCount != expectedModCount)
-                        throw new ConcurrentModificationException();
-                    return true;
-                }
-            }
-            if (tab.length >= hi && index >= 0) {
+            Node<K,V>[] tab = map.table;
+            if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {
                 while (current != null || index < hi) {
-                    if (current == null) {
+                    if (current == null)
                         current = tab[index++];
-                        if (current instanceof HashMap.TreeBin) {
-                            current = ((HashMap.TreeBin)current).first;
-                        }
-                    } else {
-                        HashMap.Entry<K,V> e;
-                        if (current instanceof HashMap.Entry) {
-                            e = (Entry<K,V>)current;
-                        } else {
-                            e = (Entry<K,V>)((TreeNode)current).entry;
-                        }
-                        current = e.next;
+                    else {
+                        Node<K,V> e = current;
+                        current = current.next;
                         action.accept(e);
                         if (map.modCount != expectedModCount)
                             throw new ConcurrentModificationException();
@@ -3108,4 +1697,664 @@
                 Spliterator.DISTINCT;
         }
     }
+
+    /* ------------------------------------------------------------ */
+    // LinkedHashMap support
+
+
+    /*
+     * The following package-protected methods are designed to be
+     * overridden by LinkedHashMap, but not by any other subclass.
+     * Nearly all other internal methods are also package-protected
+     * but are declared final, so can be used by LinkedHashMap, view
+     * classes, and HashSet.
+     */
+
+    // Create a regular (non-tree) node
+    Node<K,V> newNode(int hash, K key, V value, Node<K,V> next) {
+        return new Node<K,V>(hash, key, value, next);
+    }
+
+    // For conversion from TreeNodes to plain nodes
+    Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {
+        return new Node<K,V>(p.hash, p.key, p.value, next);
+    }
+
+    // Create a tree bin node
+    TreeNode<K,V> newTreeNode(int hash, K key, V value, Node<K,V> next) {
+        return new TreeNode<K,V>(hash, key, value, next);
+    }
+
+    // For treeifyBin
+    TreeNode<K,V> replacementTreeNode(Node<K,V> p, Node<K,V> next) {
+        return new TreeNode<K,V>(p.hash, p.key, p.value, next);
+    }
+
+    /**
+     * Reset to initial default state.  Called by clone and readObject.
+     */
+    void reinitialize() {
+        table = null;
+        entrySet = null;
+        keySet = null;
+        values = null;
+        modCount = 0;
+        threshold = 0;
+        size = 0;
+    }
+
+    // Callbacks to allow LinkedHashMap post-actions
+    void afterNodeAccess(Node<K,V> p) { }
+    void afterNodeInsertion(boolean evict) { }
+    void afterNodeRemoval(Node<K,V> p) { }
+
+    // Called only from writeObject, to ensure compatible ordering.
+    void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
+        Node<K,V>[] tab;
+        if (size > 0 && (tab = table) != null) {
+            for (int i = 0; i < tab.length; ++i) {
+                for (Node<K,V> e = tab[i]; e != null; e = e.next) {
+                    s.writeObject(e.key);
+                    s.writeObject(e.value);
+                }
+            }
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    // Tree bins
+
+    /**
+     * Entry for Tree bins. Extends LinkedHashMap.Entry (which in turn
+     * extends Node) so can be used as extension of either regular or
+     * linked node.
+     */
+    static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
+        TreeNode<K,V> parent;  // red-black tree links
+        TreeNode<K,V> left;
+        TreeNode<K,V> right;
+        TreeNode<K,V> prev;    // needed to unlink next upon deletion
+        boolean red;
+        TreeNode(int hash, K key, V val, Node<K,V> next) {
+            super(hash, key, val, next);
+        }
+
+        /**
+         * Returns root of tree containing this node.
+         */
+        final TreeNode<K,V> root() {
+            for (TreeNode<K,V> r = this, p;;) {
+                if ((p = r.parent) == null)
+                    return r;
+                r = p;
+            }
+        }
+
+        /**
+         * Ensures that the given root is the first node of its bin.
+         */
+        static <K,V> void moveRootToFront(Node<K,V>[] tab, TreeNode<K,V> root) {
+            int n;
+            if (root != null && tab != null && (n = tab.length) > 0) {
+                int index = (n - 1) & root.hash;
+                TreeNode<K,V> first = (TreeNode<K,V>)tab[index];
+                if (root != first) {
+                    Node<K,V> rn;
+                    tab[index] = root;
+                    TreeNode<K,V> rp = root.prev;
+                    if ((rn = root.next) != null)
+                        ((TreeNode<K,V>)rn).prev = rp;
+                    if (rp != null)
+                        rp.next = rn;
+                    if (first != null)
+                        first.prev = root;
+                    root.next = first;
+                    root.prev = null;
+                }
+                assert checkInvariants(root);
+            }
+        }
+
+        /**
+         * Finds the node starting at root p with the given hash and key.
+         * The kc argument caches comparableClassFor(key) upon first use
+         * comparing keys.
+         */
+        final TreeNode<K,V> find(int h, Object k, Class<?> kc) {
+            TreeNode<K,V> p = this;
+            do {
+                int ph, dir; K pk;
+                TreeNode<K,V> pl = p.left, pr = p.right, q;
+                if ((ph = p.hash) > h)
+                    p = pl;
+                else if (ph < h)
+                    p = pr;
+                else if ((pk = p.key) == k || (k != null && k.equals(pk)))
+                    return p;
+                else if (pl == null)
+                    p = pr;
+                else if (pr == null)
+                    p = pl;
+                else if ((kc != null ||
+                          (kc = comparableClassFor(k)) != null) &&
+                         (dir = compareComparables(kc, k, pk)) != 0)
+                    p = (dir < 0) ? pl : pr;
+                else if ((q = pr.find(h, k, kc)) != null)
+                    return q;
+                else
+                    p = pl;
+            } while (p != null);
+            return null;
+        }
+
+        /**
+         * Calls find for root node.
+         */
+        final TreeNode<K,V> getTreeNode(int h, Object k) {
+            return ((parent != null) ? root() : this).find(h, k, null);
+        }
+
+        /**
+         * Tie-breaking utility for ordering insertions when equal
+         * hashCodes and non-comparable. We don't require a total
+         * order, just a consistent insertion rule to maintain
+         * equivalence across rebalancings. Tie-breaking further than
+         * necessary simplifies testing a bit.
+         */
+        static int tieBreakOrder(Object a, Object b) {
+            int d;
+            if (a == null || b == null ||
+                (d = a.getClass().getName().
+                 compareTo(b.getClass().getName())) == 0)
+                d = (System.identityHashCode(a) <= System.identityHashCode(b) ?
+                     -1 : 1);
+            return d;
+        }
+
+        /**
+         * Forms tree of the nodes linked from this node.
+         * @return root of tree
+         */
+        final void treeify(Node<K,V>[] tab) {
+            TreeNode<K,V> root = null;
+            for (TreeNode<K,V> x = this, next; x != null; x = next) {
+                next = (TreeNode<K,V>)x.next;
+                x.left = x.right = null;
+                if (root == null) {
+                    x.parent = null;
+                    x.red = false;
+                    root = x;
+                }
+                else {
+                    K k = x.key;
+                    int h = x.hash;
+                    Class<?> kc = null;
+                    for (TreeNode<K,V> p = root;;) {
+                        int dir, ph;
+                        K pk = p.key;
+                        if ((ph = p.hash) > h)
+                            dir = -1;
+                        else if (ph < h)
+                            dir = 1;
+                        else if ((kc == null &&
+                                  (kc = comparableClassFor(k)) == null) ||
+                                 (dir = compareComparables(kc, k, pk)) == 0)
+                            dir = tieBreakOrder(k, pk);
+
+                        TreeNode<K,V> xp = p;
+                        if ((p = (dir <= 0) ? p.left : p.right) == null) {
+                            x.parent = xp;
+                            if (dir <= 0)
+                                xp.left = x;
+                            else
+                                xp.right = x;
+                            root = balanceInsertion(root, x);
+                            break;
+                        }
+                    }
+                }
+            }
+            moveRootToFront(tab, root);
+        }
+
+        /**
+         * Returns a list of non-TreeNodes replacing those linked from
+         * this node.
+         */
+        final Node<K,V> untreeify(HashMap<K,V> map) {
+            Node<K,V> hd = null, tl = null;
+            for (Node<K,V> q = this; q != null; q = q.next) {
+                Node<K,V> p = map.replacementNode(q, null);
+                if (tl == null)
+                    hd = p;
+                else
+                    tl.next = p;
+                tl = p;
+            }
+            return hd;
+        }
+
+        /**
+         * Tree version of putVal.
+         */
+        final TreeNode<K,V> putTreeVal(HashMap<K,V> map, Node<K,V>[] tab,
+                                       int h, K k, V v) {
+            Class<?> kc = null;
+            boolean searched = false;
+            TreeNode<K,V> root = (parent != null) ? root() : this;
+            for (TreeNode<K,V> p = root;;) {
+                int dir, ph; K pk;
+                if ((ph = p.hash) > h)
+                    dir = -1;
+                else if (ph < h)
+                    dir = 1;
+                else if ((pk = p.key) == k || (pk != null && k.equals(pk)))
+                    return p;
+                else if ((kc == null &&
+                          (kc = comparableClassFor(k)) == null) ||
+                         (dir = compareComparables(kc, k, pk)) == 0) {
+                    if (!searched) {
+                        TreeNode<K,V> q, ch;
+                        searched = true;
+                        if (((ch = p.left) != null &&
+                             (q = ch.find(h, k, kc)) != null) ||
+                            ((ch = p.right) != null &&
+                             (q = ch.find(h, k, kc)) != null))
+                            return q;
+                    }
+                    dir = tieBreakOrder(k, pk);
+                }
+
+                TreeNode<K,V> xp = p;
+                if ((p = (dir <= 0) ? p.left : p.right) == null) {
+                    Node<K,V> xpn = xp.next;
+                    TreeNode<K,V> x = map.newTreeNode(h, k, v, xpn);
+                    if (dir <= 0)
+                        xp.left = x;
+                    else
+                        xp.right = x;
+                    xp.next = x;
+                    x.parent = x.prev = xp;
+                    if (xpn != null)
+                        ((TreeNode<K,V>)xpn).prev = x;
+                    moveRootToFront(tab, balanceInsertion(root, x));
+                    return null;
+                }
+            }
+        }
+
+        /**
+         * Removes the given node, that must be present before this call.
+         * This is messier than typical red-black deletion code because we
+         * cannot swap the contents of an interior node with a leaf
+         * successor that is pinned by "next" pointers that are accessible
+         * independently during traversal. So instead we swap the tree
+         * linkages. If the current tree appears to have too few nodes,
+         * the bin is converted back to a plain bin. (The test triggers
+         * somewhere between 2 and 6 nodes, depending on tree structure).
+         */
+        final void removeTreeNode(HashMap<K,V> map, Node<K,V>[] tab,
+                                  boolean movable) {
+            int n;
+            if (tab == null || (n = tab.length) == 0)
+                return;
+            int index = (n - 1) & hash;
+            TreeNode<K,V> first = (TreeNode<K,V>)tab[index], root = first, rl;
+            TreeNode<K,V> succ = (TreeNode<K,V>)next, pred = prev;
+            if (pred == null)
+                tab[index] = first = succ;
+            else
+                pred.next = succ;
+            if (succ != null)
+                succ.prev = pred;
+            if (first == null)
+                return;
+            if (root.parent != null)
+                root = root.root();
+            if (root == null || root.right == null ||
+                (rl = root.left) == null || rl.left == null) {
+                tab[index] = first.untreeify(map);  // too small
+                return;
+            }
+            TreeNode<K,V> p = this, pl = left, pr = right, replacement;
+            if (pl != null && pr != null) {
+                TreeNode<K,V> s = pr, sl;
+                while ((sl = s.left) != null) // find successor
+                    s = sl;
+                boolean c = s.red; s.red = p.red; p.red = c; // swap colors
+                TreeNode<K,V> sr = s.right;
+                TreeNode<K,V> pp = p.parent;
+                if (s == pr) { // p was s's direct parent
+                    p.parent = s;
+                    s.right = p;
+                }
+                else {
+                    TreeNode<K,V> sp = s.parent;
+                    if ((p.parent = sp) != null) {
+                        if (s == sp.left)
+                            sp.left = p;
+                        else
+                            sp.right = p;
+                    }
+                    if ((s.right = pr) != null)
+                        pr.parent = s;
+                }
+                p.left = null;
+                if ((p.right = sr) != null)
+                    sr.parent = p;
+                if ((s.left = pl) != null)
+                    pl.parent = s;
+                if ((s.parent = pp) == null)
+                    root = s;
+                else if (p == pp.left)
+                    pp.left = s;
+                else
+                    pp.right = s;
+                if (sr != null)
+                    replacement = sr;
+                else
+                    replacement = p;
+            }
+            else if (pl != null)
+                replacement = pl;
+            else if (pr != null)
+                replacement = pr;
+            else
+                replacement = p;
+            if (replacement != p) {
+                TreeNode<K,V> pp = replacement.parent = p.parent;
+                if (pp == null)
+                    root = replacement;
+                else if (p == pp.left)
+                    pp.left = replacement;
+                else
+                    pp.right = replacement;
+                p.left = p.right = p.parent = null;
+            }
+
+            TreeNode<K,V> r = p.red ? root : balanceDeletion(root, replacement);
+
+            if (replacement == p) {  // detach
+                TreeNode<K,V> pp = p.parent;
+                p.parent = null;
+                if (pp != null) {
+                    if (p == pp.left)
+                        pp.left = null;
+                    else if (p == pp.right)
+                        pp.right = null;
+                }
+            }
+            if (movable)
+                moveRootToFront(tab, r);
+        }
+
+        /**
+         * Splits nodes in a tree bin into lower and upper tree bins,
+         * or untreeifies if now too small. Called only from resize;
+         * see above discussion about split bits and indices.
+         *
+         * @param map the map
+         * @param tab the table for recording bin heads
+         * @param index the index of the table being split
+         * @param bit the bit of hash to split on
+         */
+        final void split(HashMap<K,V> map, Node<K,V>[] tab, int index, int bit) {
+            TreeNode<K,V> b = this;
+            // Relink into lo and hi lists, preserving order
+            TreeNode<K,V> loHead = null, loTail = null;
+            TreeNode<K,V> hiHead = null, hiTail = null;
+            int lc = 0, hc = 0;
+            for (TreeNode<K,V> e = b, next; e != null; e = next) {
+                next = (TreeNode<K,V>)e.next;
+                e.next = null;
+                if ((e.hash & bit) == 0) {
+                    if ((e.prev = loTail) == null)
+                        loHead = e;
+                    else
+                        loTail.next = e;
+                    loTail = e;
+                    ++lc;
+                }
+                else {
+                    if ((e.prev = hiTail) == null)
+                        hiHead = e;
+                    else
+                        hiTail.next = e;
+                    hiTail = e;
+                    ++hc;
+                }
+            }
+
+            if (loHead != null) {
+                if (lc <= UNTREEIFY_THRESHOLD)
+                    tab[index] = loHead.untreeify(map);
+                else {
+                    tab[index] = loHead;
+                    if (hiHead != null) // (else is already treeified)
+                        loHead.treeify(tab);
+                }
+            }
+            if (hiHead != null) {
+                if (hc <= UNTREEIFY_THRESHOLD)
+                    tab[index + bit] = hiHead.untreeify(map);
+                else {
+                    tab[index + bit] = hiHead;
+                    if (loHead != null)
+                        hiHead.treeify(tab);
+                }
+            }
+        }
+
+        /* ------------------------------------------------------------ */
+        // Red-black tree methods, all adapted from CLR
+
+        static <K,V> TreeNode<K,V> rotateLeft(TreeNode<K,V> root,
+                                              TreeNode<K,V> p) {
+            TreeNode<K,V> r, pp, rl;
+            if (p != null && (r = p.right) != null) {
+                if ((rl = p.right = r.left) != null)
+                    rl.parent = p;
+                if ((pp = r.parent = p.parent) == null)
+                    (root = r).red = false;
+                else if (pp.left == p)
+                    pp.left = r;
+                else
+                    pp.right = r;
+                r.left = p;
+                p.parent = r;
+            }
+            return root;
+        }
+
+        static <K,V> TreeNode<K,V> rotateRight(TreeNode<K,V> root,
+                                               TreeNode<K,V> p) {
+            TreeNode<K,V> l, pp, lr;
+            if (p != null && (l = p.left) != null) {
+                if ((lr = p.left = l.right) != null)
+                    lr.parent = p;
+                if ((pp = l.parent = p.parent) == null)
+                    (root = l).red = false;
+                else if (pp.right == p)
+                    pp.right = l;
+                else
+                    pp.left = l;
+                l.right = p;
+                p.parent = l;
+            }
+            return root;
+        }
+
+        static <K,V> TreeNode<K,V> balanceInsertion(TreeNode<K,V> root,
+                                                    TreeNode<K,V> x) {
+            x.red = true;
+            for (TreeNode<K,V> xp, xpp, xppl, xppr;;) {
+                if ((xp = x.parent) == null) {
+                    x.red = false;
+                    return x;
+                }
+                else if (!xp.red || (xpp = xp.parent) == null)
+                    return root;
+                if (xp == (xppl = xpp.left)) {
+                    if ((xppr = xpp.right) != null && xppr.red) {
+                        xppr.red = false;
+                        xp.red = false;
+                        xpp.red = true;
+                        x = xpp;
+                    }
+                    else {
+                        if (x == xp.right) {
+                            root = rotateLeft(root, x = xp);
+                            xpp = (xp = x.parent) == null ? null : xp.parent;
+                        }
+                        if (xp != null) {
+                            xp.red = false;
+                            if (xpp != null) {
+                                xpp.red = true;
+                                root = rotateRight(root, xpp);
+                            }
+                        }
+                    }
+                }
+                else {
+                    if (xppl != null && xppl.red) {
+                        xppl.red = false;
+                        xp.red = false;
+                        xpp.red = true;
+                        x = xpp;
+                    }
+                    else {
+                        if (x == xp.left) {
+                            root = rotateRight(root, x = xp);
+                            xpp = (xp = x.parent) == null ? null : xp.parent;
+                        }
+                        if (xp != null) {
+                            xp.red = false;
+                            if (xpp != null) {
+                                xpp.red = true;
+                                root = rotateLeft(root, xpp);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        static <K,V> TreeNode<K,V> balanceDeletion(TreeNode<K,V> root,
+                                                   TreeNode<K,V> x) {
+            for (TreeNode<K,V> xp, xpl, xpr;;)  {
+                if (x == null || x == root)
+                    return root;
+                else if ((xp = x.parent) == null) {
+                    x.red = false;
+                    return x;
+                }
+                else if (x.red) {
+                    x.red = false;
+                    return root;
+                }
+                else if ((xpl = xp.left) == x) {
+                    if ((xpr = xp.right) != null && xpr.red) {
+                        xpr.red = false;
+                        xp.red = true;
+                        root = rotateLeft(root, xp);
+                        xpr = (xp = x.parent) == null ? null : xp.right;
+                    }
+                    if (xpr == null)
+                        x = xp;
+                    else {
+                        TreeNode<K,V> sl = xpr.left, sr = xpr.right;
+                        if ((sr == null || !sr.red) &&
+                            (sl == null || !sl.red)) {
+                            xpr.red = true;
+                            x = xp;
+                        }
+                        else {
+                            if (sr == null || !sr.red) {
+                                if (sl != null)
+                                    sl.red = false;
+                                xpr.red = true;
+                                root = rotateRight(root, xpr);
+                                xpr = (xp = x.parent) == null ?
+                                    null : xp.right;
+                            }
+                            if (xpr != null) {
+                                xpr.red = (xp == null) ? false : xp.red;
+                                if ((sr = xpr.right) != null)
+                                    sr.red = false;
+                            }
+                            if (xp != null) {
+                                xp.red = false;
+                                root = rotateLeft(root, xp);
+                            }
+                            x = root;
+                        }
+                    }
+                }
+                else { // symmetric
+                    if (xpl != null && xpl.red) {
+                        xpl.red = false;
+                        xp.red = true;
+                        root = rotateRight(root, xp);
+                        xpl = (xp = x.parent) == null ? null : xp.left;
+                    }
+                    if (xpl == null)
+                        x = xp;
+                    else {
+                        TreeNode<K,V> sl = xpl.left, sr = xpl.right;
+                        if ((sl == null || !sl.red) &&
+                            (sr == null || !sr.red)) {
+                            xpl.red = true;
+                            x = xp;
+                        }
+                        else {
+                            if (sl == null || !sl.red) {
+                                if (sr != null)
+                                    sr.red = false;
+                                xpl.red = true;
+                                root = rotateLeft(root, xpl);
+                                xpl = (xp = x.parent) == null ?
+                                    null : xp.left;
+                            }
+                            if (xpl != null) {
+                                xpl.red = (xp == null) ? false : xp.red;
+                                if ((sl = xpl.left) != null)
+                                    sl.red = false;
+                            }
+                            if (xp != null) {
+                                xp.red = false;
+                                root = rotateRight(root, xp);
+                            }
+                            x = root;
+                        }
+                    }
+                }
+            }
+        }
+
+        /**
+         * Recursive invariant check
+         */
+        static <K,V> boolean checkInvariants(TreeNode<K,V> t) {
+            TreeNode<K,V> tp = t.parent, tl = t.left, tr = t.right,
+                tb = t.prev, tn = (TreeNode<K,V>)t.next;
+            if (tb != null && tb.next != t)
+                return false;
+            if (tn != null && tn.prev != t)
+                return false;
+            if (tp != null && t != tp.left && t != tp.right)
+                return false;
+            if (tl != null && (tl.parent != t || tl.hash > t.hash))
+                return false;
+            if (tr != null && (tr.parent != t || tr.hash < t.hash))
+                return false;
+            if (t.red && tl != null && tl.red && tr != null && tr.red)
+                return false;
+            if (tl != null && !checkInvariants(tl))
+                return false;
+            if (tr != null && !checkInvariants(tr))
+                return false;
+            return true;
+        }
+    }
+
 }
--- a/jdk/src/share/classes/java/util/Hashtable.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/Hashtable.java	Wed Jul 05 19:11:53 2017 +0200
@@ -168,68 +168,6 @@
     /** use serialVersionUID from JDK 1.0.2 for interoperability */
     private static final long serialVersionUID = 1421746759512286392L;
 
-    private static class Holder {
-            // Unsafe mechanics
-        /**
-         *
-         */
-        static final sun.misc.Unsafe UNSAFE;
-
-        /**
-         * Offset of "final" hashSeed field we must set in
-         * readObject() method.
-         */
-        static final long HASHSEED_OFFSET;
-
-        static final boolean USE_HASHSEED;
-
-        static {
-            String hashSeedProp = java.security.AccessController.doPrivileged(
-                    new sun.security.action.GetPropertyAction(
-                        "jdk.map.useRandomSeed"));
-            boolean localBool = (null != hashSeedProp)
-                    ? Boolean.parseBoolean(hashSeedProp) : false;
-            USE_HASHSEED = localBool;
-
-            if (USE_HASHSEED) {
-                try {
-                    UNSAFE = sun.misc.Unsafe.getUnsafe();
-                    HASHSEED_OFFSET = UNSAFE.objectFieldOffset(
-                        Hashtable.class.getDeclaredField("hashSeed"));
-                } catch (NoSuchFieldException | SecurityException e) {
-                    throw new InternalError("Failed to record hashSeed offset", e);
-                }
-            } else {
-                UNSAFE = null;
-                HASHSEED_OFFSET = 0;
-            }
-        }
-    }
-
-    /**
-     * A randomizing value associated with this instance that is applied to
-     * hash code of keys to make hash collisions harder to find.
-     *
-     * Non-final so it can be set lazily, but be sure not to set more than once.
-     */
-    transient final int hashSeed;
-
-    /**
-     * Return an initial value for the hashSeed, or 0 if the random seed is not
-     * enabled.
-     */
-    final int initHashSeed() {
-        if (sun.misc.VM.isBooted() && Holder.USE_HASHSEED) {
-            int seed = ThreadLocalRandom.current().nextInt();
-            return (seed != 0) ? seed : 1;
-        }
-        return 0;
-    }
-
-    private int hash(Object k) {
-        return hashSeed ^ k.hashCode();
-    }
-
     /**
      * Constructs a new, empty hashtable with the specified initial
      * capacity and the specified load factor.
@@ -251,7 +189,6 @@
         this.loadFactor = loadFactor;
         table = new Entry<?,?>[initialCapacity];
         threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
-        hashSeed = initHashSeed();
     }
 
     /**
@@ -395,7 +332,7 @@
      */
     public synchronized boolean containsKey(Object key) {
         Entry<?,?> tab[] = table;
-        int hash = hash(key);
+        int hash = key.hashCode();
         int index = (hash & 0x7FFFFFFF) % tab.length;
         for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
             if ((e.hash == hash) && e.key.equals(key)) {
@@ -423,7 +360,7 @@
     @SuppressWarnings("unchecked")
     public synchronized V get(Object key) {
         Entry<?,?> tab[] = table;
-        int hash = hash(key);
+        int hash = key.hashCode();
         int index = (hash & 0x7FFFFFFF) % tab.length;
         for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
             if ((e.hash == hash) && e.key.equals(key)) {
@@ -488,7 +425,7 @@
             rehash();
 
             tab = table;
-            hash = hash(key);
+            hash = key.hashCode();
             index = (hash & 0x7FFFFFFF) % tab.length;
         }
 
@@ -524,7 +461,7 @@
 
         // Makes sure the key is not already in the hashtable.
         Entry<?,?> tab[] = table;
-        int hash = hash(key);
+        int hash = key.hashCode();
         int index = (hash & 0x7FFFFFFF) % tab.length;
         @SuppressWarnings("unchecked")
         Entry<K,V> entry = (Entry<K,V>)tab[index];
@@ -551,7 +488,7 @@
      */
     public synchronized V remove(Object key) {
         Entry<?,?> tab[] = table;
-        int hash = hash(key);
+        int hash = key.hashCode();
         int index = (hash & 0x7FFFFFFF) % tab.length;
         @SuppressWarnings("unchecked")
         Entry<K,V> e = (Entry<K,V>)tab[index];
@@ -760,7 +697,7 @@
             Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
             Object key = entry.getKey();
             Entry<?,?>[] tab = table;
-            int hash = hash(key);
+            int hash = key.hashCode();
             int index = (hash & 0x7FFFFFFF) % tab.length;
 
             for (Entry<?,?> e = tab[index]; e != null; e = e.next)
@@ -775,7 +712,7 @@
             Map.Entry<?,?> entry = (Map.Entry<?,?>) o;
             Object key = entry.getKey();
             Entry<?,?>[] tab = table;
-            int hash = hash(key);
+            int hash = key.hashCode();
             int index = (hash & 0x7FFFFFFF) % tab.length;
 
             @SuppressWarnings("unchecked")
@@ -975,7 +912,7 @@
 
         // Makes sure the key is not already in the hashtable.
         Entry<?,?> tab[] = table;
-        int hash = hash(key);
+        int hash = key.hashCode();
         int index = (hash & 0x7FFFFFFF) % tab.length;
         @SuppressWarnings("unchecked")
         Entry<K,V> entry = (Entry<K,V>)tab[index];
@@ -998,7 +935,7 @@
         Objects.requireNonNull(value);
 
         Entry<?,?> tab[] = table;
-        int hash = hash(key);
+        int hash = key.hashCode();
         int index = (hash & 0x7FFFFFFF) % tab.length;
         @SuppressWarnings("unchecked")
         Entry<K,V> e = (Entry<K,V>)tab[index];
@@ -1020,8 +957,10 @@
 
     @Override
     public synchronized boolean replace(K key, V oldValue, V newValue) {
+        Objects.requireNonNull(oldValue);
+        Objects.requireNonNull(newValue);
         Entry<?,?> tab[] = table;
-        int hash = hash(key);
+        int hash = key.hashCode();
         int index = (hash & 0x7FFFFFFF) % tab.length;
         @SuppressWarnings("unchecked")
         Entry<K,V> e = (Entry<K,V>)tab[index];
@@ -1040,8 +979,9 @@
 
     @Override
     public synchronized V replace(K key, V value) {
+        Objects.requireNonNull(value);
         Entry<?,?> tab[] = table;
-        int hash = hash(key);
+        int hash = key.hashCode();
         int index = (hash & 0x7FFFFFFF) % tab.length;
         @SuppressWarnings("unchecked")
         Entry<K,V> e = (Entry<K,V>)tab[index];
@@ -1060,7 +1000,7 @@
         Objects.requireNonNull(mappingFunction);
 
         Entry<?,?> tab[] = table;
-        int hash = hash(key);
+        int hash = key.hashCode();
         int index = (hash & 0x7FFFFFFF) % tab.length;
         @SuppressWarnings("unchecked")
         Entry<K,V> e = (Entry<K,V>)tab[index];
@@ -1084,7 +1024,7 @@
         Objects.requireNonNull(remappingFunction);
 
         Entry<?,?> tab[] = table;
-        int hash = hash(key);
+        int hash = key.hashCode();
         int index = (hash & 0x7FFFFFFF) % tab.length;
         @SuppressWarnings("unchecked")
         Entry<K,V> e = (Entry<K,V>)tab[index];
@@ -1113,7 +1053,7 @@
         Objects.requireNonNull(remappingFunction);
 
         Entry<?,?> tab[] = table;
-        int hash = hash(key);
+        int hash = key.hashCode();
         int index = (hash & 0x7FFFFFFF) % tab.length;
         @SuppressWarnings("unchecked")
         Entry<K,V> e = (Entry<K,V>)tab[index];
@@ -1148,7 +1088,7 @@
         Objects.requireNonNull(remappingFunction);
 
         Entry<?,?> tab[] = table;
-        int hash = hash(key);
+        int hash = key.hashCode();
         int index = (hash & 0x7FFFFFFF) % tab.length;
         @SuppressWarnings("unchecked")
         Entry<K,V> e = (Entry<K,V>)tab[index];
@@ -1228,13 +1168,6 @@
         // Read in the length, threshold, and loadfactor
         s.defaultReadObject();
 
-        // set hashMask
-        if (Holder.USE_HASHSEED) {
-            int seed = ThreadLocalRandom.current().nextInt();
-            Holder.UNSAFE.putIntVolatile(this, Holder.HASHSEED_OFFSET,
-                                         (seed != 0) ? seed : 1);
-        }
-
         // Read the original length of the array and number of elements
         int origlength = s.readInt();
         int elements = s.readInt();
@@ -1282,7 +1215,7 @@
         }
         // Makes sure the key is not already in the hashtable.
         // This should not happen in deserialized version.
-        int hash = hash(key);
+        int hash = key.hashCode();
         int index = (hash & 0x7FFFFFFF) % tab.length;
         for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {
             if ((e.hash == hash) && e.key.equals(key)) {
@@ -1347,7 +1280,7 @@
         }
 
         public int hashCode() {
-            return (Objects.hashCode(key) ^ Objects.hashCode(value));
+            return hash ^ Objects.hashCode(value);
         }
 
         public String toString() {
--- a/jdk/src/share/classes/java/util/IdentityHashMap.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/IdentityHashMap.java	Wed Jul 05 19:11:53 2017 +0200
@@ -997,6 +997,7 @@
          * behavior when c is a smaller "normal" (non-identity-based) Set.
          */
         public boolean removeAll(Collection<?> c) {
+            Objects.requireNonNull(c);
             boolean modified = false;
             for (Iterator<K> i = iterator(); i.hasNext(); ) {
                 if (c.contains(i.next())) {
@@ -1212,6 +1213,7 @@
          * behavior when c is a smaller "normal" (non-identity-based) Set.
          */
         public boolean removeAll(Collection<?> c) {
+            Objects.requireNonNull(c);
             boolean modified = false;
             for (Iterator<Map.Entry<K,V>> i = iterator(); i.hasNext(); ) {
                 if (c.contains(i.next())) {
--- a/jdk/src/share/classes/java/util/LinkedHashMap.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/LinkedHashMap.java	Wed Jul 05 19:11:53 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,9 +24,12 @@
  */
 
 package java.util;
-import java.io.*;
+
+import java.util.function.Consumer;
 import java.util.function.BiConsumer;
 import java.util.function.BiFunction;
+import java.io.Serializable;
+import java.io.IOException;
 
 /**
  * <p>Hash table and linked list implementation of the <tt>Map</tt> interface,
@@ -57,9 +60,9 @@
  * order they were presented.)
  *
  * <p>A special {@link #LinkedHashMap(int,float,boolean) constructor} is
- * provided to create a <tt>LinkedHashMap</tt> whose order of iteration is the
- * order in which its entries were last accessed, from least-recently accessed
- * to most-recently (<i>access-order</i>).  This kind of map is well-suited to
+ * provided to create a linked hash map whose order of iteration is the order
+ * in which its entries were last accessed, from least-recently accessed to
+ * most-recently (<i>access-order</i>).  This kind of map is well-suited to
  * building LRU caches.  Invoking the <tt>put</tt> or <tt>get</tt> method
  * results in an access to the corresponding entry (assuming it exists after
  * the invocation completes).  The <tt>putAll</tt> method generates one entry
@@ -155,18 +158,53 @@
  * @see     Hashtable
  * @since   1.4
  */
-
 public class LinkedHashMap<K,V>
     extends HashMap<K,V>
     implements Map<K,V>
 {
 
+    /*
+     * Implementation note.  A previous version of this class was
+     * internally structured a little differently. Because superclass
+     * HashMap now uses trees for some of its nodes, class
+     * LinkedHashMap.Entry is now treated as intermediary node class
+     * that can also be converted to tree form. The name of this
+     * class, LinkedHashMap.Entry, is confusing in several ways in its
+     * current context, but cannot be changed.  Otherwise, even though
+     * it is not exported outside this package, some existing source
+     * code is known to have relied on a symbol resolution corner case
+     * rule in calls to removeEldestEntry that suppressed compilation
+     * errors due to ambiguous usages. So, we keep the name to
+     * preserve unmodified compilability.
+     *
+     * The changes in node classes also require using two fields
+     * (head, tail) rather than a pointer to a header node to maintain
+     * the doubly-linked before/after list. This class also
+     * previously used a different style of callback methods upon
+     * access, insertion, and removal.
+     */
+
+    /**
+     * HashMap.Node subclass for normal LinkedHashMap entries.
+     */
+    static class Entry<K,V> extends HashMap.Node<K,V> {
+        Entry<K,V> before, after;
+        Entry(int hash, K key, V value, Node<K,V> next) {
+            super(hash, key, value, next);
+        }
+    }
+
     private static final long serialVersionUID = 3801124242820219131L;
 
     /**
-     * The head of the doubly linked list.
+     * The head (eldest) of the doubly linked list.
      */
-    private transient Entry<K,V> header;
+    transient LinkedHashMap.Entry<K,V> head;
+
+    /**
+     * The tail (youngest) of the doubly linked list.
+     */
+    transient LinkedHashMap.Entry<K,V> tail;
 
     /**
      * The iteration ordering method for this linked hash map: <tt>true</tt>
@@ -174,7 +212,125 @@
      *
      * @serial
      */
-    private final boolean accessOrder;
+    final boolean accessOrder;
+
+    // internal utilities
+
+    // link at the end of list
+    private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
+        LinkedHashMap.Entry<K,V> last = tail;
+        tail = p;
+        if (last == null)
+            head = p;
+        else {
+            p.before = last;
+            last.after = p;
+        }
+    }
+
+    // apply src's links to dst
+    private void transferLinks(LinkedHashMap.Entry<K,V> src,
+                               LinkedHashMap.Entry<K,V> dst) {
+        LinkedHashMap.Entry<K,V> b = dst.before = src.before;
+        LinkedHashMap.Entry<K,V> a = dst.after = src.after;
+        if (b == null)
+            head = dst;
+        else
+            b.after = dst;
+        if (a == null)
+            tail = dst;
+        else
+            a.before = dst;
+    }
+
+    // overrides of HashMap hook methods
+
+    void reinitialize() {
+        super.reinitialize();
+        head = tail = null;
+    }
+
+    Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
+        LinkedHashMap.Entry<K,V> p =
+            new LinkedHashMap.Entry<K,V>(hash, key, value, e);
+        linkNodeLast(p);
+        return p;
+    }
+
+    Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {
+        LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<K,V>)p;
+        LinkedHashMap.Entry<K,V> t =
+            new LinkedHashMap.Entry<K,V>(q.hash, q.key, q.value, next);
+        transferLinks(q, t);
+        return t;
+    }
+
+    TreeNode<K,V> newTreeNode(int hash, K key, V value, Node<K,V> next) {
+        TreeNode<K,V> p = new TreeNode<K,V>(hash, key, value, next);
+        linkNodeLast(p);
+        return p;
+    }
+
+    TreeNode<K,V> replacementTreeNode(Node<K,V> p, Node<K,V> next) {
+        LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<K,V>)p;
+        TreeNode<K,V> t = new TreeNode<K,V>(q.hash, q.key, q.value, next);
+        transferLinks(q, t);
+        return t;
+    }
+
+    void afterNodeRemoval(Node<K,V> e) { // unlink
+        LinkedHashMap.Entry<K,V> p =
+            (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
+        p.before = p.after = null;
+        if (b == null)
+            head = a;
+        else
+            b.after = a;
+        if (a == null)
+            tail = b;
+        else
+            a.before = b;
+    }
+
+    void afterNodeInsertion(boolean evict) { // possibly remove eldest
+        LinkedHashMap.Entry<K,V> first;
+        if (evict && (first = head) != null && removeEldestEntry(first)) {
+            K key = first.key;
+            removeNode(hash(key), key, null, false, true);
+        }
+    }
+
+    void afterNodeAccess(Node<K,V> e) { // move node to last
+        LinkedHashMap.Entry<K,V> last;
+        if (accessOrder && (last = tail) != e) {
+            LinkedHashMap.Entry<K,V> p =
+                (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
+            p.after = null;
+            if (b == null)
+                head = a;
+            else
+                b.after = a;
+            if (a != null)
+                a.before = b;
+            else
+                last = b;
+            if (last == null)
+                head = p;
+            else {
+                p.before = last;
+                last.after = p;
+            }
+            tail = p;
+            ++modCount;
+        }
+    }
+
+    void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
+        for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) {
+            s.writeObject(e.key);
+            s.writeObject(e.value);
+        }
+    }
 
     /**
      * Constructs an empty insertion-ordered <tt>LinkedHashMap</tt> instance
@@ -221,8 +377,9 @@
      * @throws NullPointerException if the specified map is null
      */
     public LinkedHashMap(Map<? extends K, ? extends V> m) {
-        super(m);
+        super();
         accessOrder = false;
+        putMapEntries(m, false);
     }
 
     /**
@@ -243,16 +400,6 @@
         this.accessOrder = accessOrder;
     }
 
-    /**
-     * Called by superclass constructors and pseudoconstructors (clone,
-     * readObject) before any entries are inserted into the map.  Initializes
-     * the chain.
-     */
-    @Override
-    void init() {
-        header = new Entry<>(-1, null, null, null);
-        header.before = header.after = header;
-    }
 
     /**
      * Returns <tt>true</tt> if this map maps one or more keys to the
@@ -263,15 +410,10 @@
      *         specified value
      */
     public boolean containsValue(Object value) {
-        // Overridden to take advantage of faster iterator
-        if (value==null) {
-            for (Entry<?,?> e = header.after; e != header; e = e.after)
-                if (e.value==null)
-                    return true;
-        } else {
-            for (Entry<?,?> e = header.after; e != header; e = e.after)
-                if (value.equals(e.value))
-                    return true;
+        for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) {
+            V v = e.value;
+            if (v == value || (value != null && value.equals(v)))
+                return true;
         }
         return false;
     }
@@ -292,10 +434,11 @@
      * distinguish these two cases.
      */
     public V get(Object key) {
-        Entry<K,V> e = (Entry<K,V>)getEntry(key);
-        if (e == null)
+        Node<K,V> e;
+        if ((e = getNode(hash(key), key)) == null)
             return null;
-        e.recordAccess(this);
+        if (accessOrder)
+            afterNodeAccess(e);
         return e.value;
     }
 
@@ -305,163 +448,7 @@
      */
     public void clear() {
         super.clear();
-        header.before = header.after = header;
-    }
-
-    @Override
-    public void forEach(BiConsumer<? super K, ? super V> action) {
-        Objects.requireNonNull(action);
-        int expectedModCount = modCount;
-        for (Entry<K, V> entry = header.after; entry != header; entry = entry.after) {
-            action.accept(entry.key, entry.value);
-
-            if (expectedModCount != modCount) {
-                throw new ConcurrentModificationException();
-            }
-        }
-    }
-
-    @Override
-    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
-        Objects.requireNonNull(function);
-        int expectedModCount = modCount;
-        for (Entry<K, V> entry = header.after; entry != header; entry = entry.after) {
-            entry.value = function.apply(entry.key, entry.value);
-
-            if (expectedModCount != modCount) {
-                throw new ConcurrentModificationException();
-            }
-        }
-    }
-
-    /**
-     * LinkedHashMap entry.
-     */
-    private static class Entry<K,V> extends HashMap.Entry<K,V> {
-        // These fields comprise the doubly linked list used for iteration.
-        Entry<K,V> before, after;
-
-        Entry(int hash, K key, V value, Object next) {
-            super(hash, key, value, next);
-        }
-
-        /**
-         * Removes this entry from the linked list.
-         */
-        private void remove() {
-            before.after = after;
-            after.before = before;
-        }
-
-        /**
-         * Inserts this entry before the specified existing entry in the list.
-         */
-        private void addBefore(Entry<K,V> existingEntry) {
-            after  = existingEntry;
-            before = existingEntry.before;
-            before.after = this;
-            after.before = this;
-        }
-
-        /**
-         * This method is invoked by the superclass whenever the value
-         * of a pre-existing entry is read by Map.get or modified by Map.put.
-         * If the enclosing Map is access-ordered, it moves the entry
-         * to the end of the list; otherwise, it does nothing.
-         */
-        void recordAccess(HashMap<K,V> m) {
-            LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
-            if (lm.accessOrder) {
-                lm.modCount++;
-                remove();
-                addBefore(lm.header);
-            }
-        }
-
-        void recordRemoval(HashMap<K,V> m) {
-            remove();
-        }
-    }
-
-    private abstract class LinkedHashIterator<T> implements Iterator<T> {
-        Entry<K,V> nextEntry    = header.after;
-        Entry<K,V> lastReturned = null;
-
-        /**
-         * The modCount value that the iterator believes that the backing
-         * List should have.  If this expectation is violated, the iterator
-         * has detected concurrent modification.
-         */
-        int expectedModCount = modCount;
-
-        public boolean hasNext() {
-            return nextEntry != header;
-        }
-
-        public void remove() {
-            if (lastReturned == null)
-                throw new IllegalStateException();
-            if (modCount != expectedModCount)
-                throw new ConcurrentModificationException();
-
-            LinkedHashMap.this.remove(lastReturned.key);
-            lastReturned = null;
-            expectedModCount = modCount;
-        }
-
-        Entry<K,V> nextEntry() {
-            if (modCount != expectedModCount)
-                throw new ConcurrentModificationException();
-            if (nextEntry == header)
-                throw new NoSuchElementException();
-
-            Entry<K,V> e = lastReturned = nextEntry;
-            nextEntry = e.after;
-            return e;
-        }
-    }
-
-    private class KeyIterator extends LinkedHashIterator<K> {
-        public K next() { return nextEntry().getKey(); }
-    }
-
-    private class ValueIterator extends LinkedHashIterator<V> {
-        public V next() { return nextEntry().value; }
-    }
-
-    private class EntryIterator extends LinkedHashIterator<Map.Entry<K,V>> {
-        public Map.Entry<K,V> next() { return nextEntry(); }
-    }
-
-    // These Overrides alter the behavior of superclass view iterator() methods
-    Iterator<K> newKeyIterator()   { return new KeyIterator();   }
-    Iterator<V> newValueIterator() { return new ValueIterator(); }
-    Iterator<Map.Entry<K,V>> newEntryIterator() { return new EntryIterator(); }
-
-    /**
-     * This override alters behavior of superclass put method. It causes newly
-     * allocated entry to get inserted at the end of the linked list and
-     * removes the eldest entry if appropriate.
-     */
-    @Override
-    void addEntry(int hash, K key, V value, int bucketIndex, boolean checkIfNeedTree) {
-        super.addEntry(hash, key, value, bucketIndex, checkIfNeedTree);
-
-        // Remove eldest entry if instructed
-        Entry<K,V> eldest = header.after;
-        if (removeEldestEntry(eldest)) {
-            removeEntryForKey(eldest.key);
-        }
-    }
-
-    /*
-     * Create a new LinkedHashMap.Entry and setup the before/after pointers
-     */
-    @Override
-    HashMap.Entry<K,V> newEntry(int hash, K key, V value, Object next) {
-        Entry<K,V> newEntry = new Entry<>(hash, key, value, next);
-        newEntry.addBefore(header);
-        return newEntry;
+        head = tail = null;
     }
 
     /**
@@ -475,13 +462,13 @@
      * <p>Sample use: this override will allow the map to grow up to 100
      * entries and then delete the eldest entry each time a new entry is
      * added, maintaining a steady state of 100 entries.
-     * <pre>{@code
+     * <pre>
      *     private static final int MAX_ENTRIES = 100;
      *
      *     protected boolean removeEldestEntry(Map.Entry eldest) {
-     *        return size() > MAX_ENTRIES;
+     *        return size() &gt; MAX_ENTRIES;
      *     }
-     * }</pre>
+     * </pre>
      *
      * <p>This method typically does not modify the map in any way,
      * instead allowing the map to modify itself as directed by its
@@ -508,4 +495,241 @@
     protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
         return false;
     }
+
+    /**
+     * Returns a {@link Set} view of the keys contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own <tt>remove</tt> operation), the results of
+     * the iteration are undefined.  The set supports element removal,
+     * which removes the corresponding mapping from the map, via the
+     * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
+     * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
+     * operations.  It does not support the <tt>add</tt> or <tt>addAll</tt>
+     * operations.
+     * Its {@link Spliterator} typically provides faster sequential
+     * performance but much poorer parallel performance than that of
+     * {@code HashMap}.
+     *
+     * @return a set view of the keys contained in this map
+     */
+    public Set<K> keySet() {
+        Set<K> ks;
+        return (ks = keySet) == null ? (keySet = new LinkedKeySet()) : ks;
+    }
+
+    final class LinkedKeySet extends AbstractSet<K> {
+        public final int size()                 { return size; }
+        public final void clear()               { LinkedHashMap.this.clear(); }
+        public final Iterator<K> iterator() {
+            return new LinkedKeyIterator();
+        }
+        public final boolean contains(Object o) { return containsKey(o); }
+        public final boolean remove(Object key) {
+            return removeNode(hash(key), key, null, false, true) != null;
+        }
+        public final Spliterator<K> spliterator()  {
+            return Spliterators.spliterator(this, Spliterator.SIZED |
+                                            Spliterator.ORDERED |
+                                            Spliterator.DISTINCT);
+        }
+        public final void forEach(Consumer<? super K> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int mc = modCount;
+            for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
+                action.accept(e.key);
+            if (modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this map.
+     * The collection is backed by the map, so changes to the map are
+     * reflected in the collection, and vice-versa.  If the map is
+     * modified while an iteration over the collection is in progress
+     * (except through the iterator's own <tt>remove</tt> operation),
+     * the results of the iteration are undefined.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the <tt>Iterator.remove</tt>,
+     * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
+     * <tt>retainAll</tt> and <tt>clear</tt> operations.  It does not
+     * support the <tt>add</tt> or <tt>addAll</tt> operations.
+     * Its {@link Spliterator} typically provides faster sequential
+     * performance but much poorer parallel performance than that of
+     * {@code HashMap}.
+     *
+     * @return a view of the values contained in this map
+     */
+    public Collection<V> values() {
+        Collection<V> vs;
+        return (vs = values) == null ? (values = new LinkedValues()) : vs;
+    }
+
+    final class LinkedValues extends AbstractCollection<V> {
+        public final int size()                 { return size; }
+        public final void clear()               { LinkedHashMap.this.clear(); }
+        public final Iterator<V> iterator() {
+            return new LinkedValueIterator();
+        }
+        public final boolean contains(Object o) { return containsValue(o); }
+        public final Spliterator<V> spliterator() {
+            return Spliterators.spliterator(this, Spliterator.SIZED |
+                                            Spliterator.ORDERED);
+        }
+        public final void forEach(Consumer<? super V> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int mc = modCount;
+            for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
+                action.accept(e.value);
+            if (modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    /**
+     * Returns a {@link Set} view of the mappings contained in this map.
+     * The set is backed by the map, so changes to the map are
+     * reflected in the set, and vice-versa.  If the map is modified
+     * while an iteration over the set is in progress (except through
+     * the iterator's own <tt>remove</tt> operation, or through the
+     * <tt>setValue</tt> operation on a map entry returned by the
+     * iterator) the results of the iteration are undefined.  The set
+     * supports element removal, which removes the corresponding
+     * mapping from the map, via the <tt>Iterator.remove</tt>,
+     * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt> and
+     * <tt>clear</tt> operations.  It does not support the
+     * <tt>add</tt> or <tt>addAll</tt> operations.
+     * Its {@link Spliterator} typically provides faster sequential
+     * performance but much poorer parallel performance than that of
+     * {@code HashMap}.
+     *
+     * @return a set view of the mappings contained in this map
+     */
+    public Set<Map.Entry<K,V>> entrySet() {
+        Set<Map.Entry<K,V>> es;
+        return (es = entrySet) == null ? (entrySet = new LinkedEntrySet()) : es;
+    }
+
+    final class LinkedEntrySet extends AbstractSet<Map.Entry<K,V>> {
+        public final int size()                 { return size; }
+        public final void clear()               { LinkedHashMap.this.clear(); }
+        public final Iterator<Map.Entry<K,V>> iterator() {
+            return new LinkedEntryIterator();
+        }
+        public final boolean contains(Object o) {
+            if (!(o instanceof Map.Entry))
+                return false;
+            Map.Entry<?,?> e = (Map.Entry<?,?>) o;
+            Object key = e.getKey();
+            Node<K,V> candidate = getNode(hash(key), key);
+            return candidate != null && candidate.equals(e);
+        }
+        public final boolean remove(Object o) {
+            if (o instanceof Map.Entry) {
+                Map.Entry<?,?> e = (Map.Entry<?,?>) o;
+                Object key = e.getKey();
+                Object value = e.getValue();
+                return removeNode(hash(key), key, value, true, true) != null;
+            }
+            return false;
+        }
+        public final Spliterator<Map.Entry<K,V>> spliterator() {
+            return Spliterators.spliterator(this, Spliterator.SIZED |
+                                            Spliterator.ORDERED |
+                                            Spliterator.DISTINCT);
+        }
+        public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
+            if (action == null)
+                throw new NullPointerException();
+            int mc = modCount;
+            for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
+                action.accept(e);
+            if (modCount != mc)
+                throw new ConcurrentModificationException();
+        }
+    }
+
+    // Map overrides
+
+    public void forEach(BiConsumer<? super K, ? super V> action) {
+        if (action == null)
+            throw new NullPointerException();
+        int mc = modCount;
+        for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
+            action.accept(e.key, e.value);
+        if (modCount != mc)
+            throw new ConcurrentModificationException();
+    }
+
+    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        if (function == null)
+            throw new NullPointerException();
+        int mc = modCount;
+        for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
+            e.value = function.apply(e.key, e.value);
+        if (modCount != mc)
+            throw new ConcurrentModificationException();
+    }
+
+    // Iterators
+
+    abstract class LinkedHashIterator {
+        LinkedHashMap.Entry<K,V> next;
+        LinkedHashMap.Entry<K,V> current;
+        int expectedModCount;
+
+        LinkedHashIterator() {
+            next = head;
+            expectedModCount = modCount;
+            current = null;
+        }
+
+        public final boolean hasNext() {
+            return next != null;
+        }
+
+        final LinkedHashMap.Entry<K,V> nextNode() {
+            LinkedHashMap.Entry<K,V> e = next;
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            if (e == null)
+                throw new NoSuchElementException();
+            current = e;
+            next = e.after;
+            return e;
+        }
+
+        public final void remove() {
+            Node<K,V> p = current;
+            if (p == null)
+                throw new IllegalStateException();
+            if (modCount != expectedModCount)
+                throw new ConcurrentModificationException();
+            current = null;
+            K key = p.key;
+            removeNode(hash(key), key, null, false, false);
+            expectedModCount = modCount;
+        }
+    }
+
+    final class LinkedKeyIterator extends LinkedHashIterator
+        implements Iterator<K> {
+        public final K next() { return nextNode().getKey(); }
+    }
+
+    final class LinkedValueIterator extends LinkedHashIterator
+        implements Iterator<V> {
+        public final V next() { return nextNode().value; }
+    }
+
+    final class LinkedEntryIterator extends LinkedHashIterator
+        implements Iterator<Map.Entry<K,V>> {
+        public final Map.Entry<K,V> next() { return nextNode(); }
+    }
+
+
 }
--- a/jdk/src/share/classes/java/util/Map.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/Map.java	Wed Jul 05 19:11:53 2017 +0200
@@ -805,6 +805,10 @@
      *     return false;
      * }</pre>
      *
+     * The default implementation does not throw NullPointerException
+     * for maps that do not support null values if oldValue is null unless
+     * newValue is also null.
+     *
      * @param key key with which the specified value is associated
      * @param oldValue value expected to be associated with the specified key
      * @param newValue value to be associated with the specified key
@@ -814,8 +818,11 @@
      *         (<a href="Collection.html#optional-restrictions">optional</a>)
      * @throws ClassCastException if the class of a specified key or value
      *         prevents it from being stored in this map
-     * @throws NullPointerException if a specified key or value is null,
+     * @throws NullPointerException if a specified key or newValue is null,
      *         and this map does not permit null keys or values
+     * @throws NullPointerException if oldValue is null and this map does not
+     *         permit null values
+     *         (<a href="Collection.html#optional-restrictions">optional</a>)
      * @throws IllegalArgumentException if some property of a specified key
      *         or value prevents it from being stored in this map
      * @since 1.8
--- a/jdk/src/share/classes/java/util/Properties.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/Properties.java	Wed Jul 05 19:11:53 2017 +0200
@@ -304,7 +304,7 @@
      * preceded by a backslash still yield single and double quote
      * characters, respectively.
      *
-     * <li> Only a single 'u' character is allowed in a Uniocde escape
+     * <li> Only a single 'u' character is allowed in a Unicode escape
      * sequence.
      *
      * </ul>
--- a/jdk/src/share/classes/java/util/TreeMap.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/TreeMap.java	Wed Jul 05 19:11:53 2017 +0200
@@ -1012,7 +1012,7 @@
         int expectedModCount = modCount;
 
         for (Entry<K, V> e = getFirstEntry(); e != null; e = successor(e)) {
-            e.value = Objects.requireNonNull(function.apply(e.key, e.value));
+            e.value = function.apply(e.key, e.value);
 
             if (expectedModCount != modCount) {
                 throw new ConcurrentModificationException();
--- a/jdk/src/share/classes/java/util/WeakHashMap.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/WeakHashMap.java	Wed Jul 05 19:11:53 2017 +0200
@@ -190,39 +190,6 @@
      */
     int modCount;
 
-    private static class Holder {
-        static final boolean USE_HASHSEED;
-
-        static {
-            String hashSeedProp = java.security.AccessController.doPrivileged(
-                    new sun.security.action.GetPropertyAction(
-                        "jdk.map.useRandomSeed"));
-            boolean localBool = (null != hashSeedProp)
-                    ? Boolean.parseBoolean(hashSeedProp) : false;
-            USE_HASHSEED = localBool;
-        }
-    }
-
-    /**
-     * A randomizing value associated with this instance that is applied to
-     * hash code of keys to make hash collisions harder to find.
-     *
-     * Non-final so it can be set lazily, but be sure not to set more than once.
-     */
-    transient int hashSeed;
-
-    /**
-     * Initialize the hashing mask value.
-     */
-    final void initHashSeed() {
-        if (sun.misc.VM.isBooted() && Holder.USE_HASHSEED) {
-            // Do not set hashSeed more than once!
-            // assert hashSeed == 0;
-            int seed = ThreadLocalRandom.current().nextInt();
-            hashSeed = (seed != 0) ? seed : 1;
-        }
-    }
-
     @SuppressWarnings("unchecked")
     private Entry<K,V>[] newTable(int n) {
         return (Entry<K,V>[]) new Entry<?,?>[n];
@@ -253,7 +220,6 @@
         table = newTable(capacity);
         this.loadFactor = loadFactor;
         threshold = (int)(capacity * loadFactor);
-        initHashSeed();
     }
 
     /**
@@ -329,7 +295,7 @@
      * in lower bits.
      */
     final int hash(Object k) {
-        int h = hashSeed ^ k.hashCode();
+        int h = k.hashCode();
 
         // This function ensures that hashCodes that differ only by
         // constant multiples at each bit position have a bounded
@@ -783,8 +749,7 @@
         public int hashCode() {
             K k = getKey();
             V v = getValue();
-            return ((k==null ? 0 : k.hashCode()) ^
-                    (v==null ? 0 : v.hashCode()));
+            return Objects.hashCode(k) ^ Objects.hashCode(v);
         }
 
         public String toString() {
--- a/jdk/src/share/classes/java/util/concurrent/ConcurrentHashMap.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/concurrent/ConcurrentHashMap.java	Wed Jul 05 19:11:53 2017 +0200
@@ -49,6 +49,7 @@
 import java.util.Iterator;
 import java.util.Map;
 import java.util.NoSuchElementException;
+import java.util.Objects;
 import java.util.Set;
 import java.util.Spliterator;
 import java.util.concurrent.ConcurrentMap;
@@ -373,27 +374,26 @@
      * The table is resized when occupancy exceeds a percentage
      * threshold (nominally, 0.75, but see below).  Any thread
      * noticing an overfull bin may assist in resizing after the
-     * initiating thread allocates and sets up the replacement
-     * array. However, rather than stalling, these other threads may
-     * proceed with insertions etc.  The use of TreeBins shields us
-     * from the worst case effects of overfilling while resizes are in
+     * initiating thread allocates and sets up the replacement array.
+     * However, rather than stalling, these other threads may proceed
+     * with insertions etc.  The use of TreeBins shields us from the
+     * worst case effects of overfilling while resizes are in
      * progress.  Resizing proceeds by transferring bins, one by one,
-     * from the table to the next table. To enable concurrency, the
-     * next table must be (incrementally) prefilled with place-holders
-     * serving as reverse forwarders to the old table.  Because we are
-     * using power-of-two expansion, the elements from each bin must
-     * either stay at same index, or move with a power of two
-     * offset. We eliminate unnecessary node creation by catching
-     * cases where old nodes can be reused because their next fields
-     * won't change.  On average, only about one-sixth of them need
-     * cloning when a table doubles. The nodes they replace will be
-     * garbage collectable as soon as they are no longer referenced by
-     * any reader thread that may be in the midst of concurrently
-     * traversing table.  Upon transfer, the old table bin contains
-     * only a special forwarding node (with hash field "MOVED") that
-     * contains the next table as its key. On encountering a
-     * forwarding node, access and update operations restart, using
-     * the new table.
+     * from the table to the next table. However, threads claim small
+     * blocks of indices to transfer (via field transferIndex) before
+     * doing so, reducing contention.  Because we are using
+     * power-of-two expansion, the elements from each bin must either
+     * stay at same index, or move with a power of two offset. We
+     * eliminate unnecessary node creation by catching cases where old
+     * nodes can be reused because their next fields won't change.  On
+     * average, only about one-sixth of them need cloning when a table
+     * doubles. The nodes they replace will be garbage collectable as
+     * soon as they are no longer referenced by any reader thread that
+     * may be in the midst of concurrently traversing table.  Upon
+     * transfer, the old table bin contains only a special forwarding
+     * node (with hash field "MOVED") that contains the next table as
+     * its key. On encountering a forwarding node, access and update
+     * operations restart, using the new table.
      *
      * Each bin transfer requires its bin lock, which can stall
      * waiting for locks while resizing. However, because other
@@ -401,13 +401,19 @@
      * locks, average aggregate waits become shorter as resizing
      * progresses.  The transfer operation must also ensure that all
      * accessible bins in both the old and new table are usable by any
-     * traversal.  This is arranged by proceeding from the last bin
-     * (table.length - 1) up towards the first.  Upon seeing a
-     * forwarding node, traversals (see class Traverser) arrange to
-     * move to the new table without revisiting nodes.  However, to
-     * ensure that no intervening nodes are skipped, bin splitting can
-     * only begin after the associated reverse-forwarders are in
-     * place.
+     * traversal.  This is arranged in part by proceeding from the
+     * last bin (table.length - 1) up towards the first.  Upon seeing
+     * a forwarding node, traversals (see class Traverser) arrange to
+     * move to the new table without revisiting nodes.  To ensure that
+     * no intervening nodes are skipped even when moved out of order,
+     * a stack (see class TableStack) is created on first encounter of
+     * a forwarding node during a traversal, to maintain its place if
+     * later processing the current table. The need for these
+     * save/restore mechanics is relatively rare, but when one
+     * forwarding node is encountered, typically many more will be.
+     * So Traversers use a simple caching scheme to avoid creating so
+     * many new TableStack nodes. (Thanks to Peter Levart for
+     * suggesting use of a stack here.)
      *
      * The traversal scheme also applies to partial traversals of
      * ranges of bins (via an alternate Traverser constructor)
@@ -776,11 +782,6 @@
     private transient volatile int transferIndex;
 
     /**
-     * The least available table index to split while resizing.
-     */
-    private transient volatile int transferOrigin;
-
-    /**
      * Spinlock (locked via CAS) used when resizing and/or creating CounterCells.
      */
     private transient volatile int cellsBusy;
@@ -1376,7 +1377,8 @@
         }
         int segmentShift = 32 - sshift;
         int segmentMask = ssize - 1;
-        @SuppressWarnings("unchecked") Segment<K,V>[] segments = (Segment<K,V>[])
+        @SuppressWarnings("unchecked")
+        Segment<K,V>[] segments = (Segment<K,V>[])
             new Segment<?,?>[DEFAULT_CONCURRENCY_LEVEL];
         for (int i = 0; i < segments.length; ++i)
             segments[i] = new Segment<K,V>(LOAD_FACTOR);
@@ -1419,8 +1421,10 @@
         long size = 0L;
         Node<K,V> p = null;
         for (;;) {
-            @SuppressWarnings("unchecked") K k = (K) s.readObject();
-            @SuppressWarnings("unchecked") V v = (V) s.readObject();
+            @SuppressWarnings("unchecked")
+            K k = (K) s.readObject();
+            @SuppressWarnings("unchecked")
+            V v = (V) s.readObject();
             if (k != null && v != null) {
                 p = new Node<K,V>(spread(k.hashCode()), k, v, p);
                 ++size;
@@ -1438,8 +1442,8 @@
                 int sz = (int)size;
                 n = tableSizeFor(sz + (sz >>> 1) + 1);
             }
-            @SuppressWarnings({"rawtypes","unchecked"})
-                Node<K,V>[] tab = (Node<K,V>[])new Node[n];
+            @SuppressWarnings("unchecked")
+            Node<K,V>[] tab = (Node<K,V>[])new Node<?,?>[n];
             int mask = n - 1;
             long added = 0L;
             while (p != null) {
@@ -2199,8 +2203,8 @@
                 try {
                     if ((tab = table) == null || tab.length == 0) {
                         int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
-                        @SuppressWarnings({"rawtypes","unchecked"})
-                            Node<K,V>[] nt = (Node<K,V>[])new Node[n];
+                        @SuppressWarnings("unchecked")
+                        Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
                         table = tab = nt;
                         sc = n - (n >>> 2);
                     }
@@ -2245,7 +2249,7 @@
             while (s >= (long)(sc = sizeCtl) && (tab = table) != null &&
                    tab.length < MAXIMUM_CAPACITY) {
                 if (sc < 0) {
-                    if (sc == -1 || transferIndex <= transferOrigin ||
+                    if (sc == -1 || transferIndex <= 0 ||
                         (nt = nextTable) == null)
                         break;
                     if (U.compareAndSwapInt(this, SIZECTL, sc, sc - 1))
@@ -2265,10 +2269,13 @@
         Node<K,V>[] nextTab; int sc;
         if ((f instanceof ForwardingNode) &&
             (nextTab = ((ForwardingNode<K,V>)f).nextTable) != null) {
-            if (nextTab == nextTable && tab == table &&
-                transferIndex > transferOrigin && (sc = sizeCtl) < -1 &&
-                U.compareAndSwapInt(this, SIZECTL, sc, sc - 1))
-                transfer(tab, nextTab);
+            while (transferIndex > 0 && nextTab == nextTable &&
+                   (sc = sizeCtl) < -1) {
+                if (U.compareAndSwapInt(this, SIZECTL, sc, sc - 1)) {
+                    transfer(tab, nextTab);
+                    break;
+                }
+            }
             return nextTab;
         }
         return table;
@@ -2290,8 +2297,8 @@
                 if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
                     try {
                         if (table == tab) {
-                            @SuppressWarnings({"rawtypes","unchecked"})
-                                Node<K,V>[] nt = (Node<K,V>[])new Node[n];
+                            @SuppressWarnings("unchecked")
+                            Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];
                             table = nt;
                             sc = n - (n >>> 2);
                         }
@@ -2318,36 +2325,27 @@
             stride = MIN_TRANSFER_STRIDE; // subdivide range
         if (nextTab == null) {            // initiating
             try {
-                @SuppressWarnings({"rawtypes","unchecked"})
-                    Node<K,V>[] nt = (Node<K,V>[])new Node[n << 1];
+                @SuppressWarnings("unchecked")
+                Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n << 1];
                 nextTab = nt;
             } catch (Throwable ex) {      // try to cope with OOME
                 sizeCtl = Integer.MAX_VALUE;
                 return;
             }
             nextTable = nextTab;
-            transferOrigin = n;
             transferIndex = n;
-            ForwardingNode<K,V> rev = new ForwardingNode<K,V>(tab);
-            for (int k = n; k > 0;) {    // progressively reveal ready slots
-                int nextk = (k > stride) ? k - stride : 0;
-                for (int m = nextk; m < k; ++m)
-                    nextTab[m] = rev;
-                for (int m = n + nextk; m < n + k; ++m)
-                    nextTab[m] = rev;
-                U.putOrderedInt(this, TRANSFERORIGIN, k = nextk);
-            }
         }
         int nextn = nextTab.length;
         ForwardingNode<K,V> fwd = new ForwardingNode<K,V>(nextTab);
         boolean advance = true;
         boolean finishing = false; // to ensure sweep before committing nextTab
         for (int i = 0, bound = 0;;) {
-            int nextIndex, nextBound, fh; Node<K,V> f;
+            Node<K,V> f; int fh;
             while (advance) {
+                int nextIndex, nextBound;
                 if (--i >= bound || finishing)
                     advance = false;
-                else if ((nextIndex = transferIndex) <= transferOrigin) {
+                else if ((nextIndex = transferIndex) <= 0) {
                     i = -1;
                     advance = false;
                 }
@@ -2361,29 +2359,22 @@
                 }
             }
             if (i < 0 || i >= n || i + n >= nextn) {
+                int sc;
                 if (finishing) {
                     nextTable = null;
                     table = nextTab;
                     sizeCtl = (n << 1) - (n >>> 1);
                     return;
                 }
-                for (int sc;;) {
-                    if (U.compareAndSwapInt(this, SIZECTL, sc = sizeCtl, ++sc)) {
-                        if (sc != -1)
-                            return;
-                        finishing = advance = true;
-                        i = n; // recheck before commit
-                        break;
-                    }
+                if (U.compareAndSwapInt(this, SIZECTL, sc = sizeCtl, ++sc)) {
+                    if (sc != -1)
+                        return;
+                    finishing = advance = true;
+                    i = n; // recheck before commit
                 }
             }
-            else if ((f = tabAt(tab, i)) == null) {
-                if (casTabAt(tab, i, null, fwd)) {
-                    setTabAt(nextTab, i, null);
-                    setTabAt(nextTab, i + n, null);
-                    advance = true;
-                }
-            }
+            else if ((f = tabAt(tab, i)) == null)
+                advance = casTabAt(tab, i, null, fwd);
             else if ((fh = f.hash) == MOVED)
                 advance = true; // already processed
             else {
@@ -3223,6 +3214,18 @@
     /* ----------------Table Traversal -------------- */
 
     /**
+     * Records the table, its length, and current traversal index for a
+     * traverser that must process a region of a forwarded table before
+     * proceeding with current table.
+     */
+    static final class TableStack<K,V> {
+        int length;
+        int index;
+        Node<K,V>[] tab;
+        TableStack<K,V> next;
+    }
+
+    /**
      * Encapsulates traversal for methods such as containsValue; also
      * serves as a base class for other iterators and spliterators.
      *
@@ -3246,6 +3249,7 @@
     static class Traverser<K,V> {
         Node<K,V>[] tab;        // current table; updated if resized
         Node<K,V> next;         // the next entry to use
+        TableStack<K,V> stack, spare; // to save/restore on ForwardingNodes
         int index;              // index of bin to use next
         int baseIndex;          // current index of initial table
         int baseLimit;          // index bound for initial table
@@ -3267,16 +3271,17 @@
             if ((e = next) != null)
                 e = e.next;
             for (;;) {
-                Node<K,V>[] t; int i, n; K ek;  // must use locals in checks
+                Node<K,V>[] t; int i, n;  // must use locals in checks
                 if (e != null)
                     return next = e;
                 if (baseIndex >= baseLimit || (t = tab) == null ||
                     (n = t.length) <= (i = index) || i < 0)
                     return next = null;
-                if ((e = tabAt(t, index)) != null && e.hash < 0) {
+                if ((e = tabAt(t, i)) != null && e.hash < 0) {
                     if (e instanceof ForwardingNode) {
                         tab = ((ForwardingNode<K,V>)e).nextTable;
                         e = null;
+                        pushState(t, i, n);
                         continue;
                     }
                     else if (e instanceof TreeBin)
@@ -3284,10 +3289,49 @@
                     else
                         e = null;
                 }
-                if ((index += baseSize) >= n)
-                    index = ++baseIndex;    // visit upper slots if present
+                if (stack != null)
+                    recoverState(n);
+                else if ((index = i + baseSize) >= n)
+                    index = ++baseIndex; // visit upper slots if present
             }
         }
+
+        /**
+         * Saves traversal state upon encountering a forwarding node.
+         */
+        private void pushState(Node<K,V>[] t, int i, int n) {
+            TableStack<K,V> s = spare;  // reuse if possible
+            if (s != null)
+                spare = s.next;
+            else
+                s = new TableStack<K,V>();
+            s.tab = t;
+            s.length = n;
+            s.index = i;
+            s.next = stack;
+            stack = s;
+        }
+
+        /**
+         * Possibly pops traversal state.
+         *
+         * @param n length of current table
+         */
+        private void recoverState(int n) {
+            TableStack<K,V> s; int len;
+            while ((s = stack) != null && (index += (len = s.length)) >= n) {
+                n = len;
+                index = s.index;
+                tab = s.tab;
+                s.tab = null;
+                TableStack<K,V> next = s.next;
+                s.next = spare; // save for reuse
+                stack = next;
+                spare = s;
+            }
+            if (s == null && (index += baseSize) >= n)
+                index = ++baseIndex;
+        }
     }
 
     /**
@@ -4410,6 +4454,7 @@
         }
 
         public final boolean removeAll(Collection<?> c) {
+            Objects.requireNonNull(c);
             boolean modified = false;
             for (Iterator<E> it = iterator(); it.hasNext();) {
                 if (c.contains(it.next())) {
@@ -4421,6 +4466,7 @@
         }
 
         public final boolean retainAll(Collection<?> c) {
+            Objects.requireNonNull(c);
             boolean modified = false;
             for (Iterator<E> it = iterator(); it.hasNext();) {
                 if (!c.contains(it.next())) {
@@ -4719,6 +4765,7 @@
     abstract static class BulkTask<K,V,R> extends CountedCompleter<R> {
         Node<K,V>[] tab;        // same as Traverser
         Node<K,V> next;
+        TableStack<K,V> stack, spare;
         int index;
         int baseIndex;
         int baseLimit;
@@ -4747,16 +4794,17 @@
             if ((e = next) != null)
                 e = e.next;
             for (;;) {
-                Node<K,V>[] t; int i, n; K ek;  // must use locals in checks
+                Node<K,V>[] t; int i, n;
                 if (e != null)
                     return next = e;
                 if (baseIndex >= baseLimit || (t = tab) == null ||
                     (n = t.length) <= (i = index) || i < 0)
                     return next = null;
-                if ((e = tabAt(t, index)) != null && e.hash < 0) {
+                if ((e = tabAt(t, i)) != null && e.hash < 0) {
                     if (e instanceof ForwardingNode) {
                         tab = ((ForwardingNode<K,V>)e).nextTable;
                         e = null;
+                        pushState(t, i, n);
                         continue;
                     }
                     else if (e instanceof TreeBin)
@@ -4764,10 +4812,41 @@
                     else
                         e = null;
                 }
-                if ((index += baseSize) >= n)
-                    index = ++baseIndex;    // visit upper slots if present
+                if (stack != null)
+                    recoverState(n);
+                else if ((index = i + baseSize) >= n)
+                    index = ++baseIndex;
             }
         }
+
+        private void pushState(Node<K,V>[] t, int i, int n) {
+            TableStack<K,V> s = spare;
+            if (s != null)
+                spare = s.next;
+            else
+                s = new TableStack<K,V>();
+            s.tab = t;
+            s.length = n;
+            s.index = i;
+            s.next = stack;
+            stack = s;
+        }
+
+        private void recoverState(int n) {
+            TableStack<K,V> s; int len;
+            while ((s = stack) != null && (index += (len = s.length)) >= n) {
+                n = len;
+                index = s.index;
+                tab = s.tab;
+                s.tab = null;
+                TableStack<K,V> next = s.next;
+                s.next = spare; // save for reuse
+                stack = next;
+                spare = s;
+            }
+            if (s == null && (index += baseSize) >= n)
+                index = ++baseIndex;
+        }
     }
 
     /*
@@ -5226,7 +5305,8 @@
                 result = r;
                 CountedCompleter<?> c;
                 for (c = firstComplete(); c != null; c = c.nextComplete()) {
-                    @SuppressWarnings("unchecked") ReduceKeysTask<K,V>
+                    @SuppressWarnings("unchecked")
+                    ReduceKeysTask<K,V>
                         t = (ReduceKeysTask<K,V>)c,
                         s = t.rights;
                     while (s != null) {
@@ -5273,7 +5353,8 @@
                 result = r;
                 CountedCompleter<?> c;
                 for (c = firstComplete(); c != null; c = c.nextComplete()) {
-                    @SuppressWarnings("unchecked") ReduceValuesTask<K,V>
+                    @SuppressWarnings("unchecked")
+                    ReduceValuesTask<K,V>
                         t = (ReduceValuesTask<K,V>)c,
                         s = t.rights;
                     while (s != null) {
@@ -5318,7 +5399,8 @@
                 result = r;
                 CountedCompleter<?> c;
                 for (c = firstComplete(); c != null; c = c.nextComplete()) {
-                    @SuppressWarnings("unchecked") ReduceEntriesTask<K,V>
+                    @SuppressWarnings("unchecked")
+                    ReduceEntriesTask<K,V>
                         t = (ReduceEntriesTask<K,V>)c,
                         s = t.rights;
                     while (s != null) {
@@ -5371,7 +5453,8 @@
                 result = r;
                 CountedCompleter<?> c;
                 for (c = firstComplete(); c != null; c = c.nextComplete()) {
-                    @SuppressWarnings("unchecked") MapReduceKeysTask<K,V,U>
+                    @SuppressWarnings("unchecked")
+                    MapReduceKeysTask<K,V,U>
                         t = (MapReduceKeysTask<K,V,U>)c,
                         s = t.rights;
                     while (s != null) {
@@ -5424,7 +5507,8 @@
                 result = r;
                 CountedCompleter<?> c;
                 for (c = firstComplete(); c != null; c = c.nextComplete()) {
-                    @SuppressWarnings("unchecked") MapReduceValuesTask<K,V,U>
+                    @SuppressWarnings("unchecked")
+                    MapReduceValuesTask<K,V,U>
                         t = (MapReduceValuesTask<K,V,U>)c,
                         s = t.rights;
                     while (s != null) {
@@ -5477,7 +5561,8 @@
                 result = r;
                 CountedCompleter<?> c;
                 for (c = firstComplete(); c != null; c = c.nextComplete()) {
-                    @SuppressWarnings("unchecked") MapReduceEntriesTask<K,V,U>
+                    @SuppressWarnings("unchecked")
+                    MapReduceEntriesTask<K,V,U>
                         t = (MapReduceEntriesTask<K,V,U>)c,
                         s = t.rights;
                     while (s != null) {
@@ -5530,7 +5615,8 @@
                 result = r;
                 CountedCompleter<?> c;
                 for (c = firstComplete(); c != null; c = c.nextComplete()) {
-                    @SuppressWarnings("unchecked") MapReduceMappingsTask<K,V,U>
+                    @SuppressWarnings("unchecked")
+                    MapReduceMappingsTask<K,V,U>
                         t = (MapReduceMappingsTask<K,V,U>)c,
                         s = t.rights;
                     while (s != null) {
@@ -5582,7 +5668,8 @@
                 result = r;
                 CountedCompleter<?> c;
                 for (c = firstComplete(); c != null; c = c.nextComplete()) {
-                    @SuppressWarnings("unchecked") MapReduceKeysToDoubleTask<K,V>
+                    @SuppressWarnings("unchecked")
+                    MapReduceKeysToDoubleTask<K,V>
                         t = (MapReduceKeysToDoubleTask<K,V>)c,
                         s = t.rights;
                     while (s != null) {
@@ -5631,7 +5718,8 @@
                 result = r;
                 CountedCompleter<?> c;
                 for (c = firstComplete(); c != null; c = c.nextComplete()) {
-                    @SuppressWarnings("unchecked") MapReduceValuesToDoubleTask<K,V>
+                    @SuppressWarnings("unchecked")
+                    MapReduceValuesToDoubleTask<K,V>
                         t = (MapReduceValuesToDoubleTask<K,V>)c,
                         s = t.rights;
                     while (s != null) {
@@ -5680,7 +5768,8 @@
                 result = r;
                 CountedCompleter<?> c;
                 for (c = firstComplete(); c != null; c = c.nextComplete()) {
-                    @SuppressWarnings("unchecked") MapReduceEntriesToDoubleTask<K,V>
+                    @SuppressWarnings("unchecked")
+                    MapReduceEntriesToDoubleTask<K,V>
                         t = (MapReduceEntriesToDoubleTask<K,V>)c,
                         s = t.rights;
                     while (s != null) {
@@ -5729,7 +5818,8 @@
                 result = r;
                 CountedCompleter<?> c;
                 for (c = firstComplete(); c != null; c = c.nextComplete()) {
-                    @SuppressWarnings("unchecked") MapReduceMappingsToDoubleTask<K,V>
+                    @SuppressWarnings("unchecked")
+                    MapReduceMappingsToDoubleTask<K,V>
                         t = (MapReduceMappingsToDoubleTask<K,V>)c,
                         s = t.rights;
                     while (s != null) {
@@ -5778,7 +5868,8 @@
                 result = r;
                 CountedCompleter<?> c;
                 for (c = firstComplete(); c != null; c = c.nextComplete()) {
-                    @SuppressWarnings("unchecked") MapReduceKeysToLongTask<K,V>
+                    @SuppressWarnings("unchecked")
+                    MapReduceKeysToLongTask<K,V>
                         t = (MapReduceKeysToLongTask<K,V>)c,
                         s = t.rights;
                     while (s != null) {
@@ -5827,7 +5918,8 @@
                 result = r;
                 CountedCompleter<?> c;
                 for (c = firstComplete(); c != null; c = c.nextComplete()) {
-                    @SuppressWarnings("unchecked") MapReduceValuesToLongTask<K,V>
+                    @SuppressWarnings("unchecked")
+                    MapReduceValuesToLongTask<K,V>
                         t = (MapReduceValuesToLongTask<K,V>)c,
                         s = t.rights;
                     while (s != null) {
@@ -5876,7 +5968,8 @@
                 result = r;
                 CountedCompleter<?> c;
                 for (c = firstComplete(); c != null; c = c.nextComplete()) {
-                    @SuppressWarnings("unchecked") MapReduceEntriesToLongTask<K,V>
+                    @SuppressWarnings("unchecked")
+                    MapReduceEntriesToLongTask<K,V>
                         t = (MapReduceEntriesToLongTask<K,V>)c,
                         s = t.rights;
                     while (s != null) {
@@ -5925,7 +6018,8 @@
                 result = r;
                 CountedCompleter<?> c;
                 for (c = firstComplete(); c != null; c = c.nextComplete()) {
-                    @SuppressWarnings("unchecked") MapReduceMappingsToLongTask<K,V>
+                    @SuppressWarnings("unchecked")
+                    MapReduceMappingsToLongTask<K,V>
                         t = (MapReduceMappingsToLongTask<K,V>)c,
                         s = t.rights;
                     while (s != null) {
@@ -5974,7 +6068,8 @@
                 result = r;
                 CountedCompleter<?> c;
                 for (c = firstComplete(); c != null; c = c.nextComplete()) {
-                    @SuppressWarnings("unchecked") MapReduceKeysToIntTask<K,V>
+                    @SuppressWarnings("unchecked")
+                    MapReduceKeysToIntTask<K,V>
                         t = (MapReduceKeysToIntTask<K,V>)c,
                         s = t.rights;
                     while (s != null) {
@@ -6023,7 +6118,8 @@
                 result = r;
                 CountedCompleter<?> c;
                 for (c = firstComplete(); c != null; c = c.nextComplete()) {
-                    @SuppressWarnings("unchecked") MapReduceValuesToIntTask<K,V>
+                    @SuppressWarnings("unchecked")
+                    MapReduceValuesToIntTask<K,V>
                         t = (MapReduceValuesToIntTask<K,V>)c,
                         s = t.rights;
                     while (s != null) {
@@ -6072,7 +6168,8 @@
                 result = r;
                 CountedCompleter<?> c;
                 for (c = firstComplete(); c != null; c = c.nextComplete()) {
-                    @SuppressWarnings("unchecked") MapReduceEntriesToIntTask<K,V>
+                    @SuppressWarnings("unchecked")
+                    MapReduceEntriesToIntTask<K,V>
                         t = (MapReduceEntriesToIntTask<K,V>)c,
                         s = t.rights;
                     while (s != null) {
@@ -6121,7 +6218,8 @@
                 result = r;
                 CountedCompleter<?> c;
                 for (c = firstComplete(); c != null; c = c.nextComplete()) {
-                    @SuppressWarnings("unchecked") MapReduceMappingsToIntTask<K,V>
+                    @SuppressWarnings("unchecked")
+                    MapReduceMappingsToIntTask<K,V>
                         t = (MapReduceMappingsToIntTask<K,V>)c,
                         s = t.rights;
                     while (s != null) {
@@ -6137,7 +6235,6 @@
     private static final sun.misc.Unsafe U;
     private static final long SIZECTL;
     private static final long TRANSFERINDEX;
-    private static final long TRANSFERORIGIN;
     private static final long BASECOUNT;
     private static final long CELLSBUSY;
     private static final long CELLVALUE;
@@ -6152,8 +6249,6 @@
                 (k.getDeclaredField("sizeCtl"));
             TRANSFERINDEX = U.objectFieldOffset
                 (k.getDeclaredField("transferIndex"));
-            TRANSFERORIGIN = U.objectFieldOffset
-                (k.getDeclaredField("transferOrigin"));
             BASECOUNT = U.objectFieldOffset
                 (k.getDeclaredField("baseCount"));
             CELLSBUSY = U.objectFieldOffset
--- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongArray.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongArray.java	Wed Jul 05 19:11:53 2017 +0200
@@ -303,7 +303,7 @@
      * @return the previous value
      * @since 1.8
      */
-    public final long getAndAccumulate(int i, int x,
+    public final long getAndAccumulate(int i, long x,
                                       LongBinaryOperator accumulatorFunction) {
         long offset = checkedByteOffset(i);
         long prev, next;
@@ -329,7 +329,7 @@
      * @return the updated value
      * @since 1.8
      */
-    public final long accumulateAndGet(int i, int x,
+    public final long accumulateAndGet(int i, long x,
                                       LongBinaryOperator accumulatorFunction) {
         long offset = checkedByteOffset(i);
         long prev, next;
--- a/jdk/src/share/classes/java/util/function/package-info.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/function/package-info.java	Wed Jul 05 19:11:53 2017 +0200
@@ -105,5 +105,6 @@
  * </ul>
  *
  * @see java.lang.FunctionalInterface
+ * @since 1.8
  */
 package java.util.function;
--- a/jdk/src/share/classes/java/util/logging/ConsoleHandler.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/logging/ConsoleHandler.java	Wed Jul 05 19:11:53 2017 +0200
@@ -26,9 +26,6 @@
 
 package java.util.logging;
 
-import java.io.*;
-import java.net.*;
-
 /**
  * This <tt>Handler</tt> publishes log records to <tt>System.err</tt>.
  * By default the <tt>SimpleFormatter</tt> is used to generate brief summaries.
@@ -114,6 +111,7 @@
      * @param  record  description of the log event. A null record is
      *                 silently ignored and is not published
      */
+    @Override
     public void publish(LogRecord record) {
         super.publish(record);
         flush();
@@ -124,6 +122,7 @@
      * to close the output stream.  That is, we do <b>not</b>
      * close <tt>System.err</tt>.
      */
+    @Override
     public void close() {
         flush();
     }
--- a/jdk/src/share/classes/java/util/logging/FileHandler.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/logging/FileHandler.java	Wed Jul 05 19:11:53 2017 +0200
@@ -149,7 +149,7 @@
     private FileChannel lockFileChannel;
     private File files[];
     private static final int MAX_LOCKS = 100;
-    private static java.util.HashMap<String, String> locks = new java.util.HashMap<>();
+    private static final java.util.HashMap<String, String> locks = new java.util.HashMap<>();
 
     /**
      * A metered stream is a subclass of OutputStream that
@@ -157,7 +157,7 @@
      * (b) keeps track of how many bytes have been written
      */
     private class MeteredStream extends OutputStream {
-        OutputStream out;
+        final OutputStream out;
         int written;
 
         MeteredStream(OutputStream out, int written) {
@@ -165,25 +165,30 @@
             this.written = written;
         }
 
+        @Override
         public void write(int b) throws IOException {
             out.write(b);
             written++;
         }
 
+        @Override
         public void write(byte buff[]) throws IOException {
             out.write(buff);
             written += buff.length;
         }
 
+        @Override
         public void write(byte buff[], int off, int len) throws IOException {
             out.write(buff,off,len);
             written += len;
         }
 
+        @Override
         public void flush() throws IOException {
             out.flush();
         }
 
+        @Override
         public void close() throws IOException {
             out.close();
         }
@@ -607,6 +612,7 @@
      * @param  record  description of the log event. A null record is
      *                 silently ignored and is not published
      */
+    @Override
     public synchronized void publish(LogRecord record) {
         if (!isLoggable(record)) {
             return;
@@ -620,6 +626,7 @@
             // currently being called from untrusted code.
             // So it is safe to raise privilege here.
             AccessController.doPrivileged(new PrivilegedAction<Object>() {
+                @Override
                 public Object run() {
                     rotate();
                     return null;
@@ -634,6 +641,7 @@
      * @exception  SecurityException  if a security manager exists and if
      *             the caller does not have <tt>LoggingPermission("control")</tt>.
      */
+    @Override
     public synchronized void close() throws SecurityException {
         super.close();
         // Unlock any lock file.
@@ -656,6 +664,7 @@
 
     private static class InitializationErrorManager extends ErrorManager {
         Exception lastException;
+        @Override
         public void error(String msg, Exception ex, int code) {
             lastException = ex;
         }
--- a/jdk/src/share/classes/java/util/logging/Handler.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/logging/Handler.java	Wed Jul 05 19:11:53 2017 +0200
@@ -47,12 +47,20 @@
 
 public abstract class Handler {
     private static final int offValue = Level.OFF.intValue();
-    private LogManager manager = LogManager.getLogManager();
-    private Filter filter;
-    private Formatter formatter;
-    private Level logLevel = Level.ALL;
-    private ErrorManager errorManager = new ErrorManager();
-    private String encoding;
+    private final LogManager manager = LogManager.getLogManager();
+
+    // We're using volatile here to avoid synchronizing getters, which
+    // would prevent other threads from calling isLoggable()
+    // while publish() is executing.
+    // On the other hand, setters will be synchronized to exclude concurrent
+    // execution with more complex methods, such as StreamHandler.publish().
+    // We wouldn't want 'level' to be changed by another thread in the middle
+    // of the execution of a 'publish' call.
+    private volatile Filter filter;
+    private volatile Formatter formatter;
+    private volatile Level logLevel = Level.ALL;
+    private volatile ErrorManager errorManager = new ErrorManager();
+    private volatile String encoding;
 
     // Package private support for security checking.  When sealed
     // is true, we access check updates to the class.
@@ -110,7 +118,7 @@
      * @exception  SecurityException  if a security manager exists and if
      *             the caller does not have <tt>LoggingPermission("control")</tt>.
      */
-    public void setFormatter(Formatter newFormatter) throws SecurityException {
+    public synchronized void setFormatter(Formatter newFormatter) throws SecurityException {
         checkPermission();
         // Check for a null pointer:
         newFormatter.getClass();
@@ -138,7 +146,7 @@
      * @exception  UnsupportedEncodingException if the named encoding is
      *          not supported.
      */
-    public void setEncoding(String encoding)
+    public synchronized void setEncoding(String encoding)
                         throws SecurityException, java.io.UnsupportedEncodingException {
         checkPermission();
         if (encoding != null) {
@@ -174,7 +182,7 @@
      * @exception  SecurityException  if a security manager exists and if
      *             the caller does not have <tt>LoggingPermission("control")</tt>.
      */
-    public void setFilter(Filter newFilter) throws SecurityException {
+    public synchronized void setFilter(Filter newFilter) throws SecurityException {
         checkPermission();
         filter = newFilter;
     }
@@ -198,7 +206,7 @@
      * @exception  SecurityException  if a security manager exists and if
      *             the caller does not have <tt>LoggingPermission("control")</tt>.
      */
-    public void setErrorManager(ErrorManager em) {
+    public synchronized void setErrorManager(ErrorManager em) {
         checkPermission();
         if (em == null) {
            throw new NullPointerException();
@@ -264,7 +272,7 @@
      * than this level will be discarded.
      * @return  the level of messages being logged.
      */
-    public synchronized Level getLevel() {
+    public Level getLevel() {
         return logLevel;
     }
 
@@ -282,11 +290,11 @@
      *
      */
     public boolean isLoggable(LogRecord record) {
-        int levelValue = getLevel().intValue();
+        final int levelValue = getLevel().intValue();
         if (record.getLevel().intValue() < levelValue || levelValue == offValue) {
             return false;
         }
-        Filter filter = getFilter();
+        final Filter filter = getFilter();
         if (filter == null) {
             return true;
         }
--- a/jdk/src/share/classes/java/util/logging/Level.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/logging/Level.java	Wed Jul 05 19:11:53 2017 +0200
@@ -27,6 +27,7 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.ResourceBundle;
 
@@ -63,7 +64,7 @@
  */
 
 public class Level implements java.io.Serializable {
-    private static String defaultBundle = "sun.util.logging.resources.logging";
+    private static final String defaultBundle = "sun.util.logging.resources.logging";
 
     /**
      * @serial  The non-localized name of the level.
@@ -81,7 +82,8 @@
     private final String resourceBundleName;
 
     // localized level name
-    private String localizedLevelName;
+    private transient String localizedLevelName;
+    private transient Locale cachedLocale;
 
     /**
      * OFF is a special level that can be used to turn off logging.
@@ -209,6 +211,7 @@
         this.value = value;
         this.resourceBundleName = resourceBundleName;
         this.localizedLevelName = resourceBundleName == null ? name : null;
+        this.cachedLocale = null;
         KnownLevel.add(this);
     }
 
@@ -250,17 +253,71 @@
         return this.name;
     }
 
-    final synchronized String getLocalizedLevelName() {
+    private String computeLocalizedLevelName(Locale newLocale) {
+        ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName, newLocale);
+        final String localizedName = rb.getString(name);
+
+        final boolean isDefaultBundle = defaultBundle.equals(resourceBundleName);
+        if (!isDefaultBundle) return localizedName;
+
+        // This is a trick to determine whether the name has been translated
+        // or not. If it has not been translated, we need to use Locale.ROOT
+        // when calling toUpperCase().
+        final Locale rbLocale = rb.getLocale();
+        final Locale locale =
+                Locale.ROOT.equals(rbLocale)
+                || name.equals(localizedName.toUpperCase(Locale.ROOT))
+                ? Locale.ROOT : rbLocale;
+
+        // ALL CAPS in a resource bundle's message indicates no translation
+        // needed per Oracle translation guideline.  To workaround this
+        // in Oracle JDK implementation, convert the localized level name
+        // to uppercase for compatibility reason.
+        return Locale.ROOT.equals(locale) ? name : localizedName.toUpperCase(locale);
+    }
+
+    // Avoid looking up the localizedLevelName twice if we already
+    // have it.
+    final String getCachedLocalizedLevelName() {
+
         if (localizedLevelName != null) {
-            return localizedLevelName;
+            if (cachedLocale != null) {
+                if (cachedLocale.equals(Locale.getDefault())) {
+                    // OK: our cached value was looked up with the same
+                    //     locale. We can use it.
+                    return localizedLevelName;
+                }
+            }
         }
 
+        if (resourceBundleName == null) {
+            // No resource bundle: just use the name.
+            return name;
+        }
+
+        // We need to compute the localized name.
+        // Either because it's the first time, or because our cached
+        // value is for a different locale. Just return null.
+        return null;
+    }
+
+    final synchronized String getLocalizedLevelName() {
+
+        // See if we have a cached localized name
+        final String cachedLocalizedName = getCachedLocalizedLevelName();
+        if (cachedLocalizedName != null) {
+            return cachedLocalizedName;
+        }
+
+        // No cached localized name or cache invalid.
+        // Need to compute the localized name.
+        final Locale newLocale = Locale.getDefault();
         try {
-            ResourceBundle rb = ResourceBundle.getBundle(resourceBundleName);
-            localizedLevelName = rb.getString(name);
+            localizedLevelName = computeLocalizedLevelName(newLocale);
         } catch (Exception ex) {
             localizedLevelName = name;
         }
+        cachedLocale = newLocale;
         return localizedLevelName;
     }
 
@@ -318,6 +375,7 @@
      *
      * @return the non-localized name of the Level, for example "INFO".
      */
+    @Override
     public final String toString() {
         return name;
     }
@@ -420,6 +478,7 @@
      * Compare two objects for value equality.
      * @return true if and only if the two objects have the same level value.
      */
+    @Override
     public boolean equals(Object ox) {
         try {
             Level lx = (Level)ox;
@@ -433,6 +492,7 @@
      * Generate a hashcode.
      * @return a hashcode based on the level value
      */
+    @Override
     public int hashCode() {
         return this.value;
     }
--- a/jdk/src/share/classes/java/util/logging/LogManager.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/logging/LogManager.java	Wed Jul 05 19:11:53 2017 +0200
@@ -144,7 +144,7 @@
 
 public class LogManager {
     // The global LogManager object
-    private static LogManager manager;
+    private static final LogManager manager;
 
     private Properties props = new Properties();
     private final static Level defaultLevel = Level.INFO;
@@ -156,8 +156,10 @@
     // LoggerContext for system loggers and user loggers
     private final LoggerContext systemContext = new SystemLoggerContext();
     private final LoggerContext userContext = new LoggerContext();
-    private Logger rootLogger;
-
+    // non final field - make it volatile to make sure that other threads
+    // will see the new value once ensureLogManagerInitialized() has finished
+    // executing.
+    private volatile Logger rootLogger;
     // Have we done the primordial reading of the configuration file?
     // (Must be done after a suitable amount of java.lang.System
     // initialization has been done)
@@ -169,58 +171,35 @@
     private boolean deathImminent;
 
     static {
-        AccessController.doPrivileged(new PrivilegedAction<Object>() {
-                public Object run() {
-                    String cname = null;
-                    try {
-                        cname = System.getProperty("java.util.logging.manager");
-                        if (cname != null) {
-                            try {
-                                Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(cname);
-                                manager = (LogManager) clz.newInstance();
-                            } catch (ClassNotFoundException ex) {
-                                Class<?> clz = Thread.currentThread().getContextClassLoader().loadClass(cname);
-                                manager = (LogManager) clz.newInstance();
-                            }
+        manager = AccessController.doPrivileged(new PrivilegedAction<LogManager>() {
+            @Override
+            public LogManager run() {
+                LogManager mgr = null;
+                String cname = null;
+                try {
+                    cname = System.getProperty("java.util.logging.manager");
+                    if (cname != null) {
+                        try {
+                            Class<?> clz = ClassLoader.getSystemClassLoader()
+                                    .loadClass(cname);
+                            mgr = (LogManager) clz.newInstance();
+                        } catch (ClassNotFoundException ex) {
+                            Class<?> clz = Thread.currentThread()
+                                    .getContextClassLoader().loadClass(cname);
+                            mgr = (LogManager) clz.newInstance();
                         }
-                    } catch (Exception ex) {
-                        System.err.println("Could not load Logmanager \"" + cname + "\"");
-                        ex.printStackTrace();
                     }
-                    if (manager == null) {
-                        manager = new LogManager();
-                    }
+                } catch (Exception ex) {
+                    System.err.println("Could not load Logmanager \"" + cname + "\"");
+                    ex.printStackTrace();
+                }
+                if (mgr == null) {
+                    mgr = new LogManager();
+                }
+                return mgr;
 
-                    // Create and retain Logger for the root of the namespace.
-                    manager.rootLogger = manager.new RootLogger();
-                    // since by design the global manager's userContext and
-                    // systemContext don't have their requiresDefaultLoggers
-                    // flag set - we make sure to add the root logger to
-                    // the global manager's default contexts here.
-                    manager.addLogger(manager.rootLogger);
-                    manager.systemContext.addLocalLogger(manager.rootLogger, false);
-                    manager.userContext.addLocalLogger(manager.rootLogger, false);
-
-                    // Adding the global Logger. Doing so in the Logger.<clinit>
-                    // would deadlock with the LogManager.<clinit>.
-                    // Do not call Logger.getGlobal() here as this might trigger
-                    // the deadlock too.
-                    @SuppressWarnings("deprecation")
-                    final Logger global = Logger.global;
-                    global.setLogManager(manager);
-
-                    // Make sure the global logger will be registered in the
-                    // global manager's default contexts.
-                    manager.addLogger(global);
-                    manager.systemContext.addLocalLogger(global, false);
-                    manager.userContext.addLocalLogger(global, false);
-
-                    // We don't call readConfiguration() here, as we may be running
-                    // very early in the JVM startup sequence.  Instead readConfiguration
-                    // will be called lazily in getLogManager().
-                    return null;
-                }
-            });
+            }
+        });
     }
 
 
@@ -235,6 +214,7 @@
             this.setContextClassLoader(null);
         }
 
+        @Override
         public void run() {
             // This is to ensure the LogManager.<clinit> is completed
             // before synchronized block. Otherwise deadlocks are possible.
@@ -271,12 +251,103 @@
     }
 
     /**
+     * Lazy initialization: if this instance of manager is the global
+     * manager then this method will read the initial configuration and
+     * add the root logger and global logger by calling addLogger().
+     *
+     * Note that it is subtly different from what we do in LoggerContext.
+     * In LoggerContext we're patching up the logger context tree in order to add
+     * the root and global logger *to the context tree*.
+     *
+     * For this to work, addLogger() must have already have been called
+     * once on the LogManager instance for the default logger being
+     * added.
+     *
+     * This is why ensureLogManagerInitialized() needs to be called before
+     * any logger is added to any logger context.
+     *
+     */
+    private boolean initializedCalled = false;
+    private volatile boolean initializationDone = false;
+    final void ensureLogManagerInitialized() {
+        final LogManager owner = this;
+        if (initializationDone || owner != manager) {
+            // we don't want to do this twice, and we don't want to do
+            // this on private manager instances.
+            return;
+        }
+
+        // Maybe another thread has called ensureLogManagerInitialized()
+        // before us and is still executing it. If so we will block until
+        // the log manager has finished initialized, then acquire the monitor,
+        // notice that initializationDone is now true and return.
+        // Otherwise - we have come here first! We will acquire the monitor,
+        // see that initializationDone is still false, and perform the
+        // initialization.
+        //
+        synchronized(this) {
+            // If initializedCalled is true it means that we're already in
+            // the process of initializing the LogManager in this thread.
+            // There has been a recursive call to ensureLogManagerInitialized().
+            final boolean isRecursiveInitialization = (initializedCalled == true);
+
+            assert initializedCalled || !initializationDone
+                    : "Initialization can't be done if initialized has not been called!";
+
+            if (isRecursiveInitialization || initializationDone) {
+                // If isRecursiveInitialization is true it means that we're
+                // already in the process of initializing the LogManager in
+                // this thread. There has been a recursive call to
+                // ensureLogManagerInitialized(). We should not proceed as
+                // it would lead to infinite recursion.
+                //
+                // If initializationDone is true then it means the manager
+                // has finished initializing; just return: we're done.
+                return;
+            }
+            // Calling addLogger below will in turn call requiresDefaultLogger()
+            // which will call ensureLogManagerInitialized().
+            // We use initializedCalled to break the recursion.
+            initializedCalled = true;
+            try {
+                AccessController.doPrivileged(new PrivilegedAction<Object>() {
+                    @Override
+                    public Object run() {
+                        assert rootLogger == null;
+                        assert initializedCalled && !initializationDone;
+
+                        // Read configuration.
+                        owner.readPrimordialConfiguration();
+
+                        // Create and retain Logger for the root of the namespace.
+                        owner.rootLogger = owner.new RootLogger();
+                        owner.addLogger(owner.rootLogger);
+
+                        // Adding the global Logger.
+                        // Do not call Logger.getGlobal() here as this might trigger
+                        // subtle inter-dependency issues.
+                        @SuppressWarnings("deprecation")
+                        final Logger global = Logger.global;
+
+                        // Make sure the global logger will be registered in the
+                        // global manager
+                        owner.addLogger(global);
+                        return null;
+                    }
+                });
+            } finally {
+                initializationDone = true;
+            }
+        }
+    }
+
+    /**
      * Returns the global LogManager object.
      * @return the global LogManager object
      */
     public static LogManager getLogManager() {
         if (manager != null) {
-            manager.readPrimordialConfiguration();
+            manager.ensureLogManagerInitialized();
         }
         return manager;
     }
@@ -295,6 +366,7 @@
 
                     try {
                         AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
+                                @Override
                                 public Void run() throws Exception {
                                     readConfiguration();
 
@@ -304,8 +376,7 @@
                                 }
                             });
                     } catch (Exception ex) {
-                        // System.err.println("Can't read logging configuration:");
-                        // ex.printStackTrace();
+                        assert false : "Exception raised while reading logging configuration: " + ex;
                     }
                 }
             }
@@ -391,6 +462,9 @@
         }
     }
 
+    // LoggerContext maps from AppContext
+    private WeakHashMap<Object, LoggerContext> contextsMap = null;
+
     // Returns the LoggerContext for the user code (i.e. application or AppContext).
     // Loggers are isolated from each AppContext.
     private LoggerContext getUserContext() {
@@ -399,39 +473,36 @@
         SecurityManager sm = System.getSecurityManager();
         JavaAWTAccess javaAwtAccess = SharedSecrets.getJavaAWTAccess();
         if (sm != null && javaAwtAccess != null) {
+            // for each applet, it has its own LoggerContext isolated from others
             synchronized (javaAwtAccess) {
-                // AppContext.getAppContext() returns the system AppContext if called
-                // from a system thread but Logger.getLogger might be called from
-                // an applet code. Instead, find the AppContext of the applet code
-                // from the execution stack.
-                Object ecx = javaAwtAccess.getExecutionContext();
-                if (ecx == null) {
-                    // fall back to thread group seach of AppContext
-                    ecx = javaAwtAccess.getContext();
-                }
+                // find the AppContext of the applet code
+                // will be null if we are in the main app context.
+                final Object ecx = javaAwtAccess.getAppletContext();
                 if (ecx != null) {
-                    context = (LoggerContext)javaAwtAccess.get(ecx, LoggerContext.class);
+                    if (contextsMap == null) {
+                        contextsMap = new WeakHashMap<>();
+                    }
+                    context = contextsMap.get(ecx);
                     if (context == null) {
-                        if (javaAwtAccess.isMainAppContext()) {
-                            context = userContext;
-                        } else {
-                            // Create a new LoggerContext for the applet.
-                            // The new logger context has its requiresDefaultLoggers
-                            // flag set to true - so that these loggers will be
-                            // lazily added when the context is firt accessed.
-                            context = new LoggerContext(true);
-                        }
-                        javaAwtAccess.put(ecx, LoggerContext.class, context);
+                        // Create a new LoggerContext for the applet.
+                        context = new LoggerContext();
+                        contextsMap.put(ecx, context);
                     }
                 }
             }
         }
+        // for standalone app, return userContext
         return context != null ? context : userContext;
     }
 
+    // The system context.
+    final LoggerContext getSystemContext() {
+        return systemContext;
+    }
+
     private List<LoggerContext> contexts() {
         List<LoggerContext> cxs = new ArrayList<>();
-        cxs.add(systemContext);
+        cxs.add(getSystemContext());
         cxs.add(getUserContext());
         return cxs;
     }
@@ -452,7 +523,7 @@
         Logger result = getLogger(name);
         if (result == null) {
             // only allocate the new logger once
-            Logger newLogger = new Logger(name, resourceBundleName, caller);
+            Logger newLogger = new Logger(name, resourceBundleName, caller, this);
             do {
                 if (addLogger(newLogger)) {
                     // We successfully added the new Logger that we
@@ -479,7 +550,7 @@
 
     Logger demandSystemLogger(String name, String resourceBundleName) {
         // Add a system logger in the system context's namespace
-        final Logger sysLogger = systemContext.demandLogger(name, resourceBundleName);
+        final Logger sysLogger = getSystemContext().demandLogger(name, resourceBundleName);
 
         // Add the system logger to the LogManager's namespace if not exist
         // so that there is only one single logger of the given name.
@@ -503,6 +574,7 @@
             // if logger already exists but handlers not set
             final Logger l = logger;
             AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                @Override
                 public Void run() {
                     for (Handler hdl : l.getHandlers()) {
                         sysLogger.addHandler(hdl);
@@ -521,24 +593,52 @@
     // doesn't exist in the user context, it'll also be added to the user context.
     // The user context is queried by the user code and all other loggers are
     // added in the user context.
-    static class LoggerContext {
+    class LoggerContext {
         // Table of named Loggers that maps names to Loggers.
         private final Hashtable<String,LoggerWeakRef> namedLoggers = new Hashtable<>();
         // Tree of named Loggers
         private final LogNode root;
-        private final boolean requiresDefaultLoggers;
         private LoggerContext() {
-            this(false);
+            this.root = new LogNode(null, this);
+        }
+
+
+        // Tells whether default loggers are required in this context.
+        // If true, the default loggers will be lazily added.
+        final boolean requiresDefaultLoggers() {
+            final boolean requiresDefaultLoggers = (getOwner() == manager);
+            if (requiresDefaultLoggers) {
+                getOwner().ensureLogManagerInitialized();
+            }
+            return requiresDefaultLoggers;
         }
-        private LoggerContext(boolean requiresDefaultLoggers) {
-            this.root = new LogNode(null, this);
-            this.requiresDefaultLoggers = requiresDefaultLoggers;
+
+        // This context's LogManager.
+        final LogManager getOwner() {
+            return LogManager.this;
+        }
+
+        // This context owner's root logger, which if not null, and if
+        // the context requires default loggers, will be added to the context
+        // logger's tree.
+        final Logger getRootLogger() {
+            return getOwner().rootLogger;
+        }
+
+        // The global logger, which if not null, and if
+        // the context requires default loggers, will be added to the context
+        // logger's tree.
+        final Logger getGlobalLogger() {
+            @SuppressWarnings("deprecated") // avoids initialization cycles.
+            final Logger global = Logger.global;
+            return global;
         }
 
         Logger demandLogger(String name, String resourceBundleName) {
             // a LogManager subclass may have its own implementation to add and
             // get a Logger.  So delegate to the LogManager to do the work.
-            return manager.demandLogger(name, resourceBundleName, null);
+            final LogManager owner = getOwner();
+            return owner.demandLogger(name, resourceBundleName, null);
         }
 
 
@@ -550,10 +650,10 @@
         // or getLoggerNames()
         //
         private void ensureInitialized() {
-            if (requiresDefaultLoggers) {
+            if (requiresDefaultLoggers()) {
                 // Ensure that the root and global loggers are set.
-                ensureDefaultLogger(manager.rootLogger);
-                ensureDefaultLogger(Logger.global);
+                ensureDefaultLogger(getRootLogger());
+                ensureDefaultLogger(getGlobalLogger());
             }
         }
 
@@ -582,13 +682,13 @@
         // before adding 'logger'.
         //
         private void ensureAllDefaultLoggers(Logger logger) {
-            if (requiresDefaultLoggers) {
+            if (requiresDefaultLoggers()) {
                 final String name = logger.getName();
                 if (!name.isEmpty()) {
-                    ensureDefaultLogger(manager.rootLogger);
-                }
-                if (!Logger.GLOBAL_LOGGER_NAME.equals(name)) {
-                    ensureDefaultLogger(Logger.global);
+                    ensureDefaultLogger(getRootLogger());
+                    if (!Logger.GLOBAL_LOGGER_NAME.equals(name)) {
+                        ensureDefaultLogger(getGlobalLogger());
+                    }
                 }
             }
         }
@@ -600,8 +700,8 @@
             // This check is simple sanity: we do not want that this
             // method be called for anything else than Logger.global
             // or owner.rootLogger.
-            if (!requiresDefaultLoggers || logger == null
-                    || logger != Logger.global && logger != manager.rootLogger) {
+            if (!requiresDefaultLoggers() || logger == null
+                    || logger != Logger.global && logger != LogManager.this.rootLogger) {
 
                 // the case where we have a non null logger which is neither
                 // Logger.global nor manager.rootLogger indicates a serious
@@ -627,7 +727,7 @@
 
         boolean addLocalLogger(Logger logger) {
             // no need to add default loggers if it's not required
-            return addLocalLogger(logger, requiresDefaultLoggers);
+            return addLocalLogger(logger, requiresDefaultLoggers());
         }
 
         // Add a logger to this context.  This method will only set its level
@@ -665,11 +765,13 @@
 
             // We're adding a new logger.
             // Note that we are creating a weak reference here.
-            ref = manager.new LoggerWeakRef(logger);
+            final LogManager owner = getOwner();
+            logger.setLogManager(owner);
+            ref = owner.new LoggerWeakRef(logger);
             namedLoggers.put(name, ref);
 
             // Apply any initial level defined for the new logger.
-            Level level = manager.getLevelProperty(name + ".level", null);
+            Level level = owner.getLevelProperty(name + ".level", null);
             if (level != null) {
                 doSetLevel(logger, level);
             }
@@ -721,10 +823,12 @@
         // If logger.getUseParentHandlers() returns 'true' and any of the logger's
         // parents have levels or handlers defined, make sure they are instantiated.
         private void processParentHandlers(final Logger logger, final String name) {
+            final LogManager owner = getOwner();
             AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                @Override
                 public Void run() {
-                    if (logger != manager.rootLogger) {
-                        boolean useParent = manager.getBooleanProperty(name + ".useParentHandlers", true);
+                    if (logger != owner.rootLogger) {
+                        boolean useParent = owner.getBooleanProperty(name + ".useParentHandlers", true);
                         if (!useParent) {
                             logger.setUseParentHandlers(false);
                         }
@@ -740,8 +844,8 @@
                     break;
                 }
                 String pname = name.substring(0, ix2);
-                if (manager.getProperty(pname + ".level") != null ||
-                    manager.getProperty(pname + ".handlers") != null) {
+                if (owner.getProperty(pname + ".level") != null ||
+                    owner.getProperty(pname + ".handlers") != null) {
                     // This pname has a level/handlers definition.
                     // Make sure it exists.
                     demandLogger(pname, null);
@@ -781,16 +885,17 @@
         }
     }
 
-    static class SystemLoggerContext extends LoggerContext {
+    final class SystemLoggerContext extends LoggerContext {
         // Add a system logger in the system context's namespace as well as
         // in the LogManager's namespace if not exist so that there is only
         // one single logger of the given name.  System loggers are visible
         // to applications unless a logger of the same name has been added.
+        @Override
         Logger demandLogger(String name, String resourceBundleName) {
             Logger result = findLogger(name);
             if (result == null) {
                 // only allocate the new system logger once
-                Logger newLogger = new Logger(name, resourceBundleName);
+                Logger newLogger = new Logger(name, resourceBundleName, null, getOwner());
                 do {
                     if (addLocalLogger(newLogger)) {
                         // We successfully added the new Logger that we
@@ -824,6 +929,7 @@
                                     final String handlersPropertyName)
     {
         AccessController.doPrivileged(new PrivilegedAction<Object>() {
+            @Override
             public Object run() {
                 String names[] = parseClassNames(handlersPropertyName);
                 for (int i = 0; i < names.length; i++) {
@@ -1016,6 +1122,7 @@
         // There is a security manager.  Raise privilege before
         // calling setLevel.
         AccessController.doPrivileged(new PrivilegedAction<Object>() {
+            @Override
             public Object run() {
                 logger.setLevel(level);
                 return null;
@@ -1034,6 +1141,7 @@
         // There is a security manager.  Raise privilege before
         // calling setParent.
         AccessController.doPrivileged(new PrivilegedAction<Object>() {
+            @Override
             public Object run() {
                 logger.setParent(parent);
                 return null;
@@ -1131,14 +1239,9 @@
             f = new File(f, "logging.properties");
             fname = f.getCanonicalPath();
         }
-        InputStream in = new FileInputStream(fname);
-        BufferedInputStream bin = new BufferedInputStream(in);
-        try {
+        try (final InputStream in = new FileInputStream(fname)) {
+            final BufferedInputStream bin = new BufferedInputStream(in);
             readConfiguration(bin);
-        } finally {
-            if (in != null) {
-                in.close();
-            }
         }
     }
 
@@ -1203,7 +1306,7 @@
         }
         hands = hands.trim();
         int ix = 0;
-        Vector<String> result = new Vector<>();
+        final List<String> result = new ArrayList<>();
         while (ix < hands.length()) {
             int end = ix;
             while (end < hands.length()) {
@@ -1473,28 +1576,35 @@
     // We use a subclass of Logger for the root logger, so
     // that we only instantiate the global handlers when they
     // are first needed.
-    private class RootLogger extends Logger {
+    private final class RootLogger extends Logger {
         private RootLogger() {
-            super("", null);
+            // We do not call the protected Logger two args constructor here,
+            // to avoid calling LogManager.getLogManager() from within the
+            // RootLogger constructor.
+            super("", null, null, LogManager.this);
             setLevel(defaultLevel);
         }
 
+        @Override
         public void log(LogRecord record) {
             // Make sure that the global handlers have been instantiated.
             initializeGlobalHandlers();
             super.log(record);
         }
 
+        @Override
         public void addHandler(Handler h) {
             initializeGlobalHandlers();
             super.addHandler(h);
         }
 
+        @Override
         public void removeHandler(Handler h) {
             initializeGlobalHandlers();
             super.removeHandler(h);
         }
 
+        @Override
         public Handler[] getHandlers() {
             initializeGlobalHandlers();
             return super.getHandlers();
--- a/jdk/src/share/classes/java/util/logging/Logger.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/logging/Logger.java	Wed Jul 05 19:11:53 2017 +0200
@@ -245,14 +245,26 @@
         // In order to finish the initialization of the global logger, we
         // will therefore call LogManager.getLogManager() here.
         //
-        // Care must be taken *not* to call Logger.getGlobal() in
-        // LogManager static initializers in order to avoid such
-        // deadlocks.
-        //
-        if (global != null && global.manager == null) {
-            // Complete initialization of the global Logger.
-            global.manager = LogManager.getLogManager();
-        }
+        // To prevent race conditions we also need to call
+        // LogManager.getLogManager() unconditionally here.
+        // Indeed we cannot rely on the observed value of global.manager,
+        // because global.manager will become not null somewhere during
+        // the initialization of LogManager.
+        // If two threads are calling getGlobal() concurrently, one thread
+        // will see global.manager null and call LogManager.getLogManager(),
+        // but the other thread could come in at a time when global.manager
+        // is already set although ensureLogManagerInitialized is not finished
+        // yet...
+        // Calling LogManager.getLogManager() unconditionally will fix that.
+
+        LogManager.getLogManager();
+
+        // Now the global LogManager should be initialized,
+        // and the global logger should have been added to
+        // it, unless we were called within the constructor of a LogManager
+        // subclass installed as LogManager, in which case global.manager
+        // would still be null, and global will be lazily initialized later on.
+
         return global;
     }
 
@@ -298,11 +310,11 @@
      *             no corresponding resource can be found.
      */
     protected Logger(String name, String resourceBundleName) {
-        this(name, resourceBundleName, null);
+        this(name, resourceBundleName, null, LogManager.getLogManager());
     }
 
-    Logger(String name, String resourceBundleName, Class<?> caller) {
-        this.manager = LogManager.getLogManager();
+    Logger(String name, String resourceBundleName, Class<?> caller, LogManager manager) {
+        this.manager = manager;
         setupResourceInfo(resourceBundleName, caller);
         this.name = name;
         levelValue = Level.INFO.intValue();
@@ -332,8 +344,8 @@
         levelValue = Level.INFO.intValue();
     }
 
-    // It is called from the LogManager.<clinit> to complete
-    // initialization of the global Logger.
+    // It is called from LoggerContext.addLocalLogger() when the logger
+    // is actually added to a LogManager.
     void setLogManager(LogManager manager) {
         this.manager = manager;
     }
@@ -558,7 +570,7 @@
         // cleanup some Loggers that have been GC'ed
         manager.drainLoggerRefQueueBounded();
         Logger result = new Logger(null, resourceBundleName,
-                                   Reflection.getCallerClass());
+                                   Reflection.getCallerClass(), manager);
         result.anonymous = true;
         Logger root = manager.getLogger("");
         result.doSetParent(root);
@@ -623,7 +635,7 @@
      * @param record the LogRecord to be published
      */
     public void log(LogRecord record) {
-        if (record.getLevel().intValue() < levelValue || levelValue == offValue) {
+        if (!isLoggable(record.getLevel())) {
             return;
         }
         Filter theFilter = filter;
@@ -677,7 +689,7 @@
      * @param   msg     The string message (or a key in the message catalog)
      */
     public void log(Level level, String msg) {
-        if (level.intValue() < levelValue || levelValue == offValue) {
+        if (!isLoggable(level)) {
             return;
         }
         LogRecord lr = new LogRecord(level, msg);
@@ -698,7 +710,7 @@
      *                        desired log message
      */
     public void log(Level level, Supplier<String> msgSupplier) {
-        if (level.intValue() < levelValue || levelValue == offValue) {
+        if (!isLoggable(level)) {
             return;
         }
         LogRecord lr = new LogRecord(level, msgSupplier.get());
@@ -717,7 +729,7 @@
      * @param   param1  parameter to the message
      */
     public void log(Level level, String msg, Object param1) {
-        if (level.intValue() < levelValue || levelValue == offValue) {
+        if (!isLoggable(level)) {
             return;
         }
         LogRecord lr = new LogRecord(level, msg);
@@ -738,7 +750,7 @@
      * @param   params  array of parameters to the message
      */
     public void log(Level level, String msg, Object params[]) {
-        if (level.intValue() < levelValue || levelValue == offValue) {
+        if (!isLoggable(level)) {
             return;
         }
         LogRecord lr = new LogRecord(level, msg);
@@ -763,7 +775,7 @@
      * @param   thrown  Throwable associated with log message.
      */
     public void log(Level level, String msg, Throwable thrown) {
-        if (level.intValue() < levelValue || levelValue == offValue) {
+        if (!isLoggable(level)) {
             return;
         }
         LogRecord lr = new LogRecord(level, msg);
@@ -791,7 +803,7 @@
      * @since   1.8
      */
     public void log(Level level, Throwable thrown, Supplier<String> msgSupplier) {
-        if (level.intValue() < levelValue || levelValue == offValue) {
+        if (!isLoggable(level)) {
             return;
         }
         LogRecord lr = new LogRecord(level, msgSupplier.get());
@@ -817,7 +829,7 @@
      * @param   msg     The string message (or a key in the message catalog)
      */
     public void logp(Level level, String sourceClass, String sourceMethod, String msg) {
-        if (level.intValue() < levelValue || levelValue == offValue) {
+        if (!isLoggable(level)) {
             return;
         }
         LogRecord lr = new LogRecord(level, msg);
@@ -844,7 +856,7 @@
      */
     public void logp(Level level, String sourceClass, String sourceMethod,
                      Supplier<String> msgSupplier) {
-        if (level.intValue() < levelValue || levelValue == offValue) {
+        if (!isLoggable(level)) {
             return;
         }
         LogRecord lr = new LogRecord(level, msgSupplier.get());
@@ -869,7 +881,7 @@
      */
     public void logp(Level level, String sourceClass, String sourceMethod,
                                                 String msg, Object param1) {
-        if (level.intValue() < levelValue || levelValue == offValue) {
+        if (!isLoggable(level)) {
             return;
         }
         LogRecord lr = new LogRecord(level, msg);
@@ -896,7 +908,7 @@
      */
     public void logp(Level level, String sourceClass, String sourceMethod,
                                                 String msg, Object params[]) {
-        if (level.intValue() < levelValue || levelValue == offValue) {
+        if (!isLoggable(level)) {
             return;
         }
         LogRecord lr = new LogRecord(level, msg);
@@ -927,7 +939,7 @@
      */
     public void logp(Level level, String sourceClass, String sourceMethod,
                      String msg, Throwable thrown) {
-        if (level.intValue() < levelValue || levelValue == offValue) {
+        if (!isLoggable(level)) {
             return;
         }
         LogRecord lr = new LogRecord(level, msg);
@@ -961,7 +973,7 @@
      */
     public void logp(Level level, String sourceClass, String sourceMethod,
                      Throwable thrown, Supplier<String> msgSupplier) {
-        if (level.intValue() < levelValue || levelValue == offValue) {
+        if (!isLoggable(level)) {
             return;
         }
         LogRecord lr = new LogRecord(level, msgSupplier.get());
@@ -1009,7 +1021,7 @@
      */
     public void logrb(Level level, String sourceClass, String sourceMethod,
                                 String bundleName, String msg) {
-        if (level.intValue() < levelValue || levelValue == offValue) {
+        if (!isLoggable(level)) {
             return;
         }
         LogRecord lr = new LogRecord(level, msg);
@@ -1040,7 +1052,7 @@
      */
     public void logrb(Level level, String sourceClass, String sourceMethod,
                                 String bundleName, String msg, Object param1) {
-        if (level.intValue() < levelValue || levelValue == offValue) {
+        if (!isLoggable(level)) {
             return;
         }
         LogRecord lr = new LogRecord(level, msg);
@@ -1073,7 +1085,7 @@
      */
     public void logrb(Level level, String sourceClass, String sourceMethod,
                                 String bundleName, String msg, Object params[]) {
-        if (level.intValue() < levelValue || levelValue == offValue) {
+        if (!isLoggable(level)) {
             return;
         }
         LogRecord lr = new LogRecord(level, msg);
@@ -1110,7 +1122,7 @@
      */
     public void logrb(Level level, String sourceClass, String sourceMethod,
                                         String bundleName, String msg, Throwable thrown) {
-        if (level.intValue() < levelValue || levelValue == offValue) {
+        if (!isLoggable(level)) {
             return;
         }
         LogRecord lr = new LogRecord(level, msg);
@@ -1136,9 +1148,6 @@
      * @param   sourceMethod   name of method that is being entered
      */
     public void entering(String sourceClass, String sourceMethod) {
-        if (Level.FINER.intValue() < levelValue) {
-            return;
-        }
         logp(Level.FINER, sourceClass, sourceMethod, "ENTRY");
     }
 
@@ -1155,11 +1164,7 @@
      * @param   param1         parameter to the method being entered
      */
     public void entering(String sourceClass, String sourceMethod, Object param1) {
-        if (Level.FINER.intValue() < levelValue) {
-            return;
-        }
-        Object params[] = { param1 };
-        logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", params);
+        logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", param1);
     }
 
     /**
@@ -1176,14 +1181,12 @@
      * @param   params         array of parameters to the method being entered
      */
     public void entering(String sourceClass, String sourceMethod, Object params[]) {
-        if (Level.FINER.intValue() < levelValue) {
-            return;
-        }
         String msg = "ENTRY";
         if (params == null ) {
            logp(Level.FINER, sourceClass, sourceMethod, msg);
            return;
         }
+        if (!isLoggable(Level.FINER)) return;
         for (int i = 0; i < params.length; i++) {
             msg = msg + " {" + i + "}";
         }
@@ -1201,9 +1204,6 @@
      * @param   sourceMethod   name of the method
      */
     public void exiting(String sourceClass, String sourceMethod) {
-        if (Level.FINER.intValue() < levelValue) {
-            return;
-        }
         logp(Level.FINER, sourceClass, sourceMethod, "RETURN");
     }
 
@@ -1221,10 +1221,6 @@
      * @param   result  Object that is being returned
      */
     public void exiting(String sourceClass, String sourceMethod, Object result) {
-        if (Level.FINER.intValue() < levelValue) {
-            return;
-        }
-        Object params[] = { result };
         logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result);
     }
 
@@ -1250,7 +1246,7 @@
      * @param   thrown  The Throwable that is being thrown.
      */
     public void throwing(String sourceClass, String sourceMethod, Throwable thrown) {
-        if (Level.FINER.intValue() < levelValue || levelValue == offValue ) {
+        if (!isLoggable(Level.FINER)) {
             return;
         }
         LogRecord lr = new LogRecord(Level.FINER, "THROW");
@@ -1274,9 +1270,6 @@
      * @param   msg     The string message (or a key in the message catalog)
      */
     public void severe(String msg) {
-        if (Level.SEVERE.intValue() < levelValue) {
-            return;
-        }
         log(Level.SEVERE, msg);
     }
 
@@ -1290,9 +1283,6 @@
      * @param   msg     The string message (or a key in the message catalog)
      */
     public void warning(String msg) {
-        if (Level.WARNING.intValue() < levelValue) {
-            return;
-        }
         log(Level.WARNING, msg);
     }
 
@@ -1306,9 +1296,6 @@
      * @param   msg     The string message (or a key in the message catalog)
      */
     public void info(String msg) {
-        if (Level.INFO.intValue() < levelValue) {
-            return;
-        }
         log(Level.INFO, msg);
     }
 
@@ -1322,9 +1309,6 @@
      * @param   msg     The string message (or a key in the message catalog)
      */
     public void config(String msg) {
-        if (Level.CONFIG.intValue() < levelValue) {
-            return;
-        }
         log(Level.CONFIG, msg);
     }
 
@@ -1338,9 +1322,6 @@
      * @param   msg     The string message (or a key in the message catalog)
      */
     public void fine(String msg) {
-        if (Level.FINE.intValue() < levelValue) {
-            return;
-        }
         log(Level.FINE, msg);
     }
 
@@ -1354,9 +1335,6 @@
      * @param   msg     The string message (or a key in the message catalog)
      */
     public void finer(String msg) {
-        if (Level.FINER.intValue() < levelValue) {
-            return;
-        }
         log(Level.FINER, msg);
     }
 
@@ -1370,9 +1348,6 @@
      * @param   msg     The string message (or a key in the message catalog)
      */
     public void finest(String msg) {
-        if (Level.FINEST.intValue() < levelValue) {
-            return;
-        }
         log(Level.FINEST, msg);
     }
 
@@ -1798,7 +1773,7 @@
         if (parent == null) {
             throw new NullPointerException();
         }
-        manager.checkPermission();
+        checkPermission();
         doSetParent(parent);
     }
 
--- a/jdk/src/share/classes/java/util/logging/MemoryHandler.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/logging/MemoryHandler.java	Wed Jul 05 19:11:53 2017 +0200
@@ -88,7 +88,7 @@
 
 public class MemoryHandler extends Handler {
     private final static int DEFAULT_SIZE = 1000;
-    private Level pushLevel;
+    private volatile Level pushLevel;
     private int size;
     private Handler target;
     private LogRecord buffer[];
@@ -188,6 +188,7 @@
      * @param  record  description of the log event. A null record is
      *                 silently ignored and is not published
      */
+    @Override
     public synchronized void publish(LogRecord record) {
         if (!isLoggable(record)) {
             return;
@@ -227,6 +228,7 @@
      * Note that the current contents of the <tt>MemoryHandler</tt>
      * buffer are <b>not</b> written out.  That requires a "push".
      */
+    @Override
     public void flush() {
         target.flush();
     }
@@ -238,6 +240,7 @@
      * @exception  SecurityException  if a security manager exists and if
      *             the caller does not have <tt>LoggingPermission("control")</tt>.
      */
+    @Override
     public void close() throws SecurityException {
         target.close();
         setLevel(Level.OFF);
@@ -252,11 +255,10 @@
      * @exception  SecurityException  if a security manager exists and if
      *             the caller does not have <tt>LoggingPermission("control")</tt>.
      */
-    public void setPushLevel(Level newLevel) throws SecurityException {
+    public synchronized void setPushLevel(Level newLevel) throws SecurityException {
         if (newLevel == null) {
             throw new NullPointerException();
         }
-        LogManager manager = LogManager.getLogManager();
         checkPermission();
         pushLevel = newLevel;
     }
@@ -266,7 +268,7 @@
      *
      * @return the value of the <tt>pushLevel</tt>
      */
-    public synchronized Level getPushLevel() {
+    public Level getPushLevel() {
         return pushLevel;
     }
 
@@ -283,6 +285,7 @@
      * @return true if the <tt>LogRecord</tt> would be logged.
      *
      */
+    @Override
     public boolean isLoggable(LogRecord record) {
         return super.isLoggable(record);
     }
--- a/jdk/src/share/classes/java/util/logging/SocketHandler.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/logging/SocketHandler.java	Wed Jul 05 19:11:53 2017 +0200
@@ -82,7 +82,6 @@
     private Socket sock;
     private String host;
     private int port;
-    private String portProperty;
 
     // Private method to configure a SocketHandler from LogManager
     // properties and/or default values as specified in the class
@@ -177,6 +176,7 @@
      * @exception  SecurityException  if a security manager exists and if
      *             the caller does not have <tt>LoggingPermission("control")</tt>.
      */
+    @Override
     public synchronized void close() throws SecurityException {
         super.close();
         if (sock != null) {
@@ -195,6 +195,7 @@
      * @param  record  description of the log event. A null record is
      *                 silently ignored and is not published
      */
+    @Override
     public synchronized void publish(LogRecord record) {
         if (!isLoggable(record)) {
             return;
--- a/jdk/src/share/classes/java/util/logging/StreamHandler.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/logging/StreamHandler.java	Wed Jul 05 19:11:53 2017 +0200
@@ -73,10 +73,9 @@
  */
 
 public class StreamHandler extends Handler {
-    private LogManager manager = LogManager.getLogManager();
     private OutputStream output;
     private boolean doneHeader;
-    private Writer writer;
+    private volatile Writer writer;
 
     // Private method to configure a StreamHandler from LogManager
     // properties and/or default values as specified in the class
@@ -169,7 +168,8 @@
      * @exception  UnsupportedEncodingException if the named encoding is
      *          not supported.
      */
-    public void setEncoding(String encoding)
+    @Override
+    public synchronized void setEncoding(String encoding)
                         throws SecurityException, java.io.UnsupportedEncodingException {
         super.setEncoding(encoding);
         if (output == null) {
@@ -201,6 +201,7 @@
      * @param  record  description of the log event. A null record is
      *                 silently ignored and is not published
      */
+    @Override
     public synchronized void publish(LogRecord record) {
         if (!isLoggable(record)) {
             return;
@@ -240,6 +241,7 @@
      * @return true if the <tt>LogRecord</tt> would be logged.
      *
      */
+    @Override
     public boolean isLoggable(LogRecord record) {
         if (writer == null || record == null) {
             return false;
@@ -250,6 +252,7 @@
     /**
      * Flush any buffered messages.
      */
+    @Override
     public synchronized void flush() {
         if (writer != null) {
             try {
@@ -294,6 +297,7 @@
      * @exception  SecurityException  if a security manager exists and if
      *             the caller does not have LoggingPermission("control").
      */
+    @Override
     public synchronized void close() throws SecurityException {
         flushAndClose();
     }
--- a/jdk/src/share/classes/java/util/stream/AbstractPipeline.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/stream/AbstractPipeline.java	Wed Jul 05 19:11:53 2017 +0200
@@ -71,6 +71,9 @@
  */
 abstract class AbstractPipeline<E_IN, E_OUT, S extends BaseStream<E_OUT, S>>
         extends PipelineHelper<E_OUT> implements BaseStream<E_OUT, S> {
+    private static final String MSG_STREAM_LINKED = "stream has already been operated upon or closed";
+    private static final String MSG_CONSUMED = "source already consumed or closed";
+
     /**
      * Backlink to the head of the pipeline chain (self if this is the source
      * stage).
@@ -137,6 +140,8 @@
      */
     private boolean sourceAnyStateful;
 
+    private Runnable sourceCloseAction;
+
     /**
      * True if pipeline is parallel, otherwise the pipeline is sequential; only
      * valid for the source stage.
@@ -195,7 +200,7 @@
      */
     AbstractPipeline(AbstractPipeline<?, E_IN, ?> previousStage, int opFlags) {
         if (previousStage.linkedOrConsumed)
-            throw new IllegalStateException("stream has already been operated upon");
+            throw new IllegalStateException(MSG_STREAM_LINKED);
         previousStage.linkedOrConsumed = true;
         previousStage.nextStage = this;
 
@@ -221,7 +226,7 @@
     final <R> R evaluate(TerminalOp<E_OUT, R> terminalOp) {
         assert getOutputShape() == terminalOp.inputShape();
         if (linkedOrConsumed)
-            throw new IllegalStateException("stream has already been operated upon");
+            throw new IllegalStateException(MSG_STREAM_LINKED);
         linkedOrConsumed = true;
 
         return isParallel()
@@ -238,7 +243,7 @@
     @SuppressWarnings("unchecked")
     final Node<E_OUT> evaluateToArrayNode(IntFunction<E_OUT[]> generator) {
         if (linkedOrConsumed)
-            throw new IllegalStateException("stream has already been operated upon");
+            throw new IllegalStateException(MSG_STREAM_LINKED);
         linkedOrConsumed = true;
 
         // If the last intermediate operation is stateful then
@@ -266,7 +271,7 @@
             throw new IllegalStateException();
 
         if (linkedOrConsumed)
-            throw new IllegalStateException("stream has already been operated upon");
+            throw new IllegalStateException(MSG_STREAM_LINKED);
         linkedOrConsumed = true;
 
         if (sourceStage.sourceSpliterator != null) {
@@ -282,7 +287,7 @@
             return s;
         }
         else {
-            throw new IllegalStateException("source already consumed");
+            throw new IllegalStateException(MSG_CONSUMED);
         }
     }
 
@@ -302,12 +307,35 @@
         return (S) this;
     }
 
+    @Override
+    public void close() {
+        linkedOrConsumed = true;
+        sourceSupplier = null;
+        sourceSpliterator = null;
+        if (sourceStage.sourceCloseAction != null) {
+            Runnable closeAction = sourceStage.sourceCloseAction;
+            sourceStage.sourceCloseAction = null;
+            closeAction.run();
+        }
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public S onClose(Runnable closeHandler) {
+        Runnable existingHandler = sourceStage.sourceCloseAction;
+        sourceStage.sourceCloseAction =
+                (existingHandler == null)
+                ? closeHandler
+                : Streams.composeWithExceptions(existingHandler, closeHandler);
+        return (S) this;
+    }
+
     // Primitive specialization use co-variant overrides, hence is not final
     @Override
     @SuppressWarnings("unchecked")
     public Spliterator<E_OUT> spliterator() {
         if (linkedOrConsumed)
-            throw new IllegalStateException("stream has already been operated upon");
+            throw new IllegalStateException(MSG_STREAM_LINKED);
         linkedOrConsumed = true;
 
         if (this == sourceStage) {
@@ -324,7 +352,7 @@
                 return lazySpliterator(s);
             }
             else {
-                throw new IllegalStateException("source already consumed");
+                throw new IllegalStateException(MSG_CONSUMED);
             }
         }
         else {
@@ -424,7 +452,7 @@
             sourceStage.sourceSupplier = null;
         }
         else {
-            throw new IllegalStateException("source already consumed");
+            throw new IllegalStateException(MSG_CONSUMED);
         }
 
         if (isParallel()) {
--- a/jdk/src/share/classes/java/util/stream/BaseStream.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/stream/BaseStream.java	Wed Jul 05 19:11:53 2017 +0200
@@ -24,18 +24,106 @@
  */
 package java.util.stream;
 
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collection;
 import java.util.Iterator;
 import java.util.Spliterator;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.IntConsumer;
+import java.util.function.Predicate;
 
 /**
- * Base interface for stream types such as {@link Stream}, {@link IntStream},
- * etc.  Contains methods common to all stream types.
+ * A sequence of elements supporting sequential and parallel aggregate
+ * operations.  The following example illustrates an aggregate operation using
+ * {@link Stream} and {@link IntStream}:
+ *
+ * <pre>{@code
+ *     int sum = widgets.stream()
+ *                      .filter(w -> w.getColor() == RED)
+ *                      .mapToInt(w -> w.getWeight())
+ *                      .sum();
+ * }</pre>
+ *
+ * In this example, {@code widgets} is a {@code Collection<Widget>}.  We create
+ * a stream of {@code Widget} objects via {@link Collection#stream Collection.stream()},
+ * filter it to produce a stream containing only the red widgets, and then
+ * transform it into a stream of {@code int} values representing the weight of
+ * each red widget. Then this stream is summed to produce a total weight.
+ *
+ * <p>To perform a computation, stream
+ * <a href="package-summary.html#StreamOps">operations</a> are composed into a
+ * <em>stream pipeline</em>.  A stream pipeline consists of a source (which
+ * might be an array, a collection, a generator function, an IO channel,
+ * etc), zero or more <em>intermediate operations</em> (which transform a
+ * stream into another stream, such as {@link Stream#filter(Predicate)}), and a
+ * <em>terminal operation</em> (which produces a result or side-effect, such
+ * as {@link IntStream#sum()} or {@link IntStream#forEach(IntConsumer)}).
+ * Streams are lazy; computation on the source data is only performed when the
+ * terminal operation is initiated, and source elements are consumed only
+ * as needed.
+ *
+ * <p>Collections and streams, while bearing some superficial similarities,
+ * have different goals.  Collections are primarily concerned with the efficient
+ * management of, and access to, their elements.  By contrast, streams do not
+ * provide a means to directly access or manipulate their elements, and are
+ * instead concerned with declaratively describing their source and the
+ * computational operations which will be performed in aggregate on that source.
+ * However, if the provided stream operations do not offer the desired
+ * functionality, the {@link #iterator()} and {@link #spliterator()} operations
+ * can be used to perform a controlled traversal.
+ *
+ * <p>A stream pipeline, like the "widgets" example above, can be viewed as
+ * a <em>query</em> on the stream source.  Unless the source was explicitly
+ * designed for concurrent modification (such as a {@link ConcurrentHashMap}),
+ * unpredictable or erroneous behavior may result from modifying the stream
+ * source while it is being queried.
  *
- * @param <T> type of stream elements
- * @param <S> type of stream implementing {@code BaseStream}
+ * <p>Most stream operations accept parameters that describe user-specified
+ * behavior, such as the lambda expression {@code w -> w.getWeight()} passed to
+ * {@code mapToInt} in the example above.  Such parameters are always instances
+ * of a <a href="../function/package-summary.html">functional interface</a> such
+ * as {@link java.util.function.Function}, and are often lambda expressions or
+ * method references.  These parameters can never be null, should not modify the
+ * stream source, and should be
+ * <a href="package-summary.html#NonInterference">effectively stateless</a>
+ * (their result should not depend on any state that might change during
+ * execution of the stream pipeline.)
+ *
+ * <p>A stream should be operated on (invoking an intermediate or terminal stream
+ * operation) only once.  This rules out, for example, "forked" streams, where
+ * the same source feeds two or more pipelines, or multiple traversals of the
+ * same stream.  A stream implementation may throw {@link IllegalStateException}
+ * if it detects that the stream is being reused. However, since some stream
+ * operations may return their receiver rather than a new stream object, it may
+ * not be possible to detect reuse in all cases.
+ *
+ * <p>Streams have a {@link #close()} method and implement {@link AutoCloseable},
+ * but nearly all stream instances do not actually need to be closed after use.
+ * Generally, only streams whose source is an IO channel (such as those returned
+ * by {@link Files#lines(Path, Charset)}) will require closing.  Most streams
+ * are backed by collections, arrays, or generating functions, which require no
+ * special resource management.  (If a stream does require closing, it can be
+ * declared as a resource in a {@code try}-with-resources statement.)
+ *
+ * <p>Stream pipelines may execute either sequentially or in
+ * <a href="package-summary.html#Parallelism">parallel</a>.  This
+ * execution mode is a property of the stream.  Streams are created
+ * with an initial choice of sequential or parallel execution.  (For example,
+ * {@link Collection#stream() Collection.stream()} creates a sequential stream,
+ * and {@link Collection#parallelStream() Collection.parallelStream()} creates
+ * a parallel one.)  This choice of execution mode may be modified by the
+ * {@link #sequential()} or {@link #parallel()} methods, and may be queried with
+ * the {@link #isParallel()} method.
+ *
+ * @param <T> the type of the stream elements
+ * @param <S> the type of of the stream implementing {@code BaseStream}
  * @since 1.8
+ * @see <a href="package-summary.html">java.util.stream</a>
  */
-public interface BaseStream<T, S extends BaseStream<T, S>> {
+public interface BaseStream<T, S extends BaseStream<T, S>>
+        extends AutoCloseable {
     /**
      * Returns an iterator for the elements of this stream.
      *
@@ -57,14 +145,11 @@
     Spliterator<T> spliterator();
 
     /**
-     * Returns whether this stream, when executed, would execute in parallel
-     * (assuming no further modification of the stream, such as appending
-     * further intermediate operations or changing its parallelism).  Calling
-     * this method after invoking an intermediate or terminal stream operation
-     * method may yield unpredictable results.
+     * Returns whether this stream, if a terminal operation were to be executed,
+     * would execute in parallel.  Calling this method after invoking an
+     * terminal stream operation method may yield unpredictable results.
      *
      * @return {@code true} if this stream would execute in parallel if executed
-     * without further modification otherwise {@code false}
      */
     boolean isParallel();
 
@@ -95,7 +180,8 @@
     /**
      * Returns an equivalent stream that is
      * <a href="package-summary.html#Ordering">unordered</a>.  May return
-     * itself if the stream was already unordered.
+     * itself, either because the stream was already unordered, or because
+     * the underlying stream state was modified to be unordered.
      *
      * <p>This is an <a href="package-summary.html#StreamOps">intermediate
      * operation</a>.
@@ -103,4 +189,33 @@
      * @return an unordered stream
      */
     S unordered();
+
+    /**
+     * Returns an equivalent stream with an additional close handler.  Close
+     * handlers are run when the {@link #close()} method
+     * is called on the stream, and are executed in the order they were
+     * added.  All close handlers are run, even if earlier close handlers throw
+     * exceptions.  If any close handler throws an exception, the first
+     * exception thrown will be relayed to the caller of {@code close()}, with
+     * any remaining exceptions added to that exception as suppressed exceptions
+     * (unless one of the remaining exceptions is the same exception as the
+     * first exception, since an exception cannot suppress itself.)  May
+     * return itself.
+     *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
+     * @param closeHandler A task to execute when the stream is closed
+     * @return a stream with a handler that is run if the stream is closed
+     */
+    S onClose(Runnable closeHandler);
+
+    /**
+     * Closes this stream, causing all close handlers for this stream pipeline
+     * to be called.
+     *
+     * @see AutoCloseable#close()
+     */
+    @Override
+    void close();
 }
--- a/jdk/src/share/classes/java/util/stream/CloseableStream.java	Tue Sep 17 08:08:07 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package java.util.stream;
-
-/**
- * A {@code CloseableStream} is a {@code Stream} that can be closed.
- * The close method is invoked to release resources that the object is
- * holding (such as open files).
- *
- * @param <T> The type of stream elements
- * @since 1.8
- */
-public interface CloseableStream<T> extends Stream<T>, AutoCloseable {
-
-    /**
-     * Closes this resource, relinquishing any underlying resources.
-     * This method is invoked automatically on objects managed by the
-     * {@code try}-with-resources statement.  Does nothing if called when
-     * the resource has already been closed.
-     *
-     * This method does not allow throwing checked {@code Exception}s like
-     * {@link AutoCloseable#close() AutoCloseable.close()}. Cases where the
-     * close operation may fail require careful attention by implementers. It
-     * is strongly advised to relinquish the underlying resources and to
-     * internally <em>mark</em> the resource as closed. The {@code close}
-     * method is unlikely to be invoked more than once and so this ensures
-     * that the resources are released in a timely manner. Furthermore it
-     * reduces problems that could arise when the resource wraps, or is
-     * wrapped, by another resource.
-     *
-     * @see AutoCloseable#close()
-     */
-    void close();
-}
--- a/jdk/src/share/classes/java/util/stream/Collector.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/stream/Collector.java	Wed Jul 05 19:11:53 2017 +0200
@@ -26,6 +26,7 @@
 
 import java.util.Collections;
 import java.util.EnumSet;
+import java.util.Objects;
 import java.util.Set;
 import java.util.function.BiConsumer;
 import java.util.function.BinaryOperator;
@@ -33,71 +34,74 @@
 import java.util.function.Supplier;
 
 /**
- * A <a href="package-summary.html#Reduction">reduction operation</a> that
- * folds input elements into a mutable result container, optionally transforming
+ * A <a href="package-summary.html#Reduction">mutable reduction operation</a> that
+ * accumulates input elements into a mutable result container, optionally transforming
  * the accumulated result into a final representation after all input elements
- * have been processed.
+ * have been processed.  Reduction operations can be performed either sequentially
+ * or in parallel.
  *
  * <p>Examples of mutable reduction operations include:
  * accumulating elements into a {@code Collection}; concatenating
  * strings using a {@code StringBuilder}; computing summary information about
  * elements such as sum, min, max, or average; computing "pivot table" summaries
- * such as "maximum valued transaction by seller", etc.  Reduction operations
- * can be performed either sequentially or in parallel.
- *
- * <p>The following are examples of using the predefined {@code Collector}
- * implementations in {@link Collectors} with the {@code Stream} API to perform
- * mutable reduction tasks:
- * <pre>{@code
- *     // Accumulate names into a List
- *     List<String> list = people.stream().map(Person::getName).collect(Collectors.toList());
- *
- *     // Accumulate names into a TreeSet
- *     Set<String> list = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));
- *
- *     // Convert elements to strings and concatenate them, separated by commas
- *     String joined = things.stream()
- *                           .map(Object::toString)
- *                           .collect(Collectors.joining(", "));
- *
- *     // Find highest-paid employee
- *     Employee highestPaid = employees.stream()
- *                                     .collect(Collectors.maxBy(Comparators.comparing(Employee::getSalary)))
- *                                     .get();
- *
- *     // Group employees by department
- *     Map<Department, List<Employee>> byDept
- *         = employees.stream()
- *                    .collect(Collectors.groupingBy(Employee::getDepartment));
- *
- *     // Find highest-paid employee by department
- *     Map<Department, Optional<Employee>> highestPaidByDept
- *         = employees.stream()
- *                    .collect(Collectors.groupingBy(Employee::getDepartment,
- *                                                   Collectors.maxBy(Comparators.comparing(Employee::getSalary))));
- *
- *     // Partition students into passing and failing
- *     Map<Boolean, List<Student>> passingFailing =
- *         students.stream()
- *                 .collect(Collectors.partitioningBy(s -> s.getGrade() >= PASS_THRESHOLD));
- *
- * }</pre>
+ * such as "maximum valued transaction by seller", etc.  The class {@link Collectors}
+ * provides implementations of many common mutable reductions.
  *
  * <p>A {@code Collector} is specified by four functions that work together to
  * accumulate entries into a mutable result container, and optionally perform
- * a final transform on the result.  They are: creation of a new result container,
- * incorporating a new data element into a result container, combining two
- * result containers into one, and performing a final transform on the container.
- * The combiner function is used during parallel operations, where
- * subsets of the input are accumulated into separate result
- * containers, and then the subresults merged into a combined result.  The
- * combiner function may merge one set of subresults into the other and return
- * that, or it may return a new object to describe the combined results.
+ * a final transform on the result.  They are: <ul>
+ *     <li>creation of a new result container ({@link #supplier()})</li>
+ *     <li>incorporating a new data element into a result container ({@link #accumulator()})</li>
+ *     <li>combining two result containers into one ({@link #combiner()})</li>
+ *     <li>performing an optional final transform on the container ({@link #finisher()})</li>
+ * </ul>
  *
  * <p>Collectors also have a set of characteristics, such as
- * {@link Characteristics#CONCURRENT}.  These characteristics provide
- * hints that can be used by a reduction implementation to provide better
- * performance.
+ * {@link Characteristics#CONCURRENT}, that provide hints that can be used by a
+ * reduction implementation to provide better performance.
+ *
+ * <p>A sequential implementation of a reduction using a collector would
+ * create a single result container using the supplier function, and invoke the
+ * accumulator function once for each input element.  A parallel implementation
+ * would partition the input, create a result container for each partition,
+ * accumulate the contents of each partition into a subresult for that partition,
+ * and then use the combiner function to merge the subresults into a combined
+ * result.
+ *
+ * <p>To ensure that sequential and parallel executions produce equivalent
+ * results, the collector functions must satisfy an <em>identity</em> and an
+ * <a href="package-summary.html#Associativity">associativity</a> constraints.
+ *
+ * <p>The identity constraint says that for any partially accumulated result,
+ * combining it with an empty result container must produce an equivalent
+ * result.  That is, for a partially accumulated result {@code a} that is the
+ * result of any series of accumulator and combiner invocations, {@code a} must
+ * be equivalent to {@code combiner.apply(a, supplier.get())}.
+ *
+ * <p>The associativity constraint says that splitting the computation must
+ * produce an equivalent result.  That is, for any input elements {@code t1}
+ * and {@code t2}, the results {@code r1} and {@code r2} in the computation
+ * below must be equivalent:
+ * <pre>{@code
+ *     A a1 = supplier.get();
+ *     accumulator.accept(a1, t1);
+ *     accumulator.accept(a1, t2);
+ *     R r1 = finisher.apply(a1);  // result without splitting
+ *
+ *     A a2 = supplier.get();
+ *     accumulator.accept(a2, t1);
+ *     A a3 = supplier.get();
+ *     accumulator.accept(a3, t2);
+ *     R r2 = finisher.apply(combiner.apply(a2, a3));  // result with splitting
+ * } </pre>
+ *
+ * <p>For collectors that do not have the {@code UNORDERED} characteristic,
+ * two accumulated results {@code a1} and {@code a2} are equivalent if
+ * {@code finisher.apply(a1).equals(finisher.apply(a2))}.  For unordered
+ * collectors, equivalence is relaxed to allow for non-equality related to
+ * differences in order.  (For example, an unordered collector that accumulated
+ * elements to a {@code List} would consider two lists equivalent if they
+ * contained the same elements, ignoring order.)
  *
  * <p>Libraries that implement reduction based on {@code Collector}, such as
  * {@link Stream#collect(Collector)}, must adhere to the following constraints:
@@ -132,6 +136,20 @@
  *     originating data is unordered.</li>
  * </ul>
  *
+ * <p>In addition to the predefined implementations in {@link Collectors}, the
+ * static factory methods {@link #of(Supplier, BiConsumer, BinaryOperator, Characteristics...)}
+ * can be used to construct collectors.  For example, you could create a collector
+ * that accumulates widgets into a {@code TreeSet} with:
+ *
+ * <pre>{@code
+ *     Collector<Widget, ?, TreeSet<Widget>> intoSet =
+ *         Collector.of(TreeSet::new, TreeSet::add,
+ *                      (left, right) -> { left.addAll(right); return left; });
+ * }</pre>
+ *
+ * (This behavior is also implemented by the predefined collector
+ * {@link Collectors#toCollection(Supplier)}).
+ *
  * @apiNote
  * Performing a reduction operation with a {@code Collector} should produce a
  * result equivalent to:
@@ -144,27 +162,35 @@
  *
  * <p>However, the library is free to partition the input, perform the reduction
  * on the partitions, and then use the combiner function to combine the partial
- * results to achieve a parallel reduction.  Depending on the specific reduction
+ * results to achieve a parallel reduction.  (Depending on the specific reduction
  * operation, this may perform better or worse, depending on the relative cost
- * of the accumulator and combiner functions.
+ * of the accumulator and combiner functions.)
+ *
+ * <p>Collectors are designed to be <em>composed</em>; many of the methods
+ * in {@link Collectors} are functions that take a collector and produce
+ * a new collector.  For example, given the following collector that computes
+ * the sum of the salaries of a stream of employees:
  *
- * <p>An example of an operation that can be easily modeled by {@code Collector}
- * is accumulating elements into a {@code TreeSet}. In this case, the {@code
- * resultSupplier()} function is {@code () -> new Treeset<T>()}, the
- * {@code accumulator} function is
- * {@code (set, element) -> set.add(element) }, and the combiner
- * function is {@code (left, right) -> { left.addAll(right); return left; }}.
- * (This behavior is implemented by
- * {@code Collectors.toCollection(TreeSet::new)}).
+ * <pre>{@code
+ *     Collector<Employee, ?, Integer> summingSalaries
+ *         = Collectors.summingInt(Employee::getSalary))
+ * }</pre>
  *
- * TODO Associativity and commutativity
+ * If we wanted to create a collector to tabulate the sum of salaries by
+ * department, we could reuse the "sum of salaries" logic using
+ * {@link Collectors#groupingBy(Function, Collector)}:
+ *
+ * <pre>{@code
+ *     Collector<Employee, ?, Map<Department, Integer>> summingSalariesByDept
+ *         = Collectors.groupingBy(Employee::getDepartment, summingSalaries);
+ * }</pre>
  *
  * @see Stream#collect(Collector)
  * @see Collectors
  *
  * @param <T> the type of input elements to the reduction operation
  * @param <A> the mutable accumulation type of the reduction operation (often
- *           hidden as an implementation detail)
+ *            hidden as an implementation detail)
  * @param <R> the result type of the reduction operation
  * @since 1.8
  */
@@ -177,25 +203,25 @@
     Supplier<A> supplier();
 
     /**
-     * A function that folds a new value into a mutable result container.
+     * A function that folds a value into a mutable result container.
      *
-     * @return a function which folds a new value into a mutable result container
+     * @return a function which folds a value into a mutable result container
      */
     BiConsumer<A, T> accumulator();
 
     /**
      * A function that accepts two partial results and merges them.  The
      * combiner function may fold state from one argument into the other and
-     * return that, or may return a new result object.
+     * return that, or may return a new result container.
      *
-     * @return a function which combines two partial results into a cumulative
+     * @return a function which combines two partial results into a combined
      * result
      */
     BinaryOperator<A> combiner();
 
     /**
      * Perform the final transformation from the intermediate accumulation type
-     * {@code A} to the final result representation {@code R}.
+     * {@code A} to the final result type {@code R}.
      *
      * <p>If the characteristic {@code IDENTITY_TRANSFORM} is
      * set, this function may be presumed to be an identity transform with an
@@ -228,12 +254,17 @@
      * @param <T> The type of input elements for the new collector
      * @param <R> The type of intermediate accumulation result, and final result,
      *           for the new collector
+     * @throws NullPointerException if any argument is null
      * @return the new {@code Collector}
      */
     public static<T, R> Collector<T, R, R> of(Supplier<R> supplier,
                                               BiConsumer<R, T> accumulator,
                                               BinaryOperator<R> combiner,
                                               Characteristics... characteristics) {
+        Objects.requireNonNull(supplier);
+        Objects.requireNonNull(accumulator);
+        Objects.requireNonNull(combiner);
+        Objects.requireNonNull(characteristics);
         Set<Characteristics> cs = (characteristics.length == 0)
                                   ? Collectors.CH_ID
                                   : Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH,
@@ -254,6 +285,7 @@
      * @param <T> The type of input elements for the new collector
      * @param <A> The intermediate accumulation type of the new collector
      * @param <R> The final result type of the new collector
+     * @throws NullPointerException if any argument is null
      * @return the new {@code Collector}
      */
     public static<T, A, R> Collector<T, A, R> of(Supplier<A> supplier,
@@ -261,6 +293,11 @@
                                                  BinaryOperator<A> combiner,
                                                  Function<A, R> finisher,
                                                  Characteristics... characteristics) {
+        Objects.requireNonNull(supplier);
+        Objects.requireNonNull(accumulator);
+        Objects.requireNonNull(combiner);
+        Objects.requireNonNull(finisher);
+        Objects.requireNonNull(characteristics);
         Set<Characteristics> cs = Collectors.CH_NOID;
         if (characteristics.length > 0) {
             cs = EnumSet.noneOf(Characteristics.class);
@@ -288,8 +325,9 @@
         CONCURRENT,
 
         /**
-         * Indicates that the result container has no intrinsic order, such as
-         * a {@link Set}.
+         * Indicates that the collection operation does not commit to preserving
+         * the encounter order of input elements.  (This might be true if the
+         * result container has no intrinsic order, such as a {@link Set}.)
          */
         UNORDERED,
 
--- a/jdk/src/share/classes/java/util/stream/Collectors.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/stream/Collectors.java	Wed Jul 05 19:11:53 2017 +0200
@@ -62,37 +62,35 @@
  * operations, such as accumulating elements into collections, summarizing
  * elements according to various criteria, etc.
  *
- * <p>The following are examples of using the predefined {@code Collector}
- * implementations in {@link Collectors} with the {@code Stream} API to perform
- * mutable reduction tasks:
+ * <p>The following are examples of using the predefined collectors to perform
+ * common mutable reduction tasks:
  *
  * <pre>{@code
  *     // Accumulate names into a List
  *     List<String> list = people.stream().map(Person::getName).collect(Collectors.toList());
  *
  *     // Accumulate names into a TreeSet
- *     Set<String> list = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));
+ *     Set<String> set = people.stream().map(Person::getName).collect(Collectors.toCollection(TreeSet::new));
  *
  *     // Convert elements to strings and concatenate them, separated by commas
  *     String joined = things.stream()
  *                           .map(Object::toString)
  *                           .collect(Collectors.joining(", "));
  *
- *     // Find highest-paid employee
- *     Employee highestPaid = employees.stream()
- *                                     .collect(Collectors.maxBy(Comparator.comparing(Employee::getSalary)))
- *                                     .get();
+ *     // Compute sum of salaries of employee
+ *     int total = employees.stream()
+ *                          .collect(Collectors.summingInt(Employee::getSalary)));
  *
  *     // Group employees by department
  *     Map<Department, List<Employee>> byDept
  *         = employees.stream()
  *                    .collect(Collectors.groupingBy(Employee::getDepartment));
  *
- *     // Find highest-paid employee by department
- *     Map<Department, Optional<Employee>> highestPaidByDept
+ *     // Compute sum of salaries by department
+ *     Map<Department, Integer> totalByDept
  *         = employees.stream()
  *                    .collect(Collectors.groupingBy(Employee::getDepartment,
- *                                                   Collectors.maxBy(Comparator.comparing(Employee::getSalary))));
+ *                                                   Collectors.summingInt(Employee::getSalary)));
  *
  *     // Partition students into passing and failing
  *     Map<Boolean, List<Student>> passingFailing =
@@ -101,8 +99,6 @@
  *
  * }</pre>
  *
- * TODO explanation of parallel collection
- *
  * @since 1.8
  */
 public final class Collectors {
@@ -222,7 +218,8 @@
     /**
      * Returns a {@code Collector} that accumulates the input elements into a
      * new {@code List}. There are no guarantees on the type, mutability,
-     * serializability, or thread-safety of the {@code List} returned.
+     * serializability, or thread-safety of the {@code List} returned; if more
+     * control over the returned {@code List} is required, use {@link #toCollection(Supplier)}.
      *
      * @param <T> the type of the input elements
      * @return a {@code Collector} which collects all the input elements into a
@@ -238,7 +235,9 @@
     /**
      * Returns a {@code Collector} that accumulates the input elements into a
      * new {@code Set}. There are no guarantees on the type, mutability,
-     * serializability, or thread-safety of the {@code Set} returned.
+     * serializability, or thread-safety of the {@code Set} returned; if more
+     * control over the returned {@code Set} is required, use
+     * {@link #toCollection(Supplier)}.
      *
      * <p>This is an {@link Collector.Characteristics#UNORDERED unordered}
      * Collector.
@@ -903,7 +902,7 @@
      * where the city names are sorted:
      * <pre>{@code
      *     ConcurrentMap<City, Set<String>> namesByCity
-     *         = people.stream().collect(groupingByConcurrent(Person::getCity, ConcurrentSkipListMap::new,
+     *         = people.stream().collect(groupingByConcurrent(Person::getCity,
      *                                                        mapping(Person::getLastName, toSet())));
      * }</pre>
      *
--- a/jdk/src/share/classes/java/util/stream/DelegatingStream.java	Tue Sep 17 08:08:07 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,270 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package java.util.stream;
-
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Spliterator;
-import java.util.function.BiConsumer;
-import java.util.function.BiFunction;
-import java.util.function.BinaryOperator;
-import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.function.IntFunction;
-import java.util.function.Predicate;
-import java.util.function.Supplier;
-import java.util.function.ToDoubleFunction;
-import java.util.function.ToIntFunction;
-import java.util.function.ToLongFunction;
-
-/**
- * A {@code Stream} implementation that delegates operations to another {@code
- * Stream}.
- *
- * @param <T> type of stream elements for this stream and underlying delegate
- * stream
- *
- * @since 1.8
- */
-public class DelegatingStream<T> implements Stream<T> {
-    final private Stream<T> delegate;
-
-    /**
-     * Construct a {@code Stream} that delegates operations to another {@code
-     * Stream}.
-     *
-     * @param delegate the underlying {@link Stream} to which we delegate all
-     *                 {@code Stream} methods
-     * @throws NullPointerException if the delegate is null
-     */
-    public DelegatingStream(Stream<T> delegate) {
-        this.delegate = Objects.requireNonNull(delegate);
-    }
-
-    // -- BaseStream methods --
-
-    @Override
-    public Spliterator<T> spliterator() {
-        return delegate.spliterator();
-    }
-
-    @Override
-    public boolean isParallel() {
-        return delegate.isParallel();
-    }
-
-    @Override
-    public Iterator<T> iterator() {
-        return delegate.iterator();
-    }
-
-    // -- Stream methods --
-
-    @Override
-    public Stream<T> filter(Predicate<? super T> predicate) {
-        return delegate.filter(predicate);
-    }
-
-    @Override
-    public <R> Stream<R> map(Function<? super T, ? extends R> mapper) {
-        return delegate.map(mapper);
-    }
-
-    @Override
-    public IntStream mapToInt(ToIntFunction<? super T> mapper) {
-        return delegate.mapToInt(mapper);
-    }
-
-    @Override
-    public LongStream mapToLong(ToLongFunction<? super T> mapper) {
-        return delegate.mapToLong(mapper);
-    }
-
-    @Override
-    public DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper) {
-        return delegate.mapToDouble(mapper);
-    }
-
-    @Override
-    public <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper) {
-        return delegate.flatMap(mapper);
-    }
-
-    @Override
-    public IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper) {
-        return delegate.flatMapToInt(mapper);
-    }
-
-    @Override
-    public LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper) {
-        return delegate.flatMapToLong(mapper);
-    }
-
-    @Override
-    public DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper) {
-        return delegate.flatMapToDouble(mapper);
-    }
-
-    @Override
-    public Stream<T> distinct() {
-        return delegate.distinct();
-    }
-
-    @Override
-    public Stream<T> sorted() {
-        return delegate.sorted();
-    }
-
-    @Override
-    public Stream<T> sorted(Comparator<? super T> comparator) {
-        return delegate.sorted(comparator);
-    }
-
-    @Override
-    public void forEach(Consumer<? super T> action) {
-        delegate.forEach(action);
-    }
-
-    @Override
-    public void forEachOrdered(Consumer<? super T> action) {
-        delegate.forEachOrdered(action);
-    }
-
-    @Override
-    public Stream<T> peek(Consumer<? super T> consumer) {
-        return delegate.peek(consumer);
-    }
-
-    @Override
-    public Stream<T> limit(long maxSize) {
-        return delegate.limit(maxSize);
-    }
-
-    @Override
-    public Stream<T> substream(long startingOffset) {
-        return delegate.substream(startingOffset);
-    }
-
-    @Override
-    public Stream<T> substream(long startingOffset, long endingOffset) {
-        return delegate.substream(startingOffset, endingOffset);
-    }
-
-    @Override
-    public <A> A[] toArray(IntFunction<A[]> generator) {
-        return delegate.toArray(generator);
-    }
-
-    @Override
-    public Object[] toArray() {
-        return delegate.toArray();
-    }
-
-    @Override
-    public T reduce(T identity, BinaryOperator<T> accumulator) {
-        return delegate.reduce(identity, accumulator);
-    }
-
-    @Override
-    public Optional<T> reduce(BinaryOperator<T> accumulator) {
-        return delegate.reduce(accumulator);
-    }
-
-    @Override
-    public <U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator,
-                        BinaryOperator<U> combiner) {
-        return delegate.reduce(identity, accumulator, combiner);
-    }
-
-    @Override
-    public <R> R collect(Supplier<R> resultFactory,
-                         BiConsumer<R, ? super T> accumulator,
-                         BiConsumer<R, R> combiner) {
-        return delegate.collect(resultFactory, accumulator, combiner);
-    }
-
-    @Override
-    public <R, A> R collect(Collector<? super T, A, ? extends R> collector) {
-        return delegate.collect(collector);
-    }
-
-    @Override
-    public Optional<T> max(Comparator<? super T> comparator) {
-        return delegate.max(comparator);
-    }
-
-    @Override
-    public Optional<T> min(Comparator<? super T> comparator) {
-        return delegate.min(comparator);
-    }
-
-    @Override
-    public long count() {
-        return delegate.count();
-    }
-
-    @Override
-    public boolean anyMatch(Predicate<? super T> predicate) {
-        return delegate.anyMatch(predicate);
-    }
-
-    @Override
-    public boolean allMatch(Predicate<? super T> predicate) {
-        return delegate.allMatch(predicate);
-    }
-
-    @Override
-    public boolean noneMatch(Predicate<? super T> predicate) {
-        return delegate.noneMatch(predicate);
-    }
-
-    @Override
-    public Optional<T> findFirst() {
-        return delegate.findFirst();
-    }
-
-    @Override
-    public Optional<T> findAny() {
-        return delegate.findAny();
-    }
-
-    @Override
-    public Stream<T> unordered() {
-        return delegate.unordered();
-    }
-
-    @Override
-    public Stream<T> sequential() {
-        return delegate.sequential();
-    }
-
-    @Override
-    public Stream<T> parallel() {
-        return delegate.parallel();
-    }
-}
--- a/jdk/src/share/classes/java/util/stream/DoublePipeline.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/stream/DoublePipeline.java	Wed Jul 05 19:11:53 2017 +0200
@@ -266,10 +266,11 @@
 
                     @Override
                     public void accept(double t) {
-                        // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
-                        DoubleStream result = mapper.apply(t);
-                        if (result != null)
-                            result.sequential().forEach(i -> downstream.accept(i));
+                        try (DoubleStream result = mapper.apply(t)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(i -> downstream.accept(i));
+                        }
                     }
                 };
             }
@@ -312,8 +313,8 @@
     }
 
     @Override
-    public final DoubleStream peek(DoubleConsumer consumer) {
-        Objects.requireNonNull(consumer);
+    public final DoubleStream peek(DoubleConsumer action) {
+        Objects.requireNonNull(action);
         return new StatelessOp<Double>(this, StreamShape.DOUBLE_VALUE,
                                        0) {
             @Override
@@ -321,7 +322,7 @@
                 return new Sink.ChainedDouble<Double>(sink) {
                     @Override
                     public void accept(double t) {
-                        consumer.accept(t);
+                        action.accept(t);
                         downstream.accept(t);
                     }
                 };
@@ -435,14 +436,14 @@
     }
 
     @Override
-    public final <R> R collect(Supplier<R> resultFactory,
+    public final <R> R collect(Supplier<R> supplier,
                                ObjDoubleConsumer<R> accumulator,
                                BiConsumer<R, R> combiner) {
         BinaryOperator<R> operator = (left, right) -> {
             combiner.accept(left, right);
             return left;
         };
-        return evaluate(ReduceOps.makeDouble(resultFactory, accumulator, operator));
+        return evaluate(ReduceOps.makeDouble(supplier, accumulator, operator));
     }
 
     @Override
--- a/jdk/src/share/classes/java/util/stream/DoubleStream.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/stream/DoubleStream.java	Wed Jul 05 19:11:53 2017 +0200
@@ -24,13 +24,18 @@
  */
 package java.util.stream;
 
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.DoubleSummaryStatistics;
 import java.util.Objects;
 import java.util.OptionalDouble;
 import java.util.PrimitiveIterator;
 import java.util.Spliterator;
 import java.util.Spliterators;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.BiConsumer;
 import java.util.function.DoubleBinaryOperator;
 import java.util.function.DoubleConsumer;
@@ -45,40 +50,87 @@
 import java.util.function.Supplier;
 
 /**
- * A sequence of primitive double elements supporting sequential and parallel
- * bulk operations. Streams support lazy intermediate operations (transforming
- * a stream to another stream) such as {@code filter} and {@code map}, and terminal
- * operations (consuming the contents of a stream to produce a result or
- * side-effect), such as {@code forEach}, {@code findFirst}, and {@code
- * iterator}.  Once an operation has been performed on a stream, it
- * is considered <em>consumed</em> and no longer usable for other operations.
+ * A sequence of elements supporting sequential and parallel aggregate
+ * operations.  The following example illustrates an aggregate operation using
+ * {@link Stream} and {@link DoubleStream}:
+ *
+ * <pre>{@code
+ *     double sum = widgets.stream()
+ *                         .filter(w -> w.getColor() == RED)
+ *                         .mapToDouble(w -> w.getWeight())
+ *                         .sum();
+ * }</pre>
+ *
+ * In this example, {@code widgets} is a {@code Collection<Widget>}.  We create
+ * a stream of {@code Widget} objects via {@link Collection#stream Collection.stream()},
+ * filter it to produce a stream containing only the red widgets, and then
+ * transform it into a stream of {@code double} values representing the weight of
+ * each red widget. Then this stream is summed to produce a total weight.
  *
- * <p>For sequential stream pipelines, all operations are performed in the
- * <a href="package-summary.html#Ordering">encounter order</a> of the pipeline
- * source, if the pipeline source has a defined encounter order.
+ * <p>To perform a computation, stream
+ * <a href="package-summary.html#StreamOps">operations</a> are composed into a
+ * <em>stream pipeline</em>.  A stream pipeline consists of a source (which
+ * might be an array, a collection, a generator function, an IO channel,
+ * etc), zero or more <em>intermediate operations</em> (which transform a
+ * stream into another stream, such as {@link DoubleStream#filter(DoublePredicate)}), and a
+ * <em>terminal operation</em> (which produces a result or side-effect, such
+ * as {@link DoubleStream#sum()} or {@link DoubleStream#forEach(DoubleConsumer)}.
+ * Streams are lazy; computation on the source data is only performed when the
+ * terminal operation is initiated, and source elements are consumed only
+ * as needed.
+ *
+ * <p>Collections and streams, while bearing some superficial similarities,
+ * have different goals.  Collections are primarily concerned with the efficient
+ * management of, and access to, their elements.  By contrast, streams do not
+ * provide a means to directly access or manipulate their elements, and are
+ * instead concerned with declaratively describing their source and the
+ * computational operations which will be performed in aggregate on that source.
+ * However, if the provided stream operations do not offer the desired
+ * functionality, the {@link #iterator()} and {@link #spliterator()} operations
+ * can be used to perform a controlled traversal.
  *
- * <p>For parallel stream pipelines, unless otherwise specified, intermediate
- * stream operations preserve the <a href="package-summary.html#Ordering">
- * encounter order</a> of their source, and terminal operations
- * respect the encounter order of their source, if the source
- * has an encounter order.  Provided that and parameters to stream operations
- * satisfy the <a href="package-summary.html#NonInterference">non-interference
- * requirements</a>, and excepting differences arising from the absence of
- * a defined encounter order, the result of a stream pipeline should be the
- * stable across multiple executions of the same operations on the same source.
- * However, the timing and thread in which side-effects occur (for those
- * operations which are allowed to produce side-effects, such as
- * {@link #forEach(DoubleConsumer)}), are explicitly nondeterministic for parallel
- * execution of stream pipelines.
+ * <p>A stream pipeline, like the "widgets" example above, can be viewed as
+ * a <em>query</em> on the stream source.  Unless the source was explicitly
+ * designed for concurrent modification (such as a {@link ConcurrentHashMap}),
+ * unpredictable or erroneous behavior may result from modifying the stream
+ * source while it is being queried.
+ *
+ * <p>Most stream operations accept parameters that describe user-specified
+ * behavior, such as the lambda expression {@code w -> w.getWeight()} passed to
+ * {@code mapToDouble} in the example above.  Such parameters are always instances
+ * of a <a href="../function/package-summary.html">functional interface</a> such
+ * as {@link java.util.function.Function}, and are often lambda expressions or
+ * method references.  These parameters can never be null, should not modify the
+ * stream source, and should be
+ * <a href="package-summary.html#NonInterference">effectively stateless</a>
+ * (their result should not depend on any state that might change during
+ * execution of the stream pipeline.)
  *
- * <p>Unless otherwise noted, passing a {@code null} argument to any stream
- * method may result in a {@link NullPointerException}.
+ * <p>A stream should be operated on (invoking an intermediate or terminal stream
+ * operation) only once.  This rules out, for example, "forked" streams, where
+ * the same source feeds two or more pipelines, or multiple traversals of the
+ * same stream.  A stream implementation may throw {@link IllegalStateException}
+ * if it detects that the stream is being reused. However, since some stream
+ * operations may return their receiver rather than a new stream object, it may
+ * not be possible to detect reuse in all cases.
  *
- * @apiNote
- * Streams are not data structures; they do not manage the storage for their
- * elements, nor do they support access to individual elements.  However,
- * you can use the {@link #iterator()} or {@link #spliterator()} operations to
- * perform a controlled traversal.
+ * <p>Streams have a {@link #close()} method and implement {@link AutoCloseable},
+ * but nearly all stream instances do not actually need to be closed after use.
+ * Generally, only streams whose source is an IO channel (such as those returned
+ * by {@link Files#lines(Path, Charset)}) will require closing.  Most streams
+ * are backed by collections, arrays, or generating functions, which require no
+ * special resource management.  (If a stream does require closing, it can be
+ * declared as a resource in a {@code try}-with-resources statement.)
+ *
+ * <p>Stream pipelines may execute either sequentially or in
+ * <a href="package-summary.html#Parallelism">parallel</a>.  This
+ * execution mode is a property of the stream.  Streams are created
+ * with an initial choice of sequential or parallel execution.  (For example,
+ * {@link Collection#stream() Collection.stream()} creates a sequential stream,
+ * and {@link Collection#parallelStream() Collection.parallelStream()} creates
+ * a parallel one.)  This choice of execution mode may be modified by the
+ * {@link #sequential()} or {@link #parallel()} methods, and may be queried with
+ * the {@link #isParallel()} method.
  *
  * @since 1.8
  * @see <a href="package-summary.html">java.util.stream</a>
@@ -159,22 +211,13 @@
     /**
      * Returns a stream consisting of the results of replacing each element of
      * this stream with the contents of the stream produced by applying the
-     * provided mapping function to each element.
+     * provided mapping function to each element.  (If the result of the mapping
+     * function is {@code null}, this is treated as if the result was an empty
+     * stream.)
      *
      * <p>This is an <a href="package-summary.html#StreamOps">intermediate
      * operation</a>.
      *
-     * @apiNote
-     * The {@code flatMap()} operation has the effect of applying a one-to-many
-     * tranformation to the elements of the stream, and then flattening the
-     * resulting elements into a new stream. For example, if {@code orders}
-     * is a stream of purchase orders, and each purchase order contains a
-     * collection of line items, then the following produces a stream of line
-     * items:
-     * <pre>{@code
-     *     orderStream.flatMap(order -> order.getLineItems().stream())...
-     * }</pre>
-     *
      * @param mapper a <a href="package-summary.html#NonInterference">
      *               non-interfering, stateless</a> function to apply to
      *               each element which produces an {@code DoubleStream} of new
@@ -226,18 +269,18 @@
      * <pre>{@code
      *     list.stream()
      *         .filter(filteringFunction)
-     *         .peek(e -> {System.out.println("Filtered value: " + e); });
+     *         .peek(e -> System.out.println("Filtered value: " + e));
      *         .map(mappingFunction)
-     *         .peek(e -> {System.out.println("Mapped value: " + e); });
+     *         .peek(e -> System.out.println("Mapped value: " + e));
      *         .collect(Collectors.toDoubleSummaryStastistics());
      * }</pre>
      *
-     * @param consumer a <a href="package-summary.html#NonInterference">
+     * @param action a <a href="package-summary.html#NonInterference">
      *                 non-interfering</a> action to perform on the elements as
      *                 they are consumed from the stream
      * @return the new stream
      */
-    DoubleStream peek(DoubleConsumer consumer);
+    DoubleStream peek(DoubleConsumer action);
 
     /**
      * Returns a stream consisting of the elements of this stream, truncated
@@ -254,8 +297,8 @@
 
     /**
      * Returns a stream consisting of the remaining elements of this stream
-     * after indexing {@code startInclusive} elements into the stream. If the
-     * {@code startInclusive} index lies past the end of this stream then an
+     * after discarding the first {@code startInclusive} elements of the stream.
+     * If this stream contains fewer than {@code startInclusive} elements then an
      * empty stream will be returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">stateful
@@ -269,10 +312,10 @@
 
     /**
      * Returns a stream consisting of the remaining elements of this stream
-     * after indexing {@code startInclusive} elements into the stream and
-     * truncated to contain no more than {@code endExclusive - startInclusive}
-     * elements. If the {@code startInclusive} index lies past the end
-     * of this stream then an empty stream will be returned.
+     * after discarding the first {@code startInclusive} elements and truncating
+     * the result to be no longer than {@code endExclusive - startInclusive}
+     * elements in length. If this stream contains fewer than
+     * {@code startInclusive} elements then an empty stream will be returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
      * stateful intermediate operation</a>.
@@ -421,12 +464,12 @@
     /**
      * Performs a <a href="package-summary.html#MutableReduction">mutable
      * reduction</a> operation on the elements of this stream.  A mutable
-     * reduction is one in which the reduced value is a mutable value holder,
+     * reduction is one in which the reduced value is a mutable result container,
      * such as an {@code ArrayList}, and elements are incorporated by updating
-     * the state of the result, rather than by replacing the result.  This
+     * the state of the result rather than by replacing the result.  This
      * produces a result equivalent to:
      * <pre>{@code
-     *     R result = resultFactory.get();
+     *     R result = supplier.get();
      *     for (double element : this stream)
      *         accumulator.accept(result, element);
      *     return result;
@@ -440,10 +483,9 @@
      * operation</a>.
      *
      * @param <R> type of the result
-     * @param resultFactory a function that creates a new result container.
-     *                      For a parallel execution, this function may be
-     *                      called multiple times and must return a fresh value
-     *                      each time.
+     * @param supplier a function that creates a new result container. For a
+     *                 parallel execution, this function may be called
+     *                 multiple times and must return a fresh value each time.
      * @param accumulator an <a href="package-summary.html#Associativity">associative</a>
      *                    <a href="package-summary.html#NonInterference">non-interfering,
      *                    stateless</a> function for incorporating an additional
@@ -455,7 +497,7 @@
      * @return the result of the reduction
      * @see Stream#collect(Supplier, BiConsumer, BiConsumer)
      */
-    <R> R collect(Supplier<R> resultFactory,
+    <R> R collect(Supplier<R> supplier,
                   ObjDoubleConsumer<R> accumulator,
                   BiConsumer<R, R> combiner);
 
@@ -467,12 +509,15 @@
      * yield more accurate results.  If any stream element is a {@code NaN} or
      * the sum is at any point a {@code NaN} then the sum will be {@code NaN}.
      * This is a special case of a
-     * <a href="package-summary.html#MutableReduction">reduction</a> and is
+     * <a href="package-summary.html#Reduction">reduction</a> and is
      * equivalent to:
      * <pre>{@code
      *     return reduce(0, Double::sum);
      * }</pre>
      *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
      * @return the sum of elements in this stream
      */
     double sum();
@@ -483,12 +528,15 @@
      * element will be {@code Double.NaN} if any stream element was NaN. Unlike
      * the numerical comparison operators, this method considers negative zero
      * to be strictly smaller than positive zero. This is a special case of a
-     * <a href="package-summary.html#MutableReduction">reduction</a> and is
+     * <a href="package-summary.html#Reduction">reduction</a> and is
      * equivalent to:
      * <pre>{@code
      *     return reduce(Double::min);
      * }</pre>
      *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
      * @return an {@code OptionalDouble} containing the minimum element of this
      * stream, or an empty optional if the stream is empty
      */
@@ -501,12 +549,15 @@
      * the numerical comparison operators, this method considers negative zero
      * to be strictly smaller than positive zero. This is a
      * special case of a
-     * <a href="package-summary.html#MutableReduction">reduction</a> and is
+     * <a href="package-summary.html#Reduction">reduction</a> and is
      * equivalent to:
      * <pre>{@code
      *     return reduce(Double::max);
      * }</pre>
      *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
      * @return an {@code OptionalDouble} containing the maximum element of this
      * stream, or an empty optional if the stream is empty
      */
@@ -514,7 +565,7 @@
 
     /**
      * Returns the count of elements in this stream.  This is a special case of
-     * a <a href="package-summary.html#MutableReduction">reduction</a> and is
+     * a <a href="package-summary.html#Reduction">reduction</a> and is
      * equivalent to:
      * <pre>{@code
      *     return mapToLong(e -> 1L).sum();
@@ -535,7 +586,10 @@
      * magnitude tend to yield more accurate results. If any recorded value is
      * a {@code NaN} or the sum is at any point a {@code NaN} then the average
      * will be {@code NaN}. This is a special case of a
-     * <a href="package-summary.html#MutableReduction">reduction</a>.
+     * <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
      *
      * @return an {@code OptionalDouble} containing the average element of this
      * stream, or an empty optional if the stream is empty
@@ -545,7 +599,10 @@
     /**
      * Returns a {@code DoubleSummaryStatistics} describing various summary data
      * about the elements of this stream.  This is a special
-     * case of a <a href="package-summary.html#MutableReduction">reduction</a>.
+     * case of a <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
      *
      * @return a {@code DoubleSummaryStatistics} describing various summary data
      * about the elements of this stream
@@ -602,9 +659,8 @@
 
     /**
      * Returns an {@link OptionalDouble} describing the first element of this
-     * stream (in the encounter order), or an empty {@code OptionalDouble} if
-     * the stream is empty.  If the stream has no encounter order, then any
-     * element may be returned.
+     * stream, or an empty {@code OptionalDouble} if the stream is empty.  If
+     * the stream has no encounter order, then any element may be returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
      * terminal operation</a>.
@@ -624,8 +680,8 @@
      * <p>The behavior of this operation is explicitly nondeterministic; it is
      * free to select any element in the stream.  This is to allow for maximal
      * performance in parallel operations; the cost is that multiple invocations
-     * on the same source may not return the same result.  (If the first element
-     * in the encounter order is desired, use {@link #findFirst()} instead.)
+     * on the same source may not return the same result.  (If a stable result
+     * is desired, use {@link #findFirst()} instead.)
      *
      * @return an {@code OptionalDouble} describing some element of this stream,
      * or an empty {@code OptionalDouble} if the stream is empty
@@ -637,6 +693,9 @@
      * Returns a {@code Stream} consisting of the elements of this stream,
      * boxed to {@code Double}.
      *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
      * @return a {@code Stream} consistent of the elements of this stream,
      * each boxed to a {@code Double}
      */
@@ -686,7 +745,7 @@
     }
 
     /**
-     * Returns a sequential stream whose elements are the specified values.
+     * Returns a sequential ordered stream whose elements are the specified values.
      *
      * @param values the elements of the new stream
      * @return the new stream
@@ -696,7 +755,7 @@
     }
 
     /**
-     * Returns an infinite sequential {@code DoubleStream} produced by iterative
+     * Returns an infinite sequential ordered {@code DoubleStream} produced by iterative
      * application of a function {@code f} to an initial element {@code seed},
      * producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
      * {@code f(f(seed))}, etc.
@@ -734,8 +793,8 @@
     }
 
     /**
-     * Returns a sequential {@code DoubleStream} where each element is
-     * generated by an {@code DoubleSupplier}.  This is suitable for generating
+     * Returns a sequential stream where each element is generated by
+     * the provided {@code DoubleSupplier}.  This is suitable for generating
      * constant streams, streams of random elements, etc.
      *
      * @param s the {@code DoubleSupplier} for generated elements
@@ -748,15 +807,16 @@
     }
 
     /**
-     * Creates a lazy concatenated {@code DoubleStream} whose elements are all the
-     * elements of a first {@code DoubleStream} succeeded by all the elements of the
-     * second {@code DoubleStream}. The resulting stream is ordered if both
+     * Creates a lazily concatenated stream whose elements are all the
+     * elements of the first stream followed by all the elements of the
+     * second stream. The resulting stream is ordered if both
      * of the input streams are ordered, and parallel if either of the input
-     * streams is parallel.
+     * streams is parallel.  When the resulting stream is closed, the close
+     * handlers for both input streams are invoked.
      *
      * @param a the first stream
-     * @param b the second stream to concatenate on to end of the first stream
-     * @return the concatenation of the two streams
+     * @param b the second stream
+     * @return the concatenation of the two input streams
      */
     public static DoubleStream concat(DoubleStream a, DoubleStream b) {
         Objects.requireNonNull(a);
@@ -764,15 +824,16 @@
 
         Spliterator.OfDouble split = new Streams.ConcatSpliterator.OfDouble(
                 a.spliterator(), b.spliterator());
-        return StreamSupport.doubleStream(split, a.isParallel() || b.isParallel());
+        DoubleStream stream = StreamSupport.doubleStream(split, a.isParallel() || b.isParallel());
+        return stream.onClose(Streams.composedClose(a, b));
     }
 
     /**
      * A mutable builder for a {@code DoubleStream}.
      *
-     * <p>A stream builder has a lifecycle, where it starts in a building
-     * phase, during which elements can be added, and then transitions to a
-     * built phase, after which elements may not be added.  The built phase
+     * <p>A stream builder has a lifecycle, which starts in a building
+     * phase, during which elements can be added, and then transitions to a built
+     * phase, after which elements may not be added.  The built phase
      * begins when the {@link #build()} method is called, which creates an
      * ordered stream whose elements are the elements that were added to the
      * stream builder, in the order they were added.
--- a/jdk/src/share/classes/java/util/stream/IntPipeline.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/stream/IntPipeline.java	Wed Jul 05 19:11:53 2017 +0200
@@ -302,10 +302,11 @@
 
                     @Override
                     public void accept(int t) {
-                        // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
-                        IntStream result = mapper.apply(t);
-                        if (result != null)
-                            result.sequential().forEach(i -> downstream.accept(i));
+                        try (IntStream result = mapper.apply(t)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(i -> downstream.accept(i));
+                        }
                     }
                 };
             }
@@ -348,8 +349,8 @@
     }
 
     @Override
-    public final IntStream peek(IntConsumer consumer) {
-        Objects.requireNonNull(consumer);
+    public final IntStream peek(IntConsumer action) {
+        Objects.requireNonNull(action);
         return new StatelessOp<Integer>(this, StreamShape.INT_VALUE,
                                         0) {
             @Override
@@ -357,7 +358,7 @@
                 return new Sink.ChainedInt<Integer>(sink) {
                     @Override
                     public void accept(int t) {
-                        consumer.accept(t);
+                        action.accept(t);
                         downstream.accept(t);
                     }
                 };
@@ -472,14 +473,14 @@
     }
 
     @Override
-    public final <R> R collect(Supplier<R> resultFactory,
+    public final <R> R collect(Supplier<R> supplier,
                                ObjIntConsumer<R> accumulator,
                                BiConsumer<R, R> combiner) {
         BinaryOperator<R> operator = (left, right) -> {
             combiner.accept(left, right);
             return left;
         };
-        return evaluate(ReduceOps.makeInt(resultFactory, accumulator, operator));
+        return evaluate(ReduceOps.makeInt(supplier, accumulator, operator));
     }
 
     @Override
--- a/jdk/src/share/classes/java/util/stream/IntStream.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/stream/IntStream.java	Wed Jul 05 19:11:53 2017 +0200
@@ -24,7 +24,11 @@
  */
 package java.util.stream;
 
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.IntSummaryStatistics;
 import java.util.Objects;
 import java.util.OptionalDouble;
@@ -32,6 +36,7 @@
 import java.util.PrimitiveIterator;
 import java.util.Spliterator;
 import java.util.Spliterators;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.BiConsumer;
 import java.util.function.Function;
 import java.util.function.IntBinaryOperator;
@@ -46,40 +51,87 @@
 import java.util.function.Supplier;
 
 /**
- * A sequence of primitive integer elements supporting sequential and parallel
- * bulk operations. Streams support lazy intermediate operations (transforming
- * a stream to another stream) such as {@code filter} and {@code map}, and terminal
- * operations (consuming the contents of a stream to produce a result or
- * side-effect), such as {@code forEach}, {@code findFirst}, and {@code
- * iterator}.  Once an operation has been performed on a stream, it
- * is considered <em>consumed</em> and no longer usable for other operations.
+ * A sequence of elements supporting sequential and parallel aggregate
+ * operations.  The following example illustrates an aggregate operation using
+ * {@link Stream} and {@link IntStream}:
+ *
+ * <pre>{@code
+ *     int sum = widgets.stream()
+ *                      .filter(w -> w.getColor() == RED)
+ *                      .mapToInt(w -> w.getWeight())
+ *                      .sum();
+ * }</pre>
+ *
+ * In this example, {@code widgets} is a {@code Collection<Widget>}.  We create
+ * a stream of {@code Widget} objects via {@link Collection#stream Collection.stream()},
+ * filter it to produce a stream containing only the red widgets, and then
+ * transform it into a stream of {@code int} values representing the weight of
+ * each red widget. Then this stream is summed to produce a total weight.
  *
- * <p>For sequential stream pipelines, all operations are performed in the
- * <a href="package-summary.html#Ordering">encounter order</a> of the pipeline
- * source, if the pipeline source has a defined encounter order.
+ * <p>To perform a computation, stream
+ * <a href="package-summary.html#StreamOps">operations</a> are composed into a
+ * <em>stream pipeline</em>.  A stream pipeline consists of a source (which
+ * might be an array, a collection, a generator function, an IO channel,
+ * etc), zero or more <em>intermediate operations</em> (which transform a
+ * stream into another stream, such as {@link IntStream#filter(IntPredicate)}), and a
+ * <em>terminal operation</em> (which produces a result or side-effect, such
+ * as {@link IntStream#sum()} or {@link IntStream#forEach(IntConsumer)}).
+ * Streams are lazy; computation on the source data is only performed when the
+ * terminal operation is initiated, and source elements are consumed only
+ * as needed.
+ *
+ * <p>Collections and streams, while bearing some superficial similarities,
+ * have different goals.  Collections are primarily concerned with the efficient
+ * management of, and access to, their elements.  By contrast, streams do not
+ * provide a means to directly access or manipulate their elements, and are
+ * instead concerned with declaratively describing their source and the
+ * computational operations which will be performed in aggregate on that source.
+ * However, if the provided stream operations do not offer the desired
+ * functionality, the {@link #iterator()} and {@link #spliterator()} operations
+ * can be used to perform a controlled traversal.
  *
- * <p>For parallel stream pipelines, unless otherwise specified, intermediate
- * stream operations preserve the <a href="package-summary.html#Ordering">
- * encounter order</a> of their source, and terminal operations
- * respect the encounter order of their source, if the source
- * has an encounter order.  Provided that and parameters to stream operations
- * satisfy the <a href="package-summary.html#NonInterference">non-interference
- * requirements</a>, and excepting differences arising from the absence of
- * a defined encounter order, the result of a stream pipeline should be the
- * stable across multiple executions of the same operations on the same source.
- * However, the timing and thread in which side-effects occur (for those
- * operations which are allowed to produce side-effects, such as
- * {@link #forEach(IntConsumer)}), are explicitly nondeterministic for parallel
- * execution of stream pipelines.
+ * <p>A stream pipeline, like the "widgets" example above, can be viewed as
+ * a <em>query</em> on the stream source.  Unless the source was explicitly
+ * designed for concurrent modification (such as a {@link ConcurrentHashMap}),
+ * unpredictable or erroneous behavior may result from modifying the stream
+ * source while it is being queried.
+ *
+ * <p>Most stream operations accept parameters that describe user-specified
+ * behavior, such as the lambda expression {@code w -> w.getWeight()} passed to
+ * {@code mapToInt} in the example above.  Such parameters are always instances
+ * of a <a href="../function/package-summary.html">functional interface</a> such
+ * as {@link java.util.function.Function}, and are often lambda expressions or
+ * method references.  These parameters can never be null, should not modify the
+ * stream source, and should be
+ * <a href="package-summary.html#NonInterference">effectively stateless</a>
+ * (their result should not depend on any state that might change during
+ * execution of the stream pipeline.)
  *
- * <p>Unless otherwise noted, passing a {@code null} argument to any stream
- * method may result in a {@link NullPointerException}.
+ * <p>A stream should be operated on (invoking an intermediate or terminal stream
+ * operation) only once.  This rules out, for example, "forked" streams, where
+ * the same source feeds two or more pipelines, or multiple traversals of the
+ * same stream.  A stream implementation may throw {@link IllegalStateException}
+ * if it detects that the stream is being reused. However, since some stream
+ * operations may return their receiver rather than a new stream object, it may
+ * not be possible to detect reuse in all cases.
  *
- * @apiNote
- * Streams are not data structures; they do not manage the storage for their
- * elements, nor do they support access to individual elements.  However,
- * you can use the {@link #iterator()} or {@link #spliterator()} operations to
- * perform a controlled traversal.
+ * <p>Streams have a {@link #close()} method and implement {@link AutoCloseable},
+ * but nearly all stream instances do not actually need to be closed after use.
+ * Generally, only streams whose source is an IO channel (such as those returned
+ * by {@link Files#lines(Path, Charset)}) will require closing.  Most streams
+ * are backed by collections, arrays, or generating functions, which require no
+ * special resource management.  (If a stream does require closing, it can be
+ * declared as a resource in a {@code try}-with-resources statement.)
+ *
+ * <p>Stream pipelines may execute either sequentially or in
+ * <a href="package-summary.html#Parallelism">parallel</a>.  This
+ * execution mode is a property of the stream.  Streams are created
+ * with an initial choice of sequential or parallel execution.  (For example,
+ * {@link Collection#stream() Collection.stream()} creates a sequential stream,
+ * and {@link Collection#parallelStream() Collection.parallelStream()} creates
+ * a parallel one.)  This choice of execution mode may be modified by the
+ * {@link #sequential()} or {@link #parallel()} methods, and may be queried with
+ * the {@link #isParallel()} method.
  *
  * @since 1.8
  * @see <a href="package-summary.html">java.util.stream</a>
@@ -160,22 +212,13 @@
     /**
      * Returns a stream consisting of the results of replacing each element of
      * this stream with the contents of the stream produced by applying the
-     * provided mapping function to each element.
+     * provided mapping function to each element.  (If the result of the mapping
+     * function is {@code null}, this is treated as if the result was an empty
+     * stream.)
      *
      * <p>This is an <a href="package-summary.html#StreamOps">intermediate
      * operation</a>.
      *
-     * @apiNote
-     * The {@code flatMap()} operation has the effect of applying a one-to-many
-     * tranformation to the elements of the stream, and then flattening the
-     * resulting elements into a new stream. For example, if {@code orders}
-     * is a stream of purchase orders, and each purchase order contains a
-     * collection of line items, then the following produces a stream of line
-     * items:
-     * <pre>{@code
-     *     orderStream.flatMap(order -> order.getLineItems().stream())...
-     * }</pre>
-     *
      * @param mapper a <a href="package-summary.html#NonInterference">
      *               non-interfering, stateless</a> function to apply to
      *               each element which produces an {@code IntStream} of new
@@ -224,18 +267,18 @@
      * <pre>{@code
      *     list.stream()
      *         .filter(filteringFunction)
-     *         .peek(e -> {System.out.println("Filtered value: " + e); });
+     *         .peek(e -> System.out.println("Filtered value: " + e));
      *         .map(mappingFunction)
-     *         .peek(e -> {System.out.println("Mapped value: " + e); });
+     *         .peek(e -> System.out.println("Mapped value: " + e));
      *         .collect(Collectors.toIntSummaryStastistics());
      * }</pre>
      *
-     * @param consumer a <a href="package-summary.html#NonInterference">
-     *                 non-interfering</a> action to perform on the elements as
-     *                 they are consumed from the stream
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements as
+     *               they are consumed from the stream
      * @return the new stream
      */
-    IntStream peek(IntConsumer consumer);
+    IntStream peek(IntConsumer action);
 
     /**
      * Returns a stream consisting of the elements of this stream, truncated
@@ -252,8 +295,8 @@
 
     /**
      * Returns a stream consisting of the remaining elements of this stream
-     * after indexing {@code startInclusive} elements into the stream. If the
-     * {@code startInclusive} index lies past the end of this stream then an
+     * after discarding the first {@code startInclusive} elements of the stream.
+     * If this stream contains fewer than {@code startInclusive} elements then an
      * empty stream will be returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">stateful
@@ -267,10 +310,10 @@
 
     /**
      * Returns a stream consisting of the remaining elements of this stream
-     * after indexing {@code startInclusive} elements into the stream and
-     * truncated to contain no more than {@code endExclusive - startInclusive}
-     * elements. If the {@code startInclusive} index lies past the end
-     * of this stream then an empty stream will be returned.
+     * after discarding the first {@code startInclusive} elements and truncating
+     * the result to be no longer than {@code endExclusive - startInclusive}
+     * elements in length. If this stream contains fewer than
+     * {@code startInclusive} elements then an empty stream will be returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
      * stateful intermediate operation</a>.
@@ -419,12 +462,12 @@
     /**
      * Performs a <a href="package-summary.html#MutableReduction">mutable
      * reduction</a> operation on the elements of this stream.  A mutable
-     * reduction is one in which the reduced value is a mutable value holder,
+     * reduction is one in which the reduced value is a mutable result container,
      * such as an {@code ArrayList}, and elements are incorporated by updating
-     * the state of the result, rather than by replacing the result.  This
+     * the state of the result rather than by replacing the result.  This
      * produces a result equivalent to:
      * <pre>{@code
-     *     R result = resultFactory.get();
+     *     R result = supplier.get();
      *     for (int element : this stream)
      *         accumulator.accept(result, element);
      *     return result;
@@ -437,10 +480,9 @@
      * operation</a>.
      *
      * @param <R> type of the result
-     * @param resultFactory a function that creates a new result container.
-     *                      For a parallel execution, this function may be
-     *                      called multiple times and must return a fresh value
-     *                      each time.
+     * @param supplier a function that creates a new result container. For a
+     *                 parallel execution, this function may be called
+     *                 multiple times and must return a fresh value each time.
      * @param accumulator an <a href="package-summary.html#Associativity">associative</a>
      *                    <a href="package-summary.html#NonInterference">non-interfering,
      *                    stateless</a> function for incorporating an additional
@@ -452,18 +494,21 @@
      * @return the result of the reduction
      * @see Stream#collect(Supplier, BiConsumer, BiConsumer)
      */
-    <R> R collect(Supplier<R> resultFactory,
+    <R> R collect(Supplier<R> supplier,
                   ObjIntConsumer<R> accumulator,
                   BiConsumer<R, R> combiner);
 
     /**
      * Returns the sum of elements in this stream.  This is a special case
-     * of a <a href="package-summary.html#MutableReduction">reduction</a>
+     * of a <a href="package-summary.html#Reduction">reduction</a>
      * and is equivalent to:
      * <pre>{@code
      *     return reduce(0, Integer::sum);
      * }</pre>
      *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
      * @return the sum of elements in this stream
      */
     int sum();
@@ -471,7 +516,7 @@
     /**
      * Returns an {@code OptionalInt} describing the minimum element of this
      * stream, or an empty optional if this stream is empty.  This is a special
-     * case of a <a href="package-summary.html#MutableReduction">reduction</a>
+     * case of a <a href="package-summary.html#Reduction">reduction</a>
      * and is equivalent to:
      * <pre>{@code
      *     return reduce(Integer::min);
@@ -479,7 +524,6 @@
      *
      * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
      *
-
      * @return an {@code OptionalInt} containing the minimum element of this
      * stream, or an empty {@code OptionalInt} if the stream is empty
      */
@@ -488,7 +532,7 @@
     /**
      * Returns an {@code OptionalInt} describing the maximum element of this
      * stream, or an empty optional if this stream is empty.  This is a special
-     * case of a <a href="package-summary.html#MutableReduction">reduction</a>
+     * case of a <a href="package-summary.html#Reduction">reduction</a>
      * and is equivalent to:
      * <pre>{@code
      *     return reduce(Integer::max);
@@ -504,7 +548,7 @@
 
     /**
      * Returns the count of elements in this stream.  This is a special case of
-     * a <a href="package-summary.html#MutableReduction">reduction</a> and is
+     * a <a href="package-summary.html#Reduction">reduction</a> and is
      * equivalent to:
      * <pre>{@code
      *     return mapToLong(e -> 1L).sum();
@@ -520,7 +564,10 @@
      * Returns an {@code OptionalDouble} describing the arithmetic mean of elements of
      * this stream, or an empty optional if this stream is empty.  This is a
      * special case of a
-     * <a href="package-summary.html#MutableReduction">reduction</a>.
+     * <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
      *
      * @return an {@code OptionalDouble} containing the average element of this
      * stream, or an empty optional if the stream is empty
@@ -530,7 +577,10 @@
     /**
      * Returns an {@code IntSummaryStatistics} describing various
      * summary data about the elements of this stream.  This is a special
-     * case of a <a href="package-summary.html#MutableReduction">reduction</a>.
+     * case of a <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
      *
      * @return an {@code IntSummaryStatistics} describing various summary data
      * about the elements of this stream
@@ -587,9 +637,8 @@
 
     /**
      * Returns an {@link OptionalInt} describing the first element of this
-     * stream (in the encounter order), or an empty {@code OptionalInt} if the
-     * stream is empty.  If the stream has no encounter order, then any element
-     * may be returned.
+     * stream, or an empty {@code OptionalInt} if the stream is empty.  If the
+     * stream has no encounter order, then any element may be returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
      * terminal operation</a>.
@@ -609,8 +658,8 @@
      * <p>The behavior of this operation is explicitly nondeterministic; it is
      * free to select any element in the stream.  This is to allow for maximal
      * performance in parallel operations; the cost is that multiple invocations
-     * on the same source may not return the same result.  (If the first element
-     * in the encounter order is desired, use {@link #findFirst()} instead.)
+     * on the same source may not return the same result.  (If a stable result
+     * is desired, use {@link #findFirst()} instead.)
      *
      * @return an {@code OptionalInt} describing some element of this stream, or
      * an empty {@code OptionalInt} if the stream is empty
@@ -622,6 +671,9 @@
      * Returns a {@code LongStream} consisting of the elements of this stream,
      * converted to {@code long}.
      *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
      * @return a {@code LongStream} consisting of the elements of this stream,
      * converted to {@code long}
      */
@@ -631,6 +683,9 @@
      * Returns a {@code DoubleStream} consisting of the elements of this stream,
      * converted to {@code double}.
      *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
      * @return a {@code DoubleStream} consisting of the elements of this stream,
      * converted to {@code double}
      */
@@ -640,6 +695,9 @@
      * Returns a {@code Stream} consisting of the elements of this stream,
      * each boxed to an {@code Integer}.
      *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
      * @return a {@code Stream} consistent of the elements of this stream,
      * each boxed to an {@code Integer}
      */
@@ -688,7 +746,7 @@
     }
 
     /**
-     * Returns a sequential stream whose elements are the specified values.
+     * Returns a sequential ordered stream whose elements are the specified values.
      *
      * @param values the elements of the new stream
      * @return the new stream
@@ -698,7 +756,7 @@
     }
 
     /**
-     * Returns an infinite sequential {@code IntStream} produced by iterative
+     * Returns an infinite sequential ordered {@code IntStream} produced by iterative
      * application of a function {@code f} to an initial element {@code seed},
      * producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
      * {@code f(f(seed))}, etc.
@@ -736,8 +794,8 @@
     }
 
     /**
-     * Returns a sequential {@code IntStream} where each element is
-     * generated by an {@code IntSupplier}.  This is suitable for generating
+     * Returns a sequential stream where each element is generated by
+     * the provided {@code IntSupplier}.  This is suitable for generating
      * constant streams, streams of random elements, etc.
      *
      * @param s the {@code IntSupplier} for generated elements
@@ -750,7 +808,7 @@
     }
 
     /**
-     * Returns a sequential {@code IntStream} from {@code startInclusive}
+     * Returns a sequential ordered {@code IntStream} from {@code startInclusive}
      * (inclusive) to {@code endExclusive} (exclusive) by an incremental step of
      * {@code 1}.
      *
@@ -776,7 +834,7 @@
     }
 
     /**
-     * Returns a sequential {@code IntStream} from {@code startInclusive}
+     * Returns a sequential ordered {@code IntStream} from {@code startInclusive}
      * (inclusive) to {@code endInclusive} (inclusive) by an incremental step of
      * {@code 1}.
      *
@@ -802,15 +860,16 @@
     }
 
     /**
-     * Creates a lazy concatenated {@code IntStream} whose elements are all the
-     * elements of a first {@code IntStream} succeeded by all the elements of the
-     * second {@code IntStream}. The resulting stream is ordered if both
+     * Creates a lazily concatenated stream whose elements are all the
+     * elements of the first stream followed by all the elements of the
+     * second stream. The resulting stream is ordered if both
      * of the input streams are ordered, and parallel if either of the input
-     * streams is parallel.
+     * streams is parallel.  When the resulting stream is closed, the close
+     * handlers for both input streams are invoked.
      *
      * @param a the first stream
-     * @param b the second stream to concatenate on to end of the first stream
-     * @return the concatenation of the two streams
+     * @param b the second stream
+     * @return the concatenation of the two input streams
      */
     public static IntStream concat(IntStream a, IntStream b) {
         Objects.requireNonNull(a);
@@ -818,15 +877,16 @@
 
         Spliterator.OfInt split = new Streams.ConcatSpliterator.OfInt(
                 a.spliterator(), b.spliterator());
-        return StreamSupport.intStream(split, a.isParallel() || b.isParallel());
+        IntStream stream = StreamSupport.intStream(split, a.isParallel() || b.isParallel());
+        return stream.onClose(Streams.composedClose(a, b));
     }
 
     /**
      * A mutable builder for an {@code IntStream}.
      *
-     * <p>A stream builder has a lifecycle, where it starts in a building
-     * phase, during which elements can be added, and then transitions to a
-     * built phase, after which elements may not be added.  The built phase
+     * <p>A stream builder has a lifecycle, which starts in a building
+     * phase, during which elements can be added, and then transitions to a built
+     * phase, after which elements may not be added.  The built phase
      * begins when the {@link #build()} method is called, which creates an
      * ordered stream whose elements are the elements that were added to the
      * stream builder, in the order they were added.
--- a/jdk/src/share/classes/java/util/stream/LongPipeline.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/stream/LongPipeline.java	Wed Jul 05 19:11:53 2017 +0200
@@ -283,10 +283,11 @@
 
                     @Override
                     public void accept(long t) {
-                        // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
-                        LongStream result = mapper.apply(t);
-                        if (result != null)
-                            result.sequential().forEach(i -> downstream.accept(i));
+                        try (LongStream result = mapper.apply(t)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(i -> downstream.accept(i));
+                        }
                     }
                 };
             }
@@ -329,8 +330,8 @@
     }
 
     @Override
-    public final LongStream peek(LongConsumer consumer) {
-        Objects.requireNonNull(consumer);
+    public final LongStream peek(LongConsumer action) {
+        Objects.requireNonNull(action);
         return new StatelessOp<Long>(this, StreamShape.LONG_VALUE,
                                      0) {
             @Override
@@ -338,7 +339,7 @@
                 return new Sink.ChainedLong<Long>(sink) {
                     @Override
                     public void accept(long t) {
-                        consumer.accept(t);
+                        action.accept(t);
                         downstream.accept(t);
                     }
                 };
@@ -454,14 +455,14 @@
     }
 
     @Override
-    public final <R> R collect(Supplier<R> resultFactory,
+    public final <R> R collect(Supplier<R> supplier,
                                ObjLongConsumer<R> accumulator,
                                BiConsumer<R, R> combiner) {
         BinaryOperator<R> operator = (left, right) -> {
             combiner.accept(left, right);
             return left;
         };
-        return evaluate(ReduceOps.makeLong(resultFactory, accumulator, operator));
+        return evaluate(ReduceOps.makeLong(supplier, accumulator, operator));
     }
 
     @Override
--- a/jdk/src/share/classes/java/util/stream/LongStream.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/stream/LongStream.java	Wed Jul 05 19:11:53 2017 +0200
@@ -24,7 +24,11 @@
  */
 package java.util.stream;
 
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.LongSummaryStatistics;
 import java.util.Objects;
 import java.util.OptionalDouble;
@@ -32,6 +36,7 @@
 import java.util.PrimitiveIterator;
 import java.util.Spliterator;
 import java.util.Spliterators;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.BiConsumer;
 import java.util.function.Function;
 import java.util.function.LongBinaryOperator;
@@ -46,40 +51,87 @@
 import java.util.function.Supplier;
 
 /**
- * A sequence of primitive long elements supporting sequential and parallel
- * bulk operations. Streams support lazy intermediate operations (transforming
- * a stream to another stream) such as {@code filter} and {@code map}, and terminal
- * operations (consuming the contents of a stream to produce a result or
- * side-effect), such as {@code forEach}, {@code findFirst}, and {@code
- * iterator}.  Once an operation has been performed on a stream, it
- * is considered <em>consumed</em> and no longer usable for other operations.
+ * A sequence of elements supporting sequential and parallel aggregate
+ * operations.  The following example illustrates an aggregate operation using
+ * {@link Stream} and {@link LongStream}:
+ *
+ * <pre>{@code
+ *     long sum = widgets.stream()
+ *                       .filter(w -> w.getColor() == RED)
+ *                       .mapToLong(w -> w.getWeight())
+ *                       .sum();
+ * }</pre>
+ *
+ * In this example, {@code widgets} is a {@code Collection<Widget>}.  We create
+ * a stream of {@code Widget} objects via {@link Collection#stream Collection.stream()},
+ * filter it to produce a stream containing only the red widgets, and then
+ * transform it into a stream of {@code long} values representing the weight of
+ * each red widget. Then this stream is summed to produce a total weight.
  *
- * <p>For sequential stream pipelines, all operations are performed in the
- * <a href="package-summary.html#Ordering">encounter order</a> of the pipeline
- * source, if the pipeline source has a defined encounter order.
+ * <p>To perform a computation, stream
+ * <a href="package-summary.html#StreamOps">operations</a> are composed into a
+ * <em>stream pipeline</em>.  A stream pipeline consists of a source (which
+ * might be an array, a collection, a generator function, an IO channel,
+ * etc), zero or more <em>intermediate operations</em> (which transform a
+ * stream into another stream, such as {@link LongStream#filter(LongPredicate)}), and a
+ * <em>terminal operation</em> (which produces a result or side-effect, such
+ * as {@link LongStream#sum()} or {@link LongStream#forEach(LongConsumer)}).
+ * Streams are lazy; computation on the source data is only performed when the
+ * terminal operation is initiated, and source elements are consumed only
+ * as needed.
+ *
+ * <p>Collections and streams, while bearing some superficial similarities,
+ * have different goals.  Collections are primarily concerned with the efficient
+ * management of, and access to, their elements.  By contrast, streams do not
+ * provide a means to directly access or manipulate their elements, and are
+ * instead concerned with declaratively describing their source and the
+ * computational operations which will be performed in aggregate on that source.
+ * However, if the provided stream operations do not offer the desired
+ * functionality, the {@link #iterator()} and {@link #spliterator()} operations
+ * can be used to perform a controlled traversal.
  *
- * <p>For parallel stream pipelines, unless otherwise specified, intermediate
- * stream operations preserve the <a href="package-summary.html#Ordering">
- * encounter order</a> of their source, and terminal operations
- * respect the encounter order of their source, if the source
- * has an encounter order.  Provided that and parameters to stream operations
- * satisfy the <a href="package-summary.html#NonInterference">non-interference
- * requirements</a>, and excepting differences arising from the absence of
- * a defined encounter order, the result of a stream pipeline should be the
- * stable across multiple executions of the same operations on the same source.
- * However, the timing and thread in which side-effects occur (for those
- * operations which are allowed to produce side-effects, such as
- * {@link #forEach(LongConsumer)}), are explicitly nondeterministic for parallel
- * execution of stream pipelines.
+ * <p>A stream pipeline, like the "widgets" example above, can be viewed as
+ * a <em>query</em> on the stream source.  Unless the source was explicitly
+ * designed for concurrent modification (such as a {@link ConcurrentHashMap}),
+ * unpredictable or erroneous behavior may result from modifying the stream
+ * source while it is being queried.
+ *
+ * <p>Most stream operations accept parameters that describe user-specified
+ * behavior, such as the lambda expression {@code w -> w.getWeight()} passed to
+ * {@code mapToLong} in the example above.  Such parameters are always instances
+ * of a <a href="../function/package-summary.html">functional interface</a> such
+ * as {@link java.util.function.Function}, and are often lambda expressions or
+ * method references.  These parameters can never be null, should not modify the
+ * stream source, and should be
+ * <a href="package-summary.html#NonInterference">effectively stateless</a>
+ * (their result should not depend on any state that might change during
+ * execution of the stream pipeline.)
  *
- * <p>Unless otherwise noted, passing a {@code null} argument to any stream
- * method may result in a {@link NullPointerException}.
+ * <p>A stream should be operated on (invoking an intermediate or terminal stream
+ * operation) only once.  This rules out, for example, "forked" streams, where
+ * the same source feeds two or more pipelines, or multiple traversals of the
+ * same stream.  A stream implementation may throw {@link IllegalStateException}
+ * if it detects that the stream is being reused. However, since some stream
+ * operations may return their receiver rather than a new stream object, it may
+ * not be possible to detect reuse in all cases.
  *
- * @apiNote
- * Streams are not data structures; they do not manage the storage for their
- * elements, nor do they support access to individual elements.  However,
- * you can use the {@link #iterator()} or {@link #spliterator()} operations to
- * perform a controlled traversal.
+ * <p>Streams have a {@link #close()} method and implement {@link AutoCloseable},
+ * but nearly all stream instances do not actually need to be closed after use.
+ * Generally, only streams whose source is an IO channel (such as those returned
+ * by {@link Files#lines(Path, Charset)}) will require closing.  Most streams
+ * are backed by collections, arrays, or generating functions, which require no
+ * special resource management.  (If a stream does require closing, it can be
+ * declared as a resource in a {@code try}-with-resources statement.)
+ *
+ * <p>Stream pipelines may execute either sequentially or in
+ * <a href="package-summary.html#Parallelism">parallel</a>.  This
+ * execution mode is a property of the stream.  Streams are created
+ * with an initial choice of sequential or parallel execution.  (For example,
+ * {@link Collection#stream() Collection.stream()} creates a sequential stream,
+ * and {@link Collection#parallelStream() Collection.parallelStream()} creates
+ * a parallel one.)  This choice of execution mode may be modified by the
+ * {@link #sequential()} or {@link #parallel()} methods, and may be queried with
+ * the {@link #isParallel()} method.
  *
  * @since 1.8
  * @see <a href="package-summary.html">java.util.stream</a>
@@ -160,22 +212,13 @@
     /**
      * Returns a stream consisting of the results of replacing each element of
      * this stream with the contents of the stream produced by applying the
-     * provided mapping function to each element.
+     * provided mapping function to each element.  (If the result of the mapping
+     * function is {@code null}, this is treated as if the result was an empty
+     * stream.)
      *
      * <p>This is an <a href="package-summary.html#StreamOps">intermediate
      * operation</a>.
      *
-     * @apiNote
-     * The {@code flatMap()} operation has the effect of applying a one-to-many
-     * tranformation to the elements of the stream, and then flattening the
-     * resulting elements into a new stream. For example, if {@code orders}
-     * is a stream of purchase orders, and each purchase order contains a
-     * collection of line items, then the following produces a stream of line
-     * items:
-     * <pre>{@code
-     *     orderStream.flatMap(order -> order.getLineItems().stream())...
-     * }</pre>
-     *
      * @param mapper a <a href="package-summary.html#NonInterference">
      *               non-interfering, stateless</a> function to apply to
      *               each element which produces an {@code LongStream} of new
@@ -224,18 +267,18 @@
      * <pre>{@code
      *     list.stream()
      *         .filter(filteringFunction)
-     *         .peek(e -> {System.out.println("Filtered value: " + e); });
+     *         .peek(e -> System.out.println("Filtered value: " + e));
      *         .map(mappingFunction)
-     *         .peek(e -> {System.out.println("Mapped value: " + e); });
+     *         .peek(e -> System.out.println("Mapped value: " + e));
      *         .collect(Collectors.toLongSummaryStastistics());
      * }</pre>
      *
-     * @param consumer a <a href="package-summary.html#NonInterference">
-     *                 non-interfering</a> action to perform on the elements as
-     *                 they are consumed from the stream
+     * @param action a <a href="package-summary.html#NonInterference">
+     *               non-interfering</a> action to perform on the elements as
+     *               they are consumed from the stream
      * @return the new stream
      */
-    LongStream peek(LongConsumer consumer);
+    LongStream peek(LongConsumer action);
 
     /**
      * Returns a stream consisting of the elements of this stream, truncated
@@ -252,8 +295,8 @@
 
     /**
      * Returns a stream consisting of the remaining elements of this stream
-     * after indexing {@code startInclusive} elements into the stream. If the
-     * {@code startInclusive} index lies past the end of this stream then an
+     * after discarding the first {@code startInclusive} elements of the stream.
+     * If this stream contains fewer than {@code startInclusive} elements then an
      * empty stream will be returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">stateful
@@ -267,10 +310,10 @@
 
     /**
      * Returns a stream consisting of the remaining elements of this stream
-     * after indexing {@code startInclusive} elements into the stream and
-     * truncated to contain no more than {@code endExclusive - startInclusive}
-     * elements. If the {@code startInclusive} index lies past the end
-     * of this stream then an empty stream will be returned.
+     * after discarding the first {@code startInclusive} elements and truncating
+     * the result to be no longer than {@code endExclusive - startInclusive}
+     * elements in length. If this stream contains fewer than
+     * {@code startInclusive} elements then an empty stream will be returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
      * stateful intermediate operation</a>.
@@ -419,12 +462,12 @@
     /**
      * Performs a <a href="package-summary.html#MutableReduction">mutable
      * reduction</a> operation on the elements of this stream.  A mutable
-     * reduction is one in which the reduced value is a mutable value holder,
+     * reduction is one in which the reduced value is a mutable result container,
      * such as an {@code ArrayList}, and elements are incorporated by updating
-     * the state of the result, rather than by replacing the result.  This
+     * the state of the result rather than by replacing the result.  This
      * produces a result equivalent to:
      * <pre>{@code
-     *     R result = resultFactory.get();
+     *     R result = supplier.get();
      *     for (long element : this stream)
      *         accumulator.accept(result, element);
      *     return result;
@@ -437,10 +480,9 @@
      * operation</a>.
      *
      * @param <R> type of the result
-     * @param resultFactory a function that creates a new result container.
-     *                      For a parallel execution, this function may be
-     *                      called multiple times and must return a fresh value
-     *                      each time.
+     * @param supplier a function that creates a new result container. For a
+     *                 parallel execution, this function may be called
+     *                 multiple times and must return a fresh value each time.
      * @param accumulator an <a href="package-summary.html#Associativity">associative</a>
      *                    <a href="package-summary.html#NonInterference">non-interfering,
      *                    stateless</a> function for incorporating an additional
@@ -452,18 +494,21 @@
      * @return the result of the reduction
      * @see Stream#collect(Supplier, BiConsumer, BiConsumer)
      */
-    <R> R collect(Supplier<R> resultFactory,
+    <R> R collect(Supplier<R> supplier,
                   ObjLongConsumer<R> accumulator,
                   BiConsumer<R, R> combiner);
 
     /**
      * Returns the sum of elements in this stream.  This is a special case
-     * of a <a href="package-summary.html#MutableReduction">reduction</a>
+     * of a <a href="package-summary.html#Reduction">reduction</a>
      * and is equivalent to:
      * <pre>{@code
      *     return reduce(0, Long::sum);
      * }</pre>
      *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
+     *
      * @return the sum of elements in this stream
      */
     long sum();
@@ -471,7 +516,7 @@
     /**
      * Returns an {@code OptionalLong} describing the minimum element of this
      * stream, or an empty optional if this stream is empty.  This is a special
-     * case of a <a href="package-summary.html#MutableReduction">reduction</a>
+     * case of a <a href="package-summary.html#Reduction">reduction</a>
      * and is equivalent to:
      * <pre>{@code
      *     return reduce(Long::min);
@@ -479,7 +524,6 @@
      *
      * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
      *
-
      * @return an {@code OptionalLong} containing the minimum element of this
      * stream, or an empty {@code OptionalLong} if the stream is empty
      */
@@ -488,7 +532,7 @@
     /**
      * Returns an {@code OptionalLong} describing the maximum element of this
      * stream, or an empty optional if this stream is empty.  This is a special
-     * case of a <a href="package-summary.html#MutableReduction">reduction</a>
+     * case of a <a href="package-summary.html#Reduction">reduction</a>
      * and is equivalent to:
      * <pre>{@code
      *     return reduce(Long::max);
@@ -504,7 +548,7 @@
 
     /**
      * Returns the count of elements in this stream.  This is a special case of
-     * a <a href="package-summary.html#MutableReduction">reduction</a> and is
+     * a <a href="package-summary.html#Reduction">reduction</a> and is
      * equivalent to:
      * <pre>{@code
      *     return map(e -> 1L).sum();
@@ -520,7 +564,10 @@
      * Returns an {@code OptionalDouble} describing the arithmetic mean of elements of
      * this stream, or an empty optional if this stream is empty.  This is a
      * special case of a
-     * <a href="package-summary.html#MutableReduction">reduction</a>.
+     * <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
      *
      * @return an {@code OptionalDouble} containing the average element of this
      * stream, or an empty optional if the stream is empty
@@ -530,7 +577,10 @@
     /**
      * Returns a {@code LongSummaryStatistics} describing various summary data
      * about the elements of this stream.  This is a special case of a
-     * <a href="package-summary.html#MutableReduction">reduction</a>.
+     * <a href="package-summary.html#Reduction">reduction</a>.
+     *
+     * <p>This is a <a href="package-summary.html#StreamOps">terminal
+     * operation</a>.
      *
      * @return a {@code LongSummaryStatistics} describing various summary data
      * about the elements of this stream
@@ -587,9 +637,8 @@
 
     /**
      * Returns an {@link OptionalLong} describing the first element of this
-     * stream (in the encounter order), or an empty {@code OptionalLong} if the
-     * stream is empty.  If the stream has no encounter order, then any element
-     * may be returned.
+     * stream, or an empty {@code OptionalLong} if the stream is empty.  If the
+     * stream has no encounter order, then any element may be returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
      * terminal operation</a>.
@@ -609,8 +658,8 @@
      * <p>The behavior of this operation is explicitly nondeterministic; it is
      * free to select any element in the stream.  This is to allow for maximal
      * performance in parallel operations; the cost is that multiple invocations
-     * on the same source may not return the same result.  (If the first element
-     * in the encounter order is desired, use {@link #findFirst()} instead.)
+     * on the same source may not return the same result.  (If a stable result
+     * is desired, use {@link #findFirst()} instead.)
      *
      * @return an {@code OptionalLong} describing some element of this stream,
      * or an empty {@code OptionalLong} if the stream is empty
@@ -622,6 +671,9 @@
      * Returns a {@code DoubleStream} consisting of the elements of this stream,
      * converted to {@code double}.
      *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
      * @return a {@code DoubleStream} consisting of the elements of this stream,
      * converted to {@code double}
      */
@@ -631,6 +683,9 @@
      * Returns a {@code Stream} consisting of the elements of this stream,
      * each boxed to a {@code Long}.
      *
+     * <p>This is an <a href="package-summary.html#StreamOps">intermediate
+     * operation</a>.
+     *
      * @return a {@code Stream} consistent of the elements of this stream,
      * each boxed to {@code Long}
      */
@@ -679,7 +734,7 @@
     }
 
     /**
-     * Returns a sequential stream whose elements are the specified values.
+     * Returns a sequential ordered stream whose elements are the specified values.
      *
      * @param values the elements of the new stream
      * @return the new stream
@@ -689,7 +744,7 @@
     }
 
     /**
-     * Returns an infinite sequential {@code LongStream} produced by iterative
+     * Returns an infinite sequential ordered {@code LongStream} produced by iterative
      * application of a function {@code f} to an initial element {@code seed},
      * producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
      * {@code f(f(seed))}, etc.
@@ -727,9 +782,9 @@
     }
 
     /**
-     * Returns a sequential {@code LongStream} where each element is generated
-     * by a {@code LongSupplier}.  This is suitable for generating constant
-     * streams, streams of random elements, etc.
+     * Returns a sequential stream where each element is generated by
+     * the provided {@code LongSupplier}.  This is suitable for generating
+     * constant streams, streams of random elements, etc.
      *
      * @param s the {@code LongSupplier} for generated elements
      * @return a new sequential {@code LongStream}
@@ -741,7 +796,7 @@
     }
 
     /**
-     * Returns a sequential {@code LongStream} from {@code startInclusive}
+     * Returns a sequential ordered {@code LongStream} from {@code startInclusive}
      * (inclusive) to {@code endExclusive} (exclusive) by an incremental step of
      * {@code 1}.
      *
@@ -774,7 +829,7 @@
     }
 
     /**
-     * Returns a sequential {@code LongStream} from {@code startInclusive}
+     * Returns a sequential ordered {@code LongStream} from {@code startInclusive}
      * (inclusive) to {@code endInclusive} (inclusive) by an incremental step of
      * {@code 1}.
      *
@@ -808,15 +863,16 @@
     }
 
     /**
-     * Creates a lazy concatenated {@code LongStream} whose elements are all the
-     * elements of a first {@code LongStream} succeeded by all the elements of the
-     * second {@code LongStream}. The resulting stream is ordered if both
+     * Creates a lazily concatenated stream whose elements are all the
+     * elements of the first stream followed by all the elements of the
+     * second stream. The resulting stream is ordered if both
      * of the input streams are ordered, and parallel if either of the input
-     * streams is parallel.
+     * streams is parallel.  When the resulting stream is closed, the close
+     * handlers for both input streams are invoked.
      *
      * @param a the first stream
-     * @param b the second stream to concatenate on to end of the first stream
-     * @return the concatenation of the two streams
+     * @param b the second stream
+     * @return the concatenation of the two input streams
      */
     public static LongStream concat(LongStream a, LongStream b) {
         Objects.requireNonNull(a);
@@ -824,15 +880,16 @@
 
         Spliterator.OfLong split = new Streams.ConcatSpliterator.OfLong(
                 a.spliterator(), b.spliterator());
-        return StreamSupport.longStream(split, a.isParallel() || b.isParallel());
+        LongStream stream = StreamSupport.longStream(split, a.isParallel() || b.isParallel());
+        return stream.onClose(Streams.composedClose(a, b));
     }
 
     /**
      * A mutable builder for a {@code LongStream}.
      *
-     * <p>A stream builder has a lifecycle, where it starts in a building
-     * phase, during which elements can be added, and then transitions to a
-     * built phase, after which elements may not be added.  The built phase
+     * <p>A stream builder has a lifecycle, which starts in a building
+     * phase, during which elements can be added, and then transitions to a built
+     * phase, after which elements may not be added.  The built phase begins
      * begins when the {@link #build()} method is called, which creates an
      * ordered stream whose elements are the elements that were added to the
      * stream builder, in the order they were added.
--- a/jdk/src/share/classes/java/util/stream/PipelineHelper.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/stream/PipelineHelper.java	Wed Jul 05 19:11:53 2017 +0200
@@ -28,7 +28,7 @@
 import java.util.function.IntFunction;
 
 /**
- * Helper class for executing <a href="package-summary.html#StreamPipelines">
+ * Helper class for executing <a href="package-summary.html#StreamOps">
  * stream pipelines</a>, capturing all of the information about a stream
  * pipeline (output shape, intermediate operations, stream flags, parallelism,
  * etc) in one place.
--- a/jdk/src/share/classes/java/util/stream/ReferencePipeline.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/stream/ReferencePipeline.java	Wed Jul 05 19:11:53 2017 +0200
@@ -264,10 +264,11 @@
 
                     @Override
                     public void accept(P_OUT u) {
-                        // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
-                        Stream<? extends R> result = mapper.apply(u);
-                        if (result != null)
-                            result.sequential().forEach(downstream);
+                        try (Stream<? extends R> result = mapper.apply(u)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(downstream);
+                        }
                     }
                 };
             }
@@ -291,10 +292,11 @@
 
                     @Override
                     public void accept(P_OUT u) {
-                        // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
-                        IntStream result = mapper.apply(u);
-                        if (result != null)
-                            result.sequential().forEach(downstreamAsInt);
+                        try (IntStream result = mapper.apply(u)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(downstreamAsInt);
+                        }
                     }
                 };
             }
@@ -318,10 +320,11 @@
 
                     @Override
                     public void accept(P_OUT u) {
-                        // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
-                        DoubleStream result = mapper.apply(u);
-                        if (result != null)
-                            result.sequential().forEach(downstreamAsDouble);
+                        try (DoubleStream result = mapper.apply(u)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(downstreamAsDouble);
+                        }
                     }
                 };
             }
@@ -345,10 +348,11 @@
 
                     @Override
                     public void accept(P_OUT u) {
-                        // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
-                        LongStream result = mapper.apply(u);
-                        if (result != null)
-                            result.sequential().forEach(downstreamAsLong);
+                        try (LongStream result = mapper.apply(u)) {
+                            // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
+                            if (result != null)
+                                result.sequential().forEach(downstreamAsLong);
+                        }
                     }
                 };
             }
@@ -356,8 +360,8 @@
     }
 
     @Override
-    public final Stream<P_OUT> peek(Consumer<? super P_OUT> tee) {
-        Objects.requireNonNull(tee);
+    public final Stream<P_OUT> peek(Consumer<? super P_OUT> action) {
+        Objects.requireNonNull(action);
         return new StatelessOp<P_OUT, P_OUT>(this, StreamShape.REFERENCE,
                                      0) {
             @Override
@@ -365,7 +369,7 @@
                 return new Sink.ChainedReference<P_OUT, P_OUT>(sink) {
                     @Override
                     public void accept(P_OUT u) {
-                        tee.accept(u);
+                        action.accept(u);
                         downstream.accept(u);
                     }
                 };
@@ -493,7 +497,7 @@
 
     @Override
     @SuppressWarnings("unchecked")
-    public final <R, A> R collect(Collector<? super P_OUT, A, ? extends R> collector) {
+    public final <R, A> R collect(Collector<? super P_OUT, A, R> collector) {
         A container;
         if (isParallel()
                 && (collector.characteristics().contains(Collector.Characteristics.CONCURRENT))
@@ -511,10 +515,10 @@
     }
 
     @Override
-    public final <R> R collect(Supplier<R> resultFactory,
+    public final <R> R collect(Supplier<R> supplier,
                                BiConsumer<R, ? super P_OUT> accumulator,
                                BiConsumer<R, R> combiner) {
-        return evaluate(ReduceOps.makeRef(resultFactory, accumulator, combiner));
+        return evaluate(ReduceOps.makeRef(supplier, accumulator, combiner));
     }
 
     @Override
--- a/jdk/src/share/classes/java/util/stream/Stream.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/stream/Stream.java	Wed Jul 05 19:11:53 2017 +0200
@@ -24,13 +24,18 @@
  */
 package java.util.stream;
 
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Spliterator;
 import java.util.Spliterators;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.BiConsumer;
 import java.util.function.BiFunction;
 import java.util.function.BinaryOperator;
@@ -44,51 +49,90 @@
 import java.util.function.ToLongFunction;
 import java.util.function.UnaryOperator;
 
-// @@@ Specification to-do list @@@
-// - Describe the difference between sequential and parallel streams
-// - More general information about reduce, better definitions for associativity, more description of
-//   how reduce employs parallelism, more examples
-// - Role of stream flags in various operations, specifically ordering
-//   - Whether each op preserves encounter order
-// @@@ Specification to-do list @@@
-
 /**
- * A sequence of elements supporting sequential and parallel bulk operations.
- * Streams support lazy intermediate operations (transforming a stream to
- * another stream) such as {@code filter} and {@code map}, and terminal
- * operations (consuming the contents of a stream to produce a result or
- * side-effect), such as {@code forEach}, {@code findFirst}, and {@code
- * iterator}.  Once an operation has been performed on a stream, it
- * is considered <em>consumed</em> and no longer usable for other operations.
+ * A sequence of elements supporting sequential and parallel aggregate
+ * operations.  The following example illustrates an aggregate operation using
+ * {@link Stream} and {@link IntStream}:
+ *
+ * <pre>{@code
+ *     int sum = widgets.stream()
+ *                      .filter(w -> w.getColor() == RED)
+ *                      .mapToInt(w -> w.getWeight())
+ *                      .sum();
+ * }</pre>
+ *
+ * In this example, {@code widgets} is a {@code Collection<Widget>}.  We create
+ * a stream of {@code Widget} objects via {@link Collection#stream Collection.stream()},
+ * filter it to produce a stream containing only the red widgets, and then
+ * transform it into a stream of {@code int} values representing the weight of
+ * each red widget. Then this stream is summed to produce a total weight.
  *
- * <p>For sequential stream pipelines, all operations are performed in the
- * <a href="package-summary.html#Ordering">encounter order</a> of the pipeline
- * source, if the pipeline source has a defined encounter order.
+ * <p>To perform a computation, stream
+ * <a href="package-summary.html#StreamOps">operations</a> are composed into a
+ * <em>stream pipeline</em>.  A stream pipeline consists of a source (which
+ * might be an array, a collection, a generator function, an I/O channel,
+ * etc), zero or more <em>intermediate operations</em> (which transform a
+ * stream into another stream, such as {@link Stream#filter(Predicate)}), and a
+ * <em>terminal operation</em> (which produces a result or side-effect, such
+ * as {@link Stream#count()} or {@link Stream#forEach(Consumer)}).
+ * Streams are lazy; computation on the source data is only performed when the
+ * terminal operation is initiated, and source elements are consumed only
+ * as needed.
+ *
+ * <p>Collections and streams, while bearing some superficial similarities,
+ * have different goals.  Collections are primarily concerned with the efficient
+ * management of, and access to, their elements.  By contrast, streams do not
+ * provide a means to directly access or manipulate their elements, and are
+ * instead concerned with declaratively describing their source and the
+ * computational operations which will be performed in aggregate on that source.
+ * However, if the provided stream operations do not offer the desired
+ * functionality, the {@link #iterator()} and {@link #spliterator()} operations
+ * can be used to perform a controlled traversal.
  *
- * <p>For parallel stream pipelines, unless otherwise specified, intermediate
- * stream operations preserve the <a href="package-summary.html#Ordering">
- * encounter order</a> of their source, and terminal operations
- * respect the encounter order of their source, if the source
- * has an encounter order.  Provided that and parameters to stream operations
- * satisfy the <a href="package-summary.html#NonInterference">non-interference
- * requirements</a>, and excepting differences arising from the absence of
- * a defined encounter order, the result of a stream pipeline should be the
- * stable across multiple executions of the same operations on the same source.
- * However, the timing and thread in which side-effects occur (for those
- * operations which are allowed to produce side-effects, such as
- * {@link #forEach(Consumer)}), are explicitly nondeterministic for parallel
- * execution of stream pipelines.
+ * <p>A stream pipeline, like the "widgets" example above, can be viewed as
+ * a <em>query</em> on the stream source.  Unless the source was explicitly
+ * designed for concurrent modification (such as a {@link ConcurrentHashMap}),
+ * unpredictable or erroneous behavior may result from modifying the stream
+ * source while it is being queried.
+ *
+ * <p>Most stream operations accept parameters that describe user-specified
+ * behavior, such as the lambda expression {@code w -> w.getWeight()} passed to
+ * {@code mapToInt} in the example above.  Such parameters are always instances
+ * of a <a href="../function/package-summary.html">functional interface</a> such
+ * as {@link java.util.function.Function}, and are often lambda expressions or
+ * method references.  These parameters can never be null, should not modify the
+ * stream source, and should be
+ * <a href="package-summary.html#NonInterference">effectively stateless</a>
+ * (their result should not depend on any state that might change during
+ * execution of the stream pipeline.)
  *
- * <p>Unless otherwise noted, passing a {@code null} argument to any stream
- * method may result in a {@link NullPointerException}.
+ * <p>A stream should be operated on (invoking an intermediate or terminal stream
+ * operation) only once.  This rules out, for example, "forked" streams, where
+ * the same source feeds two or more pipelines, or multiple traversals of the
+ * same stream.  A stream implementation may throw {@link IllegalStateException}
+ * if it detects that the stream is being reused. However, since some stream
+ * operations may return their receiver rather than a new stream object, it may
+ * not be possible to detect reuse in all cases.
  *
- * @apiNote
- * Streams are not data structures; they do not manage the storage for their
- * elements, nor do they support access to individual elements.  However,
- * you can use the {@link #iterator()} or {@link #spliterator()} operations to
- * perform a controlled traversal.
+ * <p>Streams have a {@link #close()} method and implement {@link AutoCloseable},
+ * but nearly all stream instances do not actually need to be closed after use.
+ * Generally, only streams whose source is an IO channel (such as those returned
+ * by {@link Files#lines(Path, Charset)}) will require closing.  Most streams
+ * are backed by collections, arrays, or generating functions, which require no
+ * special resource management.  (If a stream does require closing, it can be
+ * declared as a resource in a {@code try}-with-resources statement.)
  *
- * @param <T> type of elements
+ * <p>Stream pipelines may execute either sequentially or in
+ * <a href="package-summary.html#Parallelism">parallel</a>.  This
+ * execution mode is a property of the stream.  Streams are created
+ * with an initial choice of sequential or parallel execution.  (For example,
+ * {@link Collection#stream() Collection.stream()} creates a sequential stream,
+ * and {@link Collection#parallelStream() Collection.parallelStream()} creates
+ * a parallel one.)  This choice of execution mode may be modified by the
+ * {@link #sequential()} or {@link #parallel()} methods, and may be queried with
+ * the {@link #isParallel()} method.
+ *
+ * @param <T> the type of the stream elements
  * @since 1.8
  * @see <a href="package-summary.html">java.util.stream</a>
  */
@@ -168,9 +212,9 @@
     /**
      * Returns a stream consisting of the results of replacing each element of
      * this stream with the contents of the stream produced by applying the
-     * provided mapping function to each element.  If the result of the mapping
-     * function is {@code null}, this is treated as if the result is an empty
-     * stream.
+     * provided mapping function to each element.  (If the result of the mapping
+     * function is {@code null}, this is treated as if the result was an empty
+     * stream.)
      *
      * <p>This is an <a href="package-summary.html#StreamOps">intermediate
      * operation</a>.
@@ -197,9 +241,9 @@
     /**
      * Returns an {@code IntStream} consisting of the results of replacing each
      * element of this stream with the contents of the stream produced by
-     * applying the provided mapping function to each element.  If the result of
-     * the mapping function is {@code null}, this is treated as if the result is
-     * an empty stream.
+     * applying the provided mapping function to each element.  (If the result
+     * of the mapping function is {@code null}, this is treated as if the result
+     * was an empty stream.)
      *
      * <p>This is an <a href="package-summary.html#StreamOps">intermediate
      * operation</a>.
@@ -214,9 +258,9 @@
     /**
      * Returns a {@code LongStream} consisting of the results of replacing each
      * element of this stream with the contents of the stream produced
-     * by applying the provided mapping function to each element.  If the result
-     * of the mapping function is {@code null}, this is treated as if the
-     * result is an empty stream.
+     * by applying the provided mapping function to each element.  (If the result
+     * of the mapping function is {@code null}, this is treated as if the result
+     * was an empty stream.)
      *
      * <p>This is an <a href="package-summary.html#StreamOps">intermediate
      * operation</a>.
@@ -231,9 +275,9 @@
     /**
      * Returns a {@code DoubleStream} consisting of the results of replacing each
      * element of this stream with the contents of the stream produced
-     * by applying the provided mapping function to each element.  If the result
+     * by applying the provided mapping function to each element.  (If the result
      * of the mapping function is {@code null}, this is treated as if the result
-     * is an empty stream.
+     * was an empty stream.)
      *
      * <p>This is an <a href="package-summary.html#StreamOps">intermediate
      * operation</a>.
@@ -260,7 +304,7 @@
      * Returns a stream consisting of the elements of this stream, sorted
      * according to natural order.  If the elements of this stream are not
      * {@code Comparable}, a {@code java.lang.ClassCastException} may be thrown
-     * when the stream pipeline is executed.
+     * when the terminal operation is executed.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">stateful
      * intermediate operation</a>.
@@ -301,18 +345,18 @@
      * <pre>{@code
      *     list.stream()
      *         .filter(filteringFunction)
-     *         .peek(e -> {System.out.println("Filtered value: " + e); });
+     *         .peek(e -> System.out.println("Filtered value: " + e));
      *         .map(mappingFunction)
-     *         .peek(e -> {System.out.println("Mapped value: " + e); });
+     *         .peek(e -> System.out.println("Mapped value: " + e));
      *         .collect(Collectors.intoList());
      * }</pre>
      *
-     * @param consumer a <a href="package-summary.html#NonInterference">
+     * @param action a <a href="package-summary.html#NonInterference">
      *                 non-interfering</a> action to perform on the elements as
      *                 they are consumed from the stream
      * @return the new stream
      */
-    Stream<T> peek(Consumer<? super T> consumer);
+    Stream<T> peek(Consumer<? super T> action);
 
     /**
      * Returns a stream consisting of the elements of this stream, truncated
@@ -329,8 +373,8 @@
 
     /**
      * Returns a stream consisting of the remaining elements of this stream
-     * after indexing {@code startInclusive} elements into the stream. If the
-     * {@code startInclusive} index lies past the end of this stream then an
+     * after discarding the first {@code startInclusive} elements of the stream.
+     * If this stream contains fewer than {@code startInclusive} elements then an
      * empty stream will be returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">stateful
@@ -344,10 +388,10 @@
 
     /**
      * Returns a stream consisting of the remaining elements of this stream
-     * after indexing {@code startInclusive} elements into the stream and
-     * truncated to contain no more than {@code endExclusive - startInclusive}
-     * elements. If the {@code startInclusive} index lies past the end
-     * of this stream then an empty stream will be returned.
+     * after discarding the first {@code startInclusive} elements and truncating
+     * the result to be no longer than {@code endExclusive - startInclusive}
+     * elements in length. If this stream contains fewer than
+     * {@code startInclusive} elements then an empty stream will be returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
      * stateful intermediate operation</a>.
@@ -405,11 +449,23 @@
 
     /**
      * Returns an array containing the elements of this stream, using the
-     * provided {@code generator} function to allocate the returned array.
+     * provided {@code generator} function to allocate the returned array, as
+     * well as any additional arrays that might be required for a partitioned
+     * execution or for resizing.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">terminal
      * operation</a>.
      *
+     * @apiNote
+     * The generator function takes an integer, which is the size of the
+     * desired array, and produces an array of the desired size.  This can be
+     * concisely expressed with an array constructor reference:
+     * <pre>{@code
+     *     Person[] men = people.stream()
+     *                          .filter(p -> p.getGender() == MALE)
+     *                          .toArray(Person[]::new);
+     * }</pre>
+     *
      * @param <A> the element type of the resulting array
      * @param generator a function which produces a new array of the desired
      *                  type and the provided length
@@ -451,7 +507,7 @@
      *     Integer sum = integers.reduce(0, (a, b) -> a+b);
      * }</pre>
      *
-     * or more compactly:
+     * or:
      *
      * <pre>{@code
      *     Integer sum = integers.reduce(0, Integer::sum);
@@ -501,7 +557,8 @@
      * @param accumulator an <a href="package-summary.html#Associativity">associative</a>
      *                    <a href="package-summary.html#NonInterference">non-interfering,
      *                    stateless</a> function for combining two values
-     * @return the result of the reduction
+     * @return an {@link Optional} describing the result of the reduction
+     * @throws NullPointerException if the result of the reduction is null
      * @see #reduce(Object, BinaryOperator)
      * @see #min(java.util.Comparator)
      * @see #max(java.util.Comparator)
@@ -510,8 +567,8 @@
 
     /**
      * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
-     * elements of this stream, using the provided identity, accumulation
-     * function, and a combining functions.  This is equivalent to:
+     * elements of this stream, using the provided identity, accumulation and
+     * combining functions.  This is equivalent to:
      * <pre>{@code
      *     U result = identity;
      *     for (T element : this stream)
@@ -537,8 +594,8 @@
      * by an explicit combination of {@code map} and {@code reduce} operations.
      * The {@code accumulator} function acts as a fused mapper and accumulator,
      * which can sometimes be more efficient than separate mapping and reduction,
-     * such as in the case where knowing the previously reduced value allows you
-     * to avoid some computation.
+     * such as when knowing the previously reduced value allows you to avoid
+     * some computation.
      *
      * @param <U> The type of the result
      * @param identity the identity value for the combiner function
@@ -561,12 +618,12 @@
     /**
      * Performs a <a href="package-summary.html#MutableReduction">mutable
      * reduction</a> operation on the elements of this stream.  A mutable
-     * reduction is one in which the reduced value is a mutable value holder,
+     * reduction is one in which the reduced value is a mutable result container,
      * such as an {@code ArrayList}, and elements are incorporated by updating
-     * the state of the result, rather than by replacing the result.  This
+     * the state of the result rather than by replacing the result.  This
      * produces a result equivalent to:
      * <pre>{@code
-     *     R result = resultFactory.get();
+     *     R result = supplier.get();
      *     for (T element : this stream)
      *         accumulator.accept(result, element);
      *     return result;
@@ -579,10 +636,11 @@
      * operation</a>.
      *
      * @apiNote There are many existing classes in the JDK whose signatures are
-     * a good match for use as arguments to {@code collect()}.  For example,
-     * the following will accumulate strings into an ArrayList:
+     * well-suited for use with method references as arguments to {@code collect()}.
+     * For example, the following will accumulate strings into an {@code ArrayList}:
      * <pre>{@code
-     *     List<String> asList = stringStream.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
+     *     List<String> asList = stringStream.collect(ArrayList::new, ArrayList::add,
+     *                                                ArrayList::addAll);
      * }</pre>
      *
      * <p>The following will take a stream of strings and concatenates them into a
@@ -594,10 +652,9 @@
      * }</pre>
      *
      * @param <R> type of the result
-     * @param resultFactory a function that creates a new result container.
-     *                      For a parallel execution, this function may be
-     *                      called multiple times and must return a fresh value
-     *                      each time.
+     * @param supplier a function that creates a new result container. For a
+     *                 parallel execution, this function may be called
+     *                 multiple times and must return a fresh value each time.
      * @param accumulator an <a href="package-summary.html#Associativity">associative</a>
      *                    <a href="package-summary.html#NonInterference">non-interfering,
      *                    stateless</a> function for incorporating an additional
@@ -608,24 +665,24 @@
      *                 must be compatible with the accumulator function
      * @return the result of the reduction
      */
-    <R> R collect(Supplier<R> resultFactory,
+    <R> R collect(Supplier<R> supplier,
                   BiConsumer<R, ? super T> accumulator,
                   BiConsumer<R, R> combiner);
 
     /**
      * Performs a <a href="package-summary.html#MutableReduction">mutable
      * reduction</a> operation on the elements of this stream using a
-     * {@code Collector} object to describe the reduction.  A {@code Collector}
+     * {@code Collector}.  A {@code Collector}
      * encapsulates the functions used as arguments to
      * {@link #collect(Supplier, BiConsumer, BiConsumer)}, allowing for reuse of
-     * collection strategies, and composition of collect operations such as
+     * collection strategies and composition of collect operations such as
      * multiple-level grouping or partitioning.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">terminal
      * operation</a>.
      *
      * <p>When executed in parallel, multiple intermediate results may be
-     * instantiated, populated, and merged, so as to maintain isolation of
+     * instantiated, populated, and merged so as to maintain isolation of
      * mutable data structures.  Therefore, even when executed in parallel
      * with non-thread-safe data structures (such as {@code ArrayList}), no
      * additional synchronization is needed for a parallel reduction.
@@ -638,16 +695,16 @@
      *
      * <p>The following will classify {@code Person} objects by city:
      * <pre>{@code
-     *     Map<String, Collection<Person>> peopleByCity
-     *         = personStream.collect(Collectors.groupBy(Person::getCity));
+     *     Map<String, List<Person>> peopleByCity
+     *         = personStream.collect(Collectors.groupingBy(Person::getCity));
      * }</pre>
      *
      * <p>The following will classify {@code Person} objects by state and city,
      * cascading two {@code Collector}s together:
      * <pre>{@code
-     *     Map<String, Map<String, Collection<Person>>> peopleByStateAndCity
-     *         = personStream.collect(Collectors.groupBy(Person::getState,
-     *                                                   Collectors.groupBy(Person::getCity)));
+     *     Map<String, Map<String, List<Person>>> peopleByStateAndCity
+     *         = personStream.collect(Collectors.groupingBy(Person::getState,
+     *                                                      Collectors.groupingBy(Person::getCity)));
      * }</pre>
      *
      * @param <R> the type of the result
@@ -657,12 +714,12 @@
      * @see #collect(Supplier, BiConsumer, BiConsumer)
      * @see Collectors
      */
-    <R, A> R collect(Collector<? super T, A, ? extends R> collector);
+    <R, A> R collect(Collector<? super T, A, R> collector);
 
     /**
      * Returns the minimum element of this stream according to the provided
      * {@code Comparator}.  This is a special case of a
-     * <a href="package-summary.html#MutableReduction">reduction</a>.
+     * <a href="package-summary.html#Reduction">reduction</a>.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>.
      *
@@ -671,13 +728,14 @@
      *                   elements of this stream
      * @return an {@code Optional} describing the minimum element of this stream,
      * or an empty {@code Optional} if the stream is empty
+     * @throws NullPointerException if the minimum element is null
      */
     Optional<T> min(Comparator<? super T> comparator);
 
     /**
      * Returns the maximum element of this stream according to the provided
      * {@code Comparator}.  This is a special case of a
-     * <a href="package-summary.html#MutableReduction">reduction</a>.
+     * <a href="package-summary.html#Reduction">reduction</a>.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">terminal
      * operation</a>.
@@ -687,12 +745,13 @@
      *                   elements of this stream
      * @return an {@code Optional} describing the maximum element of this stream,
      * or an empty {@code Optional} if the stream is empty
+     * @throws NullPointerException if the maximum element is null
      */
     Optional<T> max(Comparator<? super T> comparator);
 
     /**
      * Returns the count of elements in this stream.  This is a special case of
-     * a <a href="package-summary.html#MutableReduction">reduction</a> and is
+     * a <a href="package-summary.html#Reduction">reduction</a> and is
      * equivalent to:
      * <pre>{@code
      *     return mapToLong(e -> 1L).sum();
@@ -753,10 +812,9 @@
     boolean noneMatch(Predicate<? super T> predicate);
 
     /**
-     * Returns an {@link Optional} describing the first element of this stream
-     * (in the encounter order), or an empty {@code Optional} if the stream is
-     * empty.  If the stream has no encounter order, then any element may be
-     * returned.
+     * Returns an {@link Optional} describing the first element of this stream,
+     * or an empty {@code Optional} if the stream is empty.  If the stream has
+     * no encounter order, then any element may be returned.
      *
      * <p>This is a <a href="package-summary.html#StreamOps">short-circuiting
      * terminal operation</a>.
@@ -777,8 +835,8 @@
      * <p>The behavior of this operation is explicitly nondeterministic; it is
      * free to select any element in the stream.  This is to allow for maximal
      * performance in parallel operations; the cost is that multiple invocations
-     * on the same source may not return the same result.  (If the first element
-     * in the encounter order is desired, use {@link #findFirst()} instead.)
+     * on the same source may not return the same result.  (If a stable result
+     * is desired, use {@link #findFirst()} instead.)
      *
      * @return an {@code Optional} describing some element of this stream, or an
      * empty {@code Optional} if the stream is empty
@@ -821,7 +879,7 @@
     }
 
     /**
-     * Returns a sequential stream whose elements are the specified values.
+     * Returns a sequential ordered stream whose elements are the specified values.
      *
      * @param <T> the type of stream elements
      * @param values the elements of the new stream
@@ -834,7 +892,7 @@
     }
 
     /**
-     * Returns an infinite sequential {@code Stream} produced by iterative
+     * Returns an infinite sequential ordered {@code Stream} produced by iterative
      * application of a function {@code f} to an initial element {@code seed},
      * producing a {@code Stream} consisting of {@code seed}, {@code f(seed)},
      * {@code f(f(seed))}, etc.
@@ -872,8 +930,8 @@
     }
 
     /**
-     * Returns a sequential {@code Stream} where each element is
-     * generated by a {@code Supplier}.  This is suitable for generating
+     * Returns a sequential stream where each element is generated by
+     * the provided {@code Supplier}.  This is suitable for generating
      * constant streams, streams of random elements, etc.
      *
      * @param <T> the type of stream elements
@@ -887,16 +945,16 @@
     }
 
     /**
-     * Creates a lazy concatenated {@code Stream} whose elements are all the
-     * elements of a first {@code Stream} succeeded by all the elements of the
-     * second {@code Stream}. The resulting stream is ordered if both
+     * Creates a lazily concatenated stream whose elements are all the
+     * elements of the first stream followed by all the elements of the
+     * second stream. The resulting stream is ordered if both
      * of the input streams are ordered, and parallel if either of the input
-     * streams is parallel.
+     * streams is parallel.  When the resulting stream is closed, the close
+     * handlers for both input streams are invoked.
      *
      * @param <T> The type of stream elements
      * @param a the first stream
-     * @param b the second stream to concatenate on to end of the first
-     *        stream
+     * @param b the second stream
      * @return the concatenation of the two input streams
      */
     public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {
@@ -906,7 +964,8 @@
         @SuppressWarnings("unchecked")
         Spliterator<T> split = new Streams.ConcatSpliterator.OfRef<>(
                 (Spliterator<T>) a.spliterator(), (Spliterator<T>) b.spliterator());
-        return StreamSupport.stream(split, a.isParallel() || b.isParallel());
+        Stream<T> stream = StreamSupport.stream(split, a.isParallel() || b.isParallel());
+        return stream.onClose(Streams.composedClose(a, b));
     }
 
     /**
@@ -915,7 +974,7 @@
      * {@code Builder} (without the copying overhead that comes from using
      * an {@code ArrayList} as a temporary buffer.)
      *
-     * <p>A {@code Stream.Builder} has a lifecycle, where it starts in a building
+     * <p>A stream builder has a lifecycle, which starts in a building
      * phase, during which elements can be added, and then transitions to a built
      * phase, after which elements may not be added.  The built phase begins
      * when the {@link #build()} method is called, which creates an ordered
--- a/jdk/src/share/classes/java/util/stream/StreamSpliterators.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/stream/StreamSpliterators.java	Wed Jul 05 19:11:53 2017 +0200
@@ -1456,4 +1456,5 @@
             }
         }
     }
-}
\ No newline at end of file
+}
+
--- a/jdk/src/share/classes/java/util/stream/StreamSupport.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/stream/StreamSupport.java	Wed Jul 05 19:11:53 2017 +0200
@@ -32,12 +32,8 @@
  * Low-level utility methods for creating and manipulating streams.
  *
  * <p>This class is mostly for library writers presenting stream views
- * of their data structures; most static stream methods for end users are in
- * {@link Streams}.
- *
- * <p>Unless otherwise stated, streams are created as sequential
- * streams.  A sequential stream can be transformed into a parallel stream by
- * calling the {@code parallel()} method on the created stream.
+ * of data structures; most static stream methods intended for end users are in
+ * the various {@code Stream} classes.
  *
  * @since 1.8
  */
@@ -80,7 +76,7 @@
      * {@code Supplier} of {@code Spliterator}.
      *
      * <p>The {@link Supplier#get()} method will be invoked on the supplier no
-     * more than once, and after the terminal operation of the stream pipeline
+     * more than once, and only after the terminal operation of the stream pipeline
      * commences.
      *
      * <p>For spliterators that report a characteristic of {@code IMMUTABLE}
@@ -88,7 +84,7 @@
      * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
      * more efficient to use {@link #stream(java.util.Spliterator, boolean)}
      * instead.
-     * The use of a {@code Supplier} in this form provides a level of
+     * <p>The use of a {@code Supplier} in this form provides a level of
      * indirection that reduces the scope of potential interference with the
      * source.  Since the supplier is only invoked after the terminal operation
      * commences, any modifications to the source up to the start of the
@@ -148,7 +144,7 @@
      * {@code Supplier} of {@code Spliterator.OfInt}.
      *
      * <p>The {@link Supplier#get()} method will be invoked on the supplier no
-     * more than once, and after the terminal operation of the stream pipeline
+     * more than once, and only after the terminal operation of the stream pipeline
      * commences.
      *
      * <p>For spliterators that report a characteristic of {@code IMMUTABLE}
@@ -156,7 +152,7 @@
      * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
      * more efficient to use {@link #intStream(java.util.Spliterator.OfInt, boolean)}
      * instead.
-     * The use of a {@code Supplier} in this form provides a level of
+     * <p>The use of a {@code Supplier} in this form provides a level of
      * indirection that reduces the scope of potential interference with the
      * source.  Since the supplier is only invoked after the terminal operation
      * commences, any modifications to the source up to the start of the
@@ -215,7 +211,7 @@
      * {@code Supplier} of {@code Spliterator.OfLong}.
      *
      * <p>The {@link Supplier#get()} method will be invoked on the supplier no
-     * more than once, and after the terminal operation of the stream pipeline
+     * more than once, and only after the terminal operation of the stream pipeline
      * commences.
      *
      * <p>For spliterators that report a characteristic of {@code IMMUTABLE}
@@ -223,7 +219,7 @@
      * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
      * more efficient to use {@link #longStream(java.util.Spliterator.OfLong, boolean)}
      * instead.
-     * The use of a {@code Supplier} in this form provides a level of
+     * <p>The use of a {@code Supplier} in this form provides a level of
      * indirection that reduces the scope of potential interference with the
      * source.  Since the supplier is only invoked after the terminal operation
      * commences, any modifications to the source up to the start of the
@@ -282,7 +278,7 @@
      * {@code Supplier} of {@code Spliterator.OfDouble}.
      *
      * <p>The {@link Supplier#get()} method will be invoked on the supplier no
-     * more than once, and after the terminal operation of the stream pipeline
+     * more than once, and only after the terminal operation of the stream pipeline
      * commences.
      *
      * <p>For spliterators that report a characteristic of {@code IMMUTABLE}
@@ -290,7 +286,7 @@
      * <a href="../Spliterator.html#binding">late-binding</a>, it is likely
      * more efficient to use {@link #doubleStream(java.util.Spliterator.OfDouble, boolean)}
      * instead.
-     * The use of a {@code Supplier} in this form provides a level of
+     * <p>The use of a {@code Supplier} in this form provides a level of
      * indirection that reduces the scope of potential interference with the
      * source.  Since the supplier is only invoked after the terminal operation
      * commences, any modifications to the source up to the start of the
--- a/jdk/src/share/classes/java/util/stream/Streams.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/stream/Streams.java	Wed Jul 05 19:11:53 2017 +0200
@@ -833,4 +833,61 @@
             }
         }
     }
+
+    /**
+     * Given two Runnables, return a Runnable that executes both in sequence,
+     * even if the first throws an exception, and if both throw exceptions, add
+     * any exceptions thrown by the second as suppressed exceptions of the first.
+     */
+    static Runnable composeWithExceptions(Runnable a, Runnable b) {
+        return new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    a.run();
+                }
+                catch (Throwable e1) {
+                    try {
+                        b.run();
+                    }
+                    catch (Throwable e2) {
+                        try {
+                            e1.addSuppressed(e2);
+                        } catch (Throwable ignore) {}
+                    }
+                    throw e1;
+                }
+                b.run();
+            }
+        };
+    }
+
+    /**
+     * Given two streams, return a Runnable that
+     * executes both of their {@link BaseStream#close} methods in sequence,
+     * even if the first throws an exception, and if both throw exceptions, add
+     * any exceptions thrown by the second as suppressed exceptions of the first.
+     */
+    static Runnable composedClose(BaseStream<?, ?> a, BaseStream<?, ?> b) {
+        return new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    a.close();
+                }
+                catch (Throwable e1) {
+                    try {
+                        b.close();
+                    }
+                    catch (Throwable e2) {
+                        try {
+                            e1.addSuppressed(e2);
+                        } catch (Throwable ignore) {}
+                    }
+                    throw e1;
+                }
+                b.close();
+            }
+        };
+    }
 }
--- a/jdk/src/share/classes/java/util/stream/package-info.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/stream/package-info.java	Wed Jul 05 19:11:53 2017 +0200
@@ -24,347 +24,485 @@
  */
 
 /**
- * <h1>java.util.stream</h1>
- *
- * Classes to support functional-style operations on streams of values, as in the following:
+ * Classes to support functional-style operations on streams of elements, such
+ * as map-reduce transformations on collections.  For example:
  *
  * <pre>{@code
- *     int sumOfWeights = blocks.stream().filter(b -> b.getColor() == RED)
- *                                       .mapToInt(b -> b.getWeight())
- *                                       .sum();
+ *     int sum = widgets.stream()
+ *                      .filter(b -> b.getColor() == RED)
+ *                      .mapToInt(b -> b.getWeight())
+ *                      .sum();
  * }</pre>
  *
- * <p>Here we use {@code blocks}, which might be a {@code Collection}, as a source for a stream,
- * and then perform a filter-map-reduce ({@code sum()} is an example of a <a href="package-summary.html#Reduction">reduction</a>
- * operation) on the stream to obtain the sum of the weights of the red blocks.
+ * <p>Here we use {@code widgets}, a {@code Collection<Widget>},
+ * as a source for a stream, and then perform a filter-map-reduce on the stream
+ * to obtain the sum of the weights of the red widgets.  (Summation is an
+ * example of a <a href="package-summary.html#Reduction">reduction</a>
+ * operation.)
  *
- * <p>The key abstraction used in this approach is {@link java.util.stream.Stream}, as well as its primitive
- * specializations {@link java.util.stream.IntStream}, {@link java.util.stream.LongStream},
- * and {@link java.util.stream.DoubleStream}.  Streams differ from Collections in several ways:
+ * <p>The key abstraction introduced in this package is <em>stream</em>.  The
+ * classes {@link java.util.stream.Stream}, {@link java.util.stream.IntStream},
+ * {@link java.util.stream.LongStream}, and {@link java.util.stream.DoubleStream}
+ * are streams over objects and the primitive {@code int}, {@code long} and
+ * {@code double} types.  Streams differ from collections in several ways:
  *
  * <ul>
- *     <li>No storage.  A stream is not a data structure that stores elements; instead, they
- *     carry values from a source (which could be a data structure, a generator, an IO channel, etc)
- *     through a pipeline of computational operations.</li>
- *     <li>Functional in nature.  An operation on a stream produces a result, but does not modify
- *     its underlying data source.  For example, filtering a {@code Stream} produces a new {@code Stream},
- *     rather than removing elements from the underlying source.</li>
- *     <li>Laziness-seeking.  Many stream operations, such as filtering, mapping, or duplicate removal,
- *     can be implemented lazily, exposing opportunities for optimization.  (For example, "find the first
- *     {@code String} matching a pattern" need not examine all the input strings.)  Stream operations
- *     are divided into intermediate ({@code Stream}-producing) operations and terminal (value-producing)
- *     operations; all intermediate operations are lazy.</li>
- *     <li>Possibly unbounded.  While collections have a finite size, streams need not.  Operations
- *     such as {@code limit(n)} or {@code findFirst()} can allow computations on infinite streams
- *     to complete in finite time.</li>
+ *     <li>No storage.  A stream is not a data structure that stores elements;
+ *     instead, it conveys elements from a source such as a data structure,
+ *     an array, a generator function, or an I/O channel, through a pipeline of
+ *     computational operations.</li>
+ *     <li>Functional in nature.  An operation on a stream produces a result,
+ *     but does not modify its source.  For example, filtering a {@code Stream}
+ *     obtained from a collection produces a new {@code Stream} without the
+ *     filtered elements, rather than removing elements from the source
+ *     collection.</li>
+ *     <li>Laziness-seeking.  Many stream operations, such as filtering, mapping,
+ *     or duplicate removal, can be implemented lazily, exposing opportunities
+ *     for optimization.  For example, "find the first {@code String} with
+ *     three consecutive vowels" need not examine all the input strings.
+ *     Stream operations are divided into intermediate ({@code Stream}-producing)
+ *     operations and terminal (value- or side-effect-producing) operations.
+ *     Intermediate operations are always lazy.</li>
+ *     <li>Possibly unbounded.  While collections have a finite size, streams
+ *     need not.  Short-circuiting operations such as {@code limit(n)} or
+ *     {@code findFirst()} can allow computations on infinite streams to
+ *     complete in finite time.</li>
+ *     <li>Consumable. The elements of a stream are only visited once during
+ *     the life of a stream. Like an {@link java.util.Iterator}, a new stream
+ *     must be generated to revisit the same elements of the source.
+ *     </li>
+ * </ul>
+ *
+ * Streams can be obtained in a number of ways. Some examples include:
+ * <ul>
+ *     <li>From a {@link java.util.Collection} via the {@code stream()} and
+ *     {@code parallelStream()} methods;</li>
+ *     <li>From an array via {@link java.util.Arrays#stream(Object[])};</li>
+ *     <li>From static factory methods on the stream classes, such as
+ *     {@link java.util.stream.Stream#of(Object[])},
+ *     {@link java.util.stream.IntStream#range(int, int)}
+ *     or {@link java.util.stream.Stream#iterate(Object, UnaryOperator)};</li>
+ *     <li>The lines of a file can be obtained from {@link java.io.BufferedReader#lines()};</li>
+ *     <li>Streams of file paths can be obtained from methods in {@link java.nio.file.Files};</li>
+ *     <li>Streams of random numbers can be obtained from {@link java.util.Random#ints()};</li>
+ *     <li>Numerous other stream-bearing methods in the JDK, including
+ *     {@link java.util.BitSet#stream()},
+ *     {@link java.util.regex.Pattern#splitAsStream(java.lang.CharSequence)},
+ *     and {@link java.util.jar.JarFile#stream()}.</li>
  * </ul>
  *
- * <h2><a name="StreamPipelines">Stream pipelines</a></h2>
+ * <p>Additional stream sources can be provided by third-party libraries using
+ * <a href="package-summary.html#StreamSources">these techniques</a>.
+ *
+ * <h2><a name="StreamOps">Stream operations and pipelines</a></h2>
  *
- * <p>Streams are used to create <em>pipelines</em> of <a href="package-summary.html#StreamOps">operations</a>.  A
- * complete stream pipeline has several components: a source (which may be a {@code Collection},
- * an array, a generator function, or an IO channel); zero or more <em>intermediate operations</em>
- * such as {@code Stream.filter} or {@code Stream.map}; and a <em>terminal operation</em> such
- * as {@code Stream.forEach} or {@code java.util.stream.Stream.reduce}.  Stream operations may take as parameters
- * <em>function values</em> (which are often lambda expressions, but could be method references
- * or objects) which parameterize the behavior of the operation, such as a {@code Predicate}
- * passed to the {@code Stream#filter} method.
+ * <p>Stream operations are divided into <em>intermediate</em> and
+ * <em>terminal</em> operations, and are combined to form <em>stream
+ * pipelines</em>.  A stream pipeline consists of a source (such as a
+ * {@code Collection}, an array, a generator function, or an I/O channel);
+ * followed by zero or more intermediate operations such as
+ * {@code Stream.filter} or {@code Stream.map}; and a terminal operation such
+ * as {@code Stream.forEach} or {@code Stream.reduce}.
  *
- * <p>Intermediate operations return a new {@code Stream}.  They are lazy; executing an
- * intermediate operation such as {@link java.util.stream.Stream#filter Stream.filter} does
- * not actually perform any filtering, instead creating a new {@code Stream} that, when
- * traversed, contains the elements of the initial {@code Stream} that match the
- * given {@code Predicate}.  Consuming elements from the  stream source does not
- * begin until the terminal operation is executed.
+ * <p>Intermediate operations return a new stream.  They are always
+ * <em>lazy</em>; executing an intermediate operation such as
+ * {@code filter()} does not actually perform any filtering, but instead
+ * creates a new stream that, when traversed, contains the elements of
+ * the initial stream that match the given predicate.  Traversal
+ * of the pipeline source does not begin until the terminal operation of the
+ * pipeline is executed.
  *
- * <p>Terminal operations consume the {@code Stream} and produce a result or a side-effect.
- * After a terminal operation is performed, the stream can no longer be used and you must
- * return to the data source, or select a new data source, to get a new stream. For example,
- * obtaining the sum of weights of all red blocks, and then of all blue blocks, requires a
- * filter-map-reduce on two different streams:
- * <pre>{@code
- *     int sumOfRedWeights  = blocks.stream().filter(b -> b.getColor() == RED)
- *                                           .mapToInt(b -> b.getWeight())
- *                                           .sum();
- *     int sumOfBlueWeights = blocks.stream().filter(b -> b.getColor() == BLUE)
- *                                           .mapToInt(b -> b.getWeight())
- *                                           .sum();
- * }</pre>
- *
- * <p>However, there are other techniques that allow you to obtain both results in a single
- * pass if multiple traversal is impractical or inefficient.  TODO provide link
+ * <p>Terminal operations, such as {@code Stream.forEach} or
+ * {@code IntStream.sum}, may traverse the stream to produce a result or a
+ * side-effect. After the terminal operation is performed, the stream pipeline
+ * is considered consumed, and can no longer be used; if you need to traverse
+ * the same data source again, you must return to the data source to get a new
+ * stream.  In almost all cases, terminal operations are <em>eager</em>,
+ * completing their traversal of the data source and processing of the pipeline
+ * before returning.  Only the terminal operations {@code iterator()} and
+ * {@code spliterator()} are not; these are provided as an "escape hatch" to enable
+ * arbitrary client-controlled pipeline traversals in the event that the
+ * existing operations are not sufficient to the task.
  *
- * <h3><a name="StreamOps">Stream operations</a></h3>
- *
- * <p>Intermediate stream operation (such as {@code filter} or {@code sorted}) always produce a
- * new {@code Stream}, and are always<em>lazy</em>.  Executing a lazy operations does not
- * trigger processing of the stream contents; all processing is deferred until the terminal
- * operation commences.  Processing streams lazily allows for significant efficiencies; in a
- * pipeline such as the filter-map-sum example above, filtering, mapping, and addition can be
- * fused into a single pass, with minimal intermediate state.  Laziness also enables us to avoid
- * examining all the data when it is not necessary; for operations such as "find the first
- * string longer than 1000 characters", one need not examine all the input strings, just enough
- * to find one that has the desired characteristics.  (This behavior becomes even more important
- * when the input stream is infinite and not merely large.)
+ * <p> Processing streams lazily allows for significant efficiencies; in a
+ * pipeline such as the filter-map-sum example above, filtering, mapping, and
+ * summing can be fused into a single pass on the data, with minimal
+ * intermediate state. Laziness also allows avoiding examining all the data
+ * when it is not necessary; for operations such as "find the first string
+ * longer than 1000 characters", it is only necessary to examine just enough
+ * strings to find one that has the desired characteristics without examining
+ * all of the strings available from the source. (This behavior becomes even
+ * more important when the input stream is infinite and not merely large.)
  *
- * <p>Intermediate operations are further divided into <em>stateless</em> and <em>stateful</em>
- * operations.  Stateless operations retain no state from previously seen values when processing
- * a new value; examples of stateless intermediate operations include {@code filter} and
- * {@code map}.  Stateful operations may incorporate state from previously seen elements in
- * processing new values; examples of stateful intermediate operations include {@code distinct}
- * and {@code sorted}.  Stateful operations may need to process the entire input before
- * producing a result; for example, one cannot produce any results from sorting a stream until
- * one has seen all elements of the stream.  As a result, under parallel computation, some
- * pipelines containing stateful intermediate operations have to be executed in multiple passes.
- * Pipelines containing exclusively stateless intermediate operations can be processed in a
- * single pass, whether sequential or parallel.
+ * <p>Intermediate operations are further divided into <em>stateless</em>
+ * and <em>stateful</em> operations. Stateless operations, such as {@code filter}
+ * and {@code map}, retain no state from previously seen element when processing
+ * a new element -- each element can be processed
+ * independently of operations on other elements.  Stateful operations, such as
+ * {@code distinct} and {@code sorted}, may incorporate state from previously
+ * seen elements when processing new elements.
  *
- * <p>Further, some operations are deemed <em>short-circuiting</em> operations.  An intermediate
- * operation is short-circuiting if, when presented with infinite input, it may produce a
- * finite stream as a result.  A terminal operation is short-circuiting if, when presented with
- * infinite input, it may terminate in finite time.  (Having a short-circuiting operation is a
- * necessary, but not sufficient, condition for the processing of an infinite stream to
- * terminate normally in finite time.)
+ * <p>Stateful operations may need to process the entire input
+ * before producing a result.  For example, one cannot produce any results from
+ * sorting a stream until one has seen all elements of the stream.  As a result,
+ * under parallel computation, some pipelines containing stateful intermediate
+ * operations may require multiple passes on the data or may need to buffer
+ * significant data.  Pipelines containing exclusively stateless intermediate
+ * operations can be processed in a single pass, whether sequential or parallel,
+ * with minimal data buffering.
  *
- * Terminal operations (such as {@code forEach} or {@code findFirst}) are always eager
- * (they execute completely before returning), and produce a non-{@code Stream} result, such
- * as a primitive value or a {@code Collection}, or have side-effects.
+ * <p>Further, some operations are deemed <em>short-circuiting</em> operations.
+ * An intermediate operation is short-circuiting if, when presented with
+ * infinite input, it may produce a finite stream as a result.  A terminal
+ * operation is short-circuiting if, when presented with infinite input, it may
+ * terminate in finite time.  Having a short-circuiting operation in the pipeline
+ * is a necessary, but not sufficient, condition for the processing of an infinite
+ * stream to terminate normally in finite time.
  *
  * <h3>Parallelism</h3>
  *
- * <p>By recasting aggregate operations as a pipeline of operations on a stream of values, many
- * aggregate operations can be more easily parallelized.  A {@code Stream} can execute either
- * in serial or in parallel.  When streams are created, they are either created as sequential
- * or parallel streams; the parallel-ness of streams can also be switched by the
- * {@link java.util.stream Stream#sequential()} and {@link java.util.stream.Stream#parallel()}
- * operations.  The {@code Stream} implementations in the JDK create serial streams unless
- * parallelism is explicitly requested.  For example, {@code Collection} has methods
+ * <p>Processing elements with an explicit {@code for-}loop is inherently serial.
+ * Streams facilitate parallel execution by reframing the computation as a pipeline of
+ * aggregate operations, rather than as imperative operations on each individual
+ * element.  All streams operations can execute either in serial or in parallel.
+ * The stream implementations in the JDK create serial streams unless parallelism is
+ * explicitly requested.  For example, {@code Collection} has methods
  * {@link java.util.Collection#stream} and {@link java.util.Collection#parallelStream},
- * which produce sequential and parallel streams respectively; other stream-bearing methods
- * such as {@link java.util.stream.IntStream#range(int, int)} produce sequential
- * streams but these can be efficiently parallelized by calling {@code parallel()} on the
- * result. The set of operations on serial and parallel streams is identical. To execute the
- * "sum of weights of blocks" query in parallel, we would do:
+ * which produce sequential and parallel streams respectively; other
+ * stream-bearing methods such as {@link java.util.stream.IntStream#range(int, int)}
+ * produce sequential streams but these streams can be efficiently parallelized by
+ * invoking their {@link java.util.stream.BaseStream#parallel()} method.
+ * To execute the prior "sum of weights of widgets" query in parallel, we would
+ * do:
  *
  * <pre>{@code
- *     int sumOfWeights = blocks.parallelStream().filter(b -> b.getColor() == RED)
- *                                               .mapToInt(b -> b.getWeight())
- *                                               .sum();
+ *     int sumOfWeights = widgets.}<code><b>parallelStream()</b></code>{@code
+ *                               .filter(b -> b.getColor() == RED)
+ *                               .mapToInt(b -> b.getWeight())
+ *                               .sum();
  * }</pre>
  *
- * <p>The only difference between the serial and parallel versions of this example code is
- * the creation of the initial {@code Stream}.  Whether a {@code Stream} will execute in serial
- * or parallel can be determined by the {@code Stream#isParallel} method.  When the terminal
- * operation is initiated, the entire stream pipeline is either executed sequentially or in
- * parallel, determined by the last operation that affected the stream's serial-parallel
- * orientation (which could be the stream source, or the {@code sequential()} or
- * {@code parallel()} methods.)
- *
- * <p>In order for the results of parallel operations to be deterministic and consistent with
- * their serial equivalent, the function values passed into the various stream operations should
- * be <a href="#NonInteference"><em>stateless</em></a>.
- *
- * <h3><a name="Ordering">Ordering</a></h3>
- *
- * <p>Streams may or may not have an <em>encounter order</em>.  An encounter
- * order specifies the order in which elements are provided by the stream to the
- * operations pipeline.  Whether or not there is an encounter order depends on
- * the source, the intermediate  operations, and the terminal operation.
- * Certain stream sources (such as {@code List} or arrays) are intrinsically
- * ordered, whereas others (such as {@code HashSet}) are not.  Some intermediate
- * operations may impose an encounter order on an otherwise unordered stream,
- * such as {@link java.util.stream.Stream#sorted()}, and others may render an
- * ordered stream unordered (such as {@link java.util.stream.Stream#unordered()}).
- * Some terminal operations may ignore encounter order, such as
- * {@link java.util.stream.Stream#forEach}.
+ * <p>The only difference between the serial and parallel versions of this
+ * example is the creation of the initial stream, using "{@code parallelStream()}"
+ * instead of "{@code stream()}".  When the terminal operation is initiated,
+ * the stream pipeline is executed sequentially or in parallel depending on the
+ * orientation of the stream on which it is invoked.  Whether a stream will execute in serial or
+ * parallel can be determined with the {@code isParallel()} method, and the
+ * orientation of a stream can be modified with the
+ * {@link java.util.stream.BaseStream#sequential()} and
+ * {@link java.util.stream.BaseStream#parallel()} operations.  When the terminal
+ * operation is initiated, the stream pipeline is executed sequentially or in
+ * parallel depending on the mode of the stream on which it is invoked.
  *
- * <p>If a Stream is ordered, most operations are constrained to operate on the
- * elements in their encounter order; if the source of a stream is a {@code List}
- * containing {@code [1, 2, 3]}, then the result of executing {@code map(x -> x*2)}
- * must be {@code [2, 4, 6]}.  However, if the source has no defined encounter
- * order, than any of the six permutations of the values {@code [2, 4, 6]} would
- * be a valid result. Many operations can still be efficiently parallelized even
- * under ordering constraints.
- *
- * <p>For sequential streams, ordering is only relevant to the determinism
- * of operations performed repeatedly on the same source.  (An {@code ArrayList}
- * is constrained to iterate elements in order; a {@code HashSet} is not, and
- * repeated iteration might produce a different order.)
+ * <p>Except for operations identified as explicitly nondeterministic, such
+ * as {@code findAny()}, whether a stream executes sequentially or in parallel
+ * should not change the result of the computation.
  *
- * <p>For parallel streams, relaxing the ordering constraint can enable
- * optimized implementation for some operations.  For example, duplicate
- * filtration on an ordered stream must completely process the first partition
- * before it can return any elements from a subsequent partition, even if those
- * elements are available earlier.  On the other hand, without the constraint of
- * ordering, duplicate filtration can be done more efficiently by using
- * a shared {@code ConcurrentHashSet}.  There will be cases where the stream
- * is structurally ordered (the source is ordered and the intermediate
- * operations are order-preserving), but the user does not particularly care
- * about the encounter order.  In some cases, explicitly de-ordering the stream
- * with the {@link java.util.stream.Stream#unordered()} method may result in
- * improved parallel performance for some stateful or terminal operations.
+ * <p>Most stream operations accept parameters that describe user-specified
+ * behavior, which are often lambda expressions.  To preserve correct behavior,
+ * these <em>behavioral parameters</em> must be <em>non-interfering</em>, and in
+ * most cases must be <em>stateless</em>.  Such parameters are always instances
+ * of a <a href="../function/package-summary.html">functional interface</a> such
+ * as {@link java.util.function.Function}, and are often lambda expressions or
+ * method references.
  *
  * <h3><a name="Non-Interference">Non-interference</a></h3>
  *
- * The {@code java.util.stream} package enables you to execute possibly-parallel
- * bulk-data operations over a variety of data sources, including even non-thread-safe
- * collections such as {@code ArrayList}.  This is possible only if we can
- * prevent <em>interference</em> with the data source during the execution of a
- * stream pipeline.  (Execution begins when the terminal operation is invoked, and ends
- * when the terminal operation completes.)  For most data sources, preventing interference
- * means ensuring that the data source is <em>not modified at all</em> during the execution
- * of the stream pipeline.  (Some data sources, such as concurrent collections, are
- * specifically designed to handle concurrent modification.)
+ * Streams enable you to execute possibly-parallel aggregate operations over a
+ * variety of data sources, including even non-thread-safe collections such as
+ * {@code ArrayList}. This is possible only if we can prevent
+ * <em>interference</em> with the data source during the execution of a stream
+ * pipeline.  Except for the escape-hatch operations {@code iterator()} and
+ * {@code spliterator()}, execution begins when the terminal operation is
+ * invoked, and ends when the terminal operation completes.  For most data
+ * sources, preventing interference means ensuring that the data source is
+ * <em>not modified at all</em> during the execution of the stream pipeline.
+ * The notable exception to this are streams whose sources are concurrent
+ * collections, which are specifically designed to handle concurrent modification.
  *
- * <p>Accordingly, lambda expressions (or other objects implementing the appropriate functional
- * interface) passed to stream methods should never modify the stream's data source.  An
- * implementation is said to <em>interfere</em> with the data source if it modifies, or causes
- * to be modified, the stream's data source.  The need for non-interference applies to all
- * pipelines, not just parallel ones.  Unless the stream source is concurrent, modifying a
- * stream's data source during execution of a stream pipeline can cause exceptions, incorrect
- * answers, or nonconformant results.
+ * <p>Accordingly, behavioral parameters passed to stream methods should never
+ * modify the stream's data source.  An implementation is said to
+ * <em>interfere</em> with the data source if it modifies, or causes to be
+ * modified, the stream's data source.  The need for non-interference applies
+ * to all pipelines, not just parallel ones.  Unless the stream source is
+ * concurrent, modifying a stream's data source during execution of a stream
+ * pipeline can cause exceptions, incorrect answers, or nonconformant behavior.
  *
- * <p>Further, results may be nondeterministic or incorrect if the lambda expressions passed to
- * stream operations are <em>stateful</em>.  A stateful lambda (or other object implementing the
- * appropriate functional interface) is one whose result depends on any state which might change
- * during the execution of the stream pipeline.  An example of a stateful lambda is:
+ * <p>Results may be nondeterministic or incorrect if the behavioral
+ * parameters of stream operations are <em>stateful</em>.  A stateful lambda
+ * (or other object implementing the appropriate functional interface) is one
+ * whose result depends on any state which might change during the execution
+ * of the stream pipeline.  An example of a stateful lambda is:
+ *
  * <pre>{@code
  *     Set<Integer> seen = Collections.synchronizedSet(new HashSet<>());
  *     stream.parallel().map(e -> { if (seen.add(e)) return 0; else return e; })...
  * }</pre>
- * Here, if the mapping operation is performed in parallel, the results for the same input
- * could vary from run to run, due to thread scheduling differences, whereas, with a stateless
- * lambda expression the results would always be the same.
+ *
+ * Here, if the mapping operation is performed in parallel, the results for the
+ * same input could vary from run to run, due to thread scheduling differences,
+ * whereas, with a stateless lambda expression the results would always be the
+ * same.
+ *
+ * For well-behaved stream sources, the source can be modified before the
+ * terminal operation commences and those modifications will be reflected in
+ * the covered elements.  For example, consider the following code:
+ *
+ * <pre>{@code
+ *     List<String> l = new ArrayList(Arrays.asList("one", "two"));
+ *     Stream<String> sl = l.stream();
+ *     l.add("three");
+ *     String s = sl.collect(joining(" "));
+ * }</pre>
+ *
+ * First a list is created consisting of two strings: "one"; and "two". Then a
+ * stream is created from that list. Next the list is modified by adding a third
+ * string: "three". Finally the elements of the stream are collected and joined
+ * together. Since the list was modified before the terminal {@code collect}
+ * operation commenced the result will be a string of "one two three". All the
+ * streams returned from JDK collections, and most other JDK classes,
+ * are well-behaved in this manner; for streams generated by other libraries, see
+ * <a href="package-summary.html#StreamSources">Low-level stream
+ * construction</a> for requirements for building well-behaved streams.
+ *
+ * <p>Some streams, particularly those whose stream sources are concurrent, can
+ * tolerate concurrent modification during execution of a stream pipeline.
+ * However, in no case -- even if the stream source is concurrent -- should
+ * behavioral parameters to stream operations modify the stream source.  Modifying
+ * the stream source from within the stream source may cause pipeline execution
+ * to fail to terminate, produce inaccurate results, or throw exceptions.
+ * The following example shows inappropriate interference with the source:
+ * <pre>{@code
+ *     // Don't do this!
+ *     List<String> l = new ArrayList(Arrays.asList("one", "two"));
+ *     Stream<String> sl = l.stream();
+ *     String s = sl.peek(s -> l.add("BAD LAMBDA")).collect(joining(" "));
+ * }</pre>
  *
  * <h3>Side-effects</h3>
  *
+ * Side-effects in behavioral parameters to stream operations are, in general,
+ * discouraged, as they can often lead to unwitting violations of the
+ * statelessness requirement, as well as other thread-safety hazards.  Many
+ * computations where one might be tempted to use side effects can be more
+ * safely and efficiently expressed without side-effects, such as using
+ * <a href="package-summary.html#Reduction">reduction</a> instead of mutable
+ * accumulators. However, side-effects such as using {@code println()} for debugging
+ * purposes are usually harmless.  A small number of stream operations, such as
+ * {@code forEach()} and {@code peek()}, can operate only via side-effects;
+ * these should be used with care.
+ *
+ * <p>As an example of how to transform a stream pipeline that inappropriately
+ * uses side-effects to one that does not, the following code searches a stream
+ * of strings for those matching a given regular expression, and puts the
+ * matches in a list.
+ *
+ * <pre>{@code
+ *     ArrayList<String> results = new ArrayList<>();
+ *     stream.filter(s -> pattern.matcher(s).matches())
+ *           .forEach(s -> results.add(s));  // Unnecessary use of side-effects!
+ * }</pre>
+ *
+ * This code unnecessarily uses side-effects.  If executed in parallel, the
+ * non-thread-safety of {@code ArrayList} would cause incorrect results, and
+ * adding needed synchronization would cause contention, undermining the
+ * benefit of parallelism.  Furthermore, using side-effects here is completely
+ * unnecessary; the {@code forEach()} can simply be replaced with a reduction
+ * operation that is safer, more efficient, and more amenable to
+ * parallelization:
+ *
+ * <pre>{@code
+ *     List<String>results =
+ *         stream.filter(s -> pattern.matcher(s).matches())
+ *               .collect(Collectors.toList());  // No side-effects!
+ * }</pre>
+ *
+ * <h3><a name="Ordering">Ordering</a></h3>
+ *
+ * <p>Streams may or may not have a defined <em>encounter order</em>.  Whether
+ * or not a stream has an encounter order depends on the source and the
+ * intermediate operations.  Certain stream sources (such as {@code List} or
+ * arrays) are intrinsically ordered, whereas others (such as {@code HashSet})
+ * are not.  Some intermediate operations, such as {@code sorted()}, may impose
+ * an encounter order on an otherwise unordered stream, and others may render an
+ * ordered stream unordered, such as {@link java.util.stream.BaseStream#unordered()}.
+ * Further, some terminal operations may ignore encounter order, such as
+ * {@code forEach()}.
+ *
+ * <p>If a stream is ordered, most operations are constrained to operate on the
+ * elements in their encounter order; if the source of a stream is a {@code List}
+ * containing {@code [1, 2, 3]}, then the result of executing {@code map(x -> x*2)}
+ * must be {@code [2, 4, 6]}.  However, if the source has no defined encounter
+ * order, then any permutation of the values {@code [2, 4, 6]} would be a valid
+ * result.
+ *
+ * <p>For sequential streams, the presence or absence of an encounter order does
+ * not affect performance, only determinism.  If a stream is ordered, repeated
+ * execution of identical stream pipelines on an identical source will produce
+ * an identical result; if it is not ordered, repeated execution might produce
+ * different results.
+ *
+ * <p>For parallel streams, relaxing the ordering constraint can sometimes enable
+ * more efficient execution.  Certain aggregate operations,
+ * such as filtering duplicates ({@code distinct()}) or grouped reductions
+ * ({@code Collectors.groupingBy()}) can be implemented more efficiently if ordering of elements
+ * is not relevant.  Similarly, operations that are intrinsically tied to encounter order,
+ * such as {@code limit()}, may require
+ * buffering to ensure proper ordering, undermining the benefit of parallelism.
+ * In cases where the stream has an encounter order, but the user does not
+ * particularly <em>care</em> about that encounter order, explicitly de-ordering
+ * the stream with {@link java.util.stream.BaseStream#unordered() unordered()} may
+ * improve parallel performance for some stateful or terminal operations.
+ * However, most stream pipelines, such as the "sum of weight of blocks" example
+ * above, still parallelize efficiently even under ordering constraints.
+ *
  * <h2><a name="Reduction">Reduction operations</a></h2>
  *
- * A <em>reduction</em> operation takes a stream of elements and processes them in a way
- * that reduces to a single value or summary description, such as finding the sum or maximum
- * of a set of numbers.  (In more complex scenarios, the reduction operation might need to
- * extract data from the elements before reducing that data to a single value, such as
- * finding the sum of weights of a set of blocks.  This would require extracting the weight
- * from each block before summing up the weights.)
+ * A <em>reduction</em> operation (also called a <em>fold</em>) takes a sequence
+ * of input elements and combines them into a single summary result by repeated
+ * application of a combining operation, such as finding the sum or maximum of
+ * a set of numbers, or accumulating elements into a list.  The streams classes have
+ * multiple forms of general reduction operations, called
+ * {@link java.util.stream.Stream#reduce(java.util.function.BinaryOperator) reduce()}
+ * and {@link java.util.stream.Stream#collect(java.util.stream.Collector) collect()},
+ * as well as multiple specialized reduction forms such as
+ * {@link java.util.stream.IntStream#sum() sum()}, {@link java.util.stream.IntStream#max() max()},
+ * or {@link java.util.stream.IntStream#count() count()}.
  *
- * <p>Of course, such operations can be readily implemented as simple sequential loops, as in:
+ * <p>Of course, such operations can be readily implemented as simple sequential
+ * loops, as in:
  * <pre>{@code
  *    int sum = 0;
  *    for (int x : numbers) {
  *       sum += x;
  *    }
  * }</pre>
- * However, there may be a significant advantage to preferring a {@link java.util.stream.Stream#reduce reduce operation}
- * over a mutative accumulation such as the above -- a properly constructed reduce operation is
- * inherently parallelizable so long as the
- * {@link java.util.function.BinaryOperator reduction operaterator}
- * has the right characteristics. Specifically the operator must be
- * <a href="#Associativity">associative</a>.  For example, given a
- * stream of numbers for which we want to find the sum, we can write:
+ * However, there are good reasons to prefer a reduce operation
+ * over a mutative accumulation such as the above.  Not only is a reduction
+ * "more abstract" -- it operates on the stream as a whole rather than individual
+ * elements -- but a properly constructed reduce operation is inherently
+ * parallelizable, so long as the function(s) used to process the elements
+ * are <a href="package-summary.html#Associativity">associative</a> and
+ * <a href="package-summary.html#NonInterfering">stateless</a>.
+ * For example, given a stream of numbers for which we want to find the sum, we
+ * can write:
  * <pre>{@code
- *    int sum = numbers.reduce(0, (x,y) -> x+y);
+ *    int sum = numbers.stream().reduce(0, (x,y) -> x+y);
  * }</pre>
- * or more succinctly:
+ * or:
  * <pre>{@code
- *    int sum = numbers.reduce(0, Integer::sum);
+ *    int sum = numbers.stream().reduce(0, Integer::sum);
  * }</pre>
  *
- * <p>(The primitive specializations of {@link java.util.stream.Stream}, such as
- * {@link java.util.stream.IntStream}, even have convenience methods for common reductions,
- * such as {@link java.util.stream.IntStream#sum() sum} and {@link java.util.stream.IntStream#max() max},
- * which are implemented as simple wrappers around reduce.)
+ * <p>These reduction operations can run safely in parallel with almost no
+ * modification:
+ * <pre>{@code
+ *    int sum = numbers.parallelStream().reduce(0, Integer::sum);
+ * }</pre>
  *
- * <p>Reduction parallellizes well since the implementation of {@code reduce} can operate on
- * subsets of the stream in parallel, and then combine the intermediate results to get the final
- * correct answer.  Even if you were to use a parallelizable form of the
- * {@link java.util.stream.Stream#forEach(Consumer) forEach()} method
- * in place of the original for-each loop above, you would still have to provide thread-safe
- * updates to the shared accumulating variable {@code sum}, and the required synchronization
- * would likely eliminate any performance gain from parallelism. Using a {@code reduce} method
- * instead removes all of the burden of parallelizing the reduction operation, and the library
- * can provide an efficient parallel implementation with no additional synchronization needed.
+ * <p>Reduction parallellizes well because the implementation
+ * can operate on subsets of the data in parallel, and then combine the
+ * intermediate results to get the final correct answer.  (Even if the language
+ * had a "parallel for-each" construct, the mutative accumulation approach would
+ * still required the developer to provide
+ * thread-safe updates to the shared accumulating variable {@code sum}, and
+ * the required synchronization would then likely eliminate any performance gain from
+ * parallelism.)  Using {@code reduce()} instead removes all of the
+ * burden of parallelizing the reduction operation, and the library can provide
+ * an efficient parallel implementation with no additional synchronization
+ * required.
  *
- * <p>The "blocks" examples shown earlier shows how reduction combines with other operations
- * to replace for loops with bulk operations.  If {@code blocks} is a collection of {@code Block}
- * objects, which have a {@code getWeight} method, we can find the heaviest block with:
+ * <p>The "widgets" examples shown earlier shows how reduction combines with
+ * other operations to replace for loops with bulk operations.  If {@code widgets}
+ * is a collection of {@code Widget} objects, which have a {@code getWeight} method,
+ * we can find the heaviest widget with:
  * <pre>{@code
- *     OptionalInt heaviest = blocks.stream()
- *                                  .mapToInt(Block::getWeight)
- *                                  .reduce(Integer::max);
+ *     OptionalInt heaviest = widgets.parallelStream()
+ *                                   .mapToInt(Widget::getWeight)
+ *                                   .max();
  * }</pre>
  *
- * <p>In its more general form, a {@code reduce} operation on elements of type {@code <T>}
- * yielding a result of type {@code <U>} requires three parameters:
+ * <p>In its more general form, a {@code reduce} operation on elements of type
+ * {@code <T>} yielding a result of type {@code <U>} requires three parameters:
  * <pre>{@code
  * <U> U reduce(U identity,
- *              BiFunction<U, ? super T, U> accumlator,
+ *              BiFunction<U, ? super T, U> accumulator,
  *              BinaryOperator<U> combiner);
  * }</pre>
- * Here, the <em>identity</em> element is both an initial seed for the reduction, and a default
- * result if there are no elements. The <em>accumulator</em> function takes a partial result and
- * the next element, and produce a new partial result. The <em>combiner</em> function combines
- * the partial results of two accumulators to produce a new partial result, and eventually the
- * final result.
+ * Here, the <em>identity</em> element is both an initial seed value for the reduction
+ * and a default result if there are no input elements. The <em>accumulator</em>
+ * function takes a partial result and the next element, and produces a new
+ * partial result. The <em>combiner</em> function combines two partial results
+ * to produce a new partial result.  (The combiner is necessary in parallel
+ * reductions, where the input is partitioned, a partial accumulation computed
+ * for each partition, and then the partial results are combined to produce a
+ * final result.)
  *
- * <p>This form is a generalization of the two-argument form, and is also a generalization of
- * the map-reduce construct illustrated above.  If we wanted to re-cast the simple {@code sum}
- * example using the more general form, {@code 0} would be the identity element, while
- * {@code Integer::sum} would be both the accumulator and combiner. For the sum-of-weights
- * example, this could be re-cast as:
+ * <p>More formally, the {@code identity} value must be an <em>identity</em> for
+ * the combiner function. This means that for all {@code u},
+ * {@code combiner.apply(identity, u)} is equal to {@code u}. Additionally, the
+ * {@code combiner} function must be <a href="package-summary.html#Associativity">associative</a> and
+ * must be compatible with the {@code accumulator} function: for all {@code u}
+ * and {@code t}, {@code combiner.apply(u, accumulator.apply(identity, t))} must
+ * be {@code equals()} to {@code accumulator.apply(u, t)}.
+ *
+ * <p>The three-argument form is a generalization of the two-argument form,
+ * incorporating a mapping step into the accumulation step.  We could
+ * re-cast the simple sum-of-weights example using the more general form as
+ * follows:
  * <pre>{@code
- *     int sumOfWeights = blocks.stream().reduce(0,
- *                                               (sum, b) -> sum + b.getWeight())
- *                                               Integer::sum);
+ *     int sumOfWeights = widgets.stream()
+ *                               .reduce(0,
+ *                                       (sum, b) -> sum + b.getWeight())
+ *                                       Integer::sum);
  * }</pre>
- * though the map-reduce form is more readable and generally preferable.  The generalized form
- * is provided for cases where significant work can be optimized away by combining mapping and
- * reducing into a single function.
+ * though the explicit map-reduce form is more readable and therefore should
+ * usually be preferred. The generalized form is provided for cases where
+ * significant work can be optimized away by combining mapping and reducing
+ * into a single function.
  *
- * <p>More formally, the {@code identity} value must be an <em>identity</em> for the combiner
- * function. This means that for all {@code u}, {@code combiner.apply(identity, u)} is equal
- * to {@code u}. Additionally, the {@code combiner} function must be
- * <a href="#Associativity">associative</a> and must be compatible with the {@code accumulator}
- * function; for all {@code u} and {@code t}, the following must hold:
- * <pre>{@code
- *     combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t)
- * }</pre>
+ * <h3><a name="MutableReduction">Mutable reduction</a></h3>
  *
- * <h3><a name="MutableReduction">Mutable Reduction</a></h3>
- *
- * A <em>mutable</em> reduction operation is similar to an ordinary reduction, in that it reduces
- * a stream of values to a single value, but instead of producing a distinct single-valued result, it
- * mutates a general <em>result container</em>, such as a {@code Collection} or {@code StringBuilder},
+ * A <em>mutable reduction operation</em> accumulates input elements into a
+ * mutable result container, such as a {@code Collection} or {@code StringBuilder},
  * as it processes the elements in the stream.
  *
- * <p>For example, if we wanted to take a stream of strings and concatenate them into a single
- * long string, we <em>could</em> achieve this with ordinary reduction:
+ * <p>If we wanted to take a stream of strings and concatenate them into a
+ * single long string, we <em>could</em> achieve this with ordinary reduction:
  * <pre>{@code
  *     String concatenated = strings.reduce("", String::concat)
  * }</pre>
  *
- * We would get the desired result, and it would even work in parallel.  However, we might not
- * be happy about the performance!  Such an implementation would do a great deal of string
- * copying, and the run time would be <em>O(n^2)</em> in the number of elements.  A more
- * performant approach would be to accumulate the results into a {@link java.lang.StringBuilder}, which
- * is a mutable container for accumulating strings.  We can use the same technique to
+ * <p>We would get the desired result, and it would even work in parallel.  However,
+ * we might not be happy about the performance!  Such an implementation would do
+ * a great deal of string copying, and the run time would be <em>O(n^2)</em> in
+ * the number of characters.  A more performant approach would be to accumulate
+ * the results into a {@link java.lang.StringBuilder}, which is a mutable
+ * container for accumulating strings.  We can use the same technique to
  * parallelize mutable reduction as we do with ordinary reduction.
  *
- * <p>The mutable reduction operation is called {@link java.util.stream.Stream#collect(Collector) collect()}, as it
- * collects together the desired results into a result container such as {@code StringBuilder}.
- * A {@code collect} operation requires three things: a factory function which will construct
- * new instances of the result container, an accumulating function that will update a result
- * container by incorporating a new element, and a combining function that can take two
- * result containers and merge their contents.  The form of this is very similar to the general
+ * <p>The mutable reduction operation is called
+ * {@link java.util.stream.Stream#collect(Collector) collect()},
+ * as it collects together the desired results into a result container such
+ * as a {@code Collection}.
+ * A {@code collect} operation requires three functions:
+ * a supplier function to construct new instances of the result container, an
+ * accumulator function to incorporate an input element into a result
+ * container, and a combining function to merge the contents of one result
+ * container into another.  The form of this is very similar to the general
  * form of ordinary reduction:
  * <pre>{@code
- * <R> R collect(Supplier<R> resultFactory,
+ * <R> R collect(Supplier<R> supplier,
  *               BiConsumer<R, ? super T> accumulator,
  *               BiConsumer<R, R> combiner);
  * }</pre>
- * As with {@code reduce()}, the benefit of expressing {@code collect} in this abstract way is
- * that it is directly amenable to parallelization: we can accumulate partial results in parallel
- * and then combine them.  For example, to collect the String representations of the elements
- * in a stream into an {@code ArrayList}, we could write the obvious sequential for-each form:
+ * <p>As with {@code reduce()}, a benefit of expressing {@code collect} in this
+ * abstract way is that it is directly amenable to parallelization: we can
+ * accumulate partial results in parallel and then combine them, so long as the
+ * accumulation and combining functions satisfy the appropriate requirements.
+ * For example, to collect the String representations of the elements in a
+ * stream into an {@code ArrayList}, we could write the obvious sequential
+ * for-each form:
  * <pre>{@code
  *     ArrayList<String> strings = new ArrayList<>();
  *     for (T element : stream) {
@@ -377,92 +515,108 @@
  *                                                (c, e) -> c.add(e.toString()),
  *                                                (c1, c2) -> c1.addAll(c2));
  * }</pre>
- * or, noting that we have buried a mapping operation inside the accumulator function, more
- * succinctly as:
- * <pre>{@code
- *     ArrayList<String> strings = stream.map(Object::toString)
- *                                       .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
- * }</pre>
- * Here, our supplier is just the {@link java.util.ArrayList#ArrayList() ArrayList constructor}, the
- * accumulator adds the stringified element to an {@code ArrayList}, and the combiner simply
- * uses {@link java.util.ArrayList#addAll addAll} to copy the strings from one container into the other.
- *
- * <p>As with the regular reduction operation, the ability to parallelize only comes if an
- * <a href="package-summary.html#Associativity">associativity</a> condition is met. The {@code combiner} is associative
- * if for result containers {@code r1}, {@code r2}, and {@code r3}:
- * <pre>{@code
- *    combiner.accept(r1, r2);
- *    combiner.accept(r1, r3);
- * }</pre>
- * is equivalent to
- * <pre>{@code
- *    combiner.accept(r2, r3);
- *    combiner.accept(r1, r2);
- * }</pre>
- * where equivalence means that {@code r1} is left in the same state (according to the meaning
- * of {@link java.lang.Object#equals equals} for the element types). Similarly, the {@code resultFactory}
- * must act as an <em>identity</em> with respect to the {@code combiner} so that for any result
- * container {@code r}:
+ * or, pulling the mapping operation out of the accumulator function, we could
+ * express it more succinctly as:
  * <pre>{@code
- *     combiner.accept(r, resultFactory.get());
+ *     List<String> strings = stream.map(Object::toString)
+ *                                  .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
  * }</pre>
- * does not modify the state of {@code r} (again according to the meaning of
- * {@link java.lang.Object#equals equals}). Finally, the {@code accumulator} and {@code combiner} must be
- * compatible such that for a result container {@code r} and element {@code t}:
- * <pre>{@code
- *    r2 = resultFactory.get();
- *    accumulator.accept(r2, t);
- *    combiner.accept(r, r2);
- * }</pre>
- * is equivalent to:
+ * Here, our supplier is just the {@link java.util.ArrayList#ArrayList()
+ * ArrayList constructor}, the accumulator adds the stringified element to an
+ * {@code ArrayList}, and the combiner simply uses {@link java.util.ArrayList#addAll addAll}
+ * to copy the strings from one container into the other.
+ *
+ * <p>The three aspects of {@code collect} -- supplier, accumulator, and
+ * combiner -- are tightly coupled.  We can use the abstraction of a
+ * {@link java.util.stream.Collector} to capture all three aspects.  The
+ * above example for collecting strings into a {@code List} can be rewritten
+ * using a standard {@code Collector} as:
  * <pre>{@code
- *    accumulator.accept(r,t);
+ *     List<String> strings = stream.map(Object::toString)
+ *                                  .collect(Collectors.toList());
  * }</pre>
- * where equivalence means that {@code r} is left in the same state (again according to the
- * meaning of {@link java.lang.Object#equals equals}).
  *
- * <p> The three aspects of {@code collect}: supplier, accumulator, and combiner, are often very
- * tightly coupled, and it is convenient to introduce the notion of a {@link java.util.stream.Collector} as
- * being an object that embodies all three aspects. There is a {@link java.util.stream.Stream#collect(Collector) collect}
- * method that simply takes a {@code Collector} and returns the resulting container.
- * The above example for collecting strings into a {@code List} can be rewritten using a
- * standard {@code Collector} as:
+ * <p>Packaging mutable reductions into a Collector has another advantage:
+ * composability.  The class {@link java.util.stream.Collectors} contains a
+ * number of predefined factories for collectors, including combinators
+ * that transform one collector into another.  For example, suppose we have a
+ * collector that computes the sum of the salaries of a stream of
+ * employees, as follows:
+ *
  * <pre>{@code
- *     ArrayList<String> strings = stream.map(Object::toString)
- *                                       .collect(Collectors.toList());
+ *     Collector<Employee, ?, Integer> summingSalaries
+ *         = Collectors.summingInt(Employee::getSalary);
  * }</pre>
  *
- * <h3><a name="ConcurrentReduction">Reduction, Concurrency, and Ordering</a></h3>
+ * (The {@code ?} for the second type parameter merely indicates that we don't
+ * care about the intermediate representation used by this collector.)
+ * If we wanted to create a collector to tabulate the sum of salaries by
+ * department, we could reuse {@code summingSalaries} using
+ * {@link java.util.stream.Collectors#groupingBy(java.util.function.Function, java.util.stream.Collector) groupingBy}:
+ *
+ * <pre>{@code
+ *     Map<Department, Integer> salariesByDept
+ *         = employees.stream().collect(Collectors.groupingBy(Employee::getDepartment,
+ *                                                            summingSalaries));
+ * }</pre>
+ *
+ * <p>As with the regular reduction operation, {@code collect()} operations can
+ * only be parallelized if appropriate conditions are met.  For any partially
+ * accumulated result, combining it with an empty result container must
+ * produce an equivalent result.  That is, for a partially accumulated result
+ * {@code p} that is the result of any series of accumulator and combiner
+ * invocations, {@code p} must be equivalent to
+ * {@code combiner.apply(p, supplier.get())}.
  *
- * With some complex reduction operations, for example a collect that produces a
- * {@code Map}, such as:
+ * <p>Further, however the computation is split, it must produce an equivalent
+ * result.  For any input elements {@code t1} and {@code t2}, the results
+ * {@code r1} and {@code r2} in the computation below must be equivalent:
+ * <pre>{@code
+ *     A a1 = supplier.get();
+ *     accumulator.accept(a1, t1);
+ *     accumulator.accept(a1, t2);
+ *     R r1 = finisher.apply(a1);  // result without splitting
+ *
+ *     A a2 = supplier.get();
+ *     accumulator.accept(a2, t1);
+ *     A a3 = supplier.get();
+ *     accumulator.accept(a3, t2);
+ *     R r2 = finisher.apply(combiner.apply(a2, a3));  // result with splitting
+ * }</pre>
+ *
+ * <p>Here, equivalence generally means according to {@link java.lang.Object#equals(Object)}.
+ * but in some cases equivalence may be relaxed to account for differences in
+ * order.
+ *
+ * <h3><a name="ConcurrentReduction">Reduction, concurrency, and ordering</a></h3>
+ *
+ * With some complex reduction operations, for example a {@code collect()} that
+ * produces a {@code Map}, such as:
  * <pre>{@code
  *     Map<Buyer, List<Transaction>> salesByBuyer
  *         = txns.parallelStream()
  *               .collect(Collectors.groupingBy(Transaction::getBuyer));
  * }</pre>
- * (where {@link java.util.stream.Collectors#groupingBy} is a utility function
- * that returns a {@link java.util.stream.Collector} for grouping sets of elements based on some key)
  * it may actually be counterproductive to perform the operation in parallel.
- * This is because the combining step (merging one {@code Map} into another by key)
- * can be expensive for some {@code Map} implementations.
+ * This is because the combining step (merging one {@code Map} into another by
+ * key) can be expensive for some {@code Map} implementations.
  *
  * <p>Suppose, however, that the result container used in this reduction
  * was a concurrently modifiable collection -- such as a
- * {@link java.util.concurrent.ConcurrentHashMap ConcurrentHashMap}. In that case,
- * the parallel invocations of the accumulator could actually deposit their results
- * concurrently into the same shared result container, eliminating the need for the combiner to
- * merge distinct result containers. This potentially provides a boost
- * to the parallel execution performance. We call this a <em>concurrent</em> reduction.
+ * {@link java.util.concurrent.ConcurrentHashMap}. In that case, the parallel
+ * invocations of the accumulator could actually deposit their results
+ * concurrently into the same shared result container, eliminating the need for
+ * the combiner to merge distinct result containers. This potentially provides
+ * a boost to the parallel execution performance. We call this a
+ * <em>concurrent</em> reduction.
  *
- * <p>A {@link java.util.stream.Collector} that supports concurrent reduction is marked with the
- * {@link java.util.stream.Collector.Characteristics#CONCURRENT} characteristic.
- * Having a concurrent collector is a necessary condition for performing a
- * concurrent reduction, but that alone is not sufficient. If you imagine multiple
- * accumulators depositing results into a shared container, the order in which
- * results are deposited is non-deterministic. Consequently, a concurrent reduction
- * is only possible if ordering is not important for the stream being processed.
- * The {@link java.util.stream.Stream#collect(Collector)}
+ * <p>A {@link java.util.stream.Collector} that supports concurrent reduction is
+ * marked with the {@link java.util.stream.Collector.Characteristics#CONCURRENT}
+ * characteristic.  However, a concurrent collection also has a downside.  If
+ * multiple threads are depositing results concurrently into a shared container,
+ * the order in which results are deposited is non-deterministic. Consequently,
+ * a concurrent reduction is only possible if ordering is not important for the
+ * stream being processed. The {@link java.util.stream.Stream#collect(Collector)}
  * implementation will only perform a concurrent reduction if
  * <ul>
  * <li>The stream is parallel;</li>
@@ -472,95 +626,100 @@
  * <li>Either the stream is unordered, or the collector has the
  * {@link java.util.stream.Collector.Characteristics#UNORDERED} characteristic.
  * </ul>
- * For example:
+ * You can ensure the stream is unordered by using the
+ * {@link java.util.stream.BaseStream#unordered()} method.  For example:
  * <pre>{@code
  *     Map<Buyer, List<Transaction>> salesByBuyer
  *         = txns.parallelStream()
  *               .unordered()
  *               .collect(groupingByConcurrent(Transaction::getBuyer));
  * }</pre>
- * (where {@link java.util.stream.Collectors#groupingByConcurrent} is the concurrent companion
- * to {@code groupingBy}).
+ * (where {@link java.util.stream.Collectors#groupingByConcurrent} is the
+ * concurrent equivalent of {@code groupingBy}).
  *
- * <p>Note that if it is important that the elements for a given key appear in the
- * order they appear in the source, then we cannot use a concurrent reduction,
- * as ordering is one of the casualties of concurrent insertion.  We would then
- * be constrained to implement either a sequential reduction or a merge-based
- * parallel reduction.
+ * <p>Note that if it is important that the elements for a given key appear in
+ * the order they appear in the source, then we cannot use a concurrent
+ * reduction, as ordering is one of the casualties of concurrent insertion.
+ * We would then be constrained to implement either a sequential reduction or
+ * a merge-based parallel reduction.
  *
- * <h2><a name="Associativity">Associativity</a></h2>
+ * <h3><a name="Associativity">Associativity</a></h3>
  *
- * An operator or function {@code op} is <em>associative</em> if the following holds:
+ * An operator or function {@code op} is <em>associative</em> if the following
+ * holds:
  * <pre>{@code
  *     (a op b) op c == a op (b op c)
  * }</pre>
- * The importance of this to parallel evaluation can be seen if we expand this to four terms:
+ * The importance of this to parallel evaluation can be seen if we expand this
+ * to four terms:
  * <pre>{@code
  *     a op b op c op d == (a op b) op (c op d)
  * }</pre>
- * So we can evaluate {@code (a op b)} in parallel with {@code (c op d)} and then invoke {@code op} on
- * the results.
- * TODO what does associative mean for mutative combining functions?
- * FIXME: we described mutative associativity above.
+ * So we can evaluate {@code (a op b)} in parallel with {@code (c op d)}, and
+ * then invoke {@code op} on the results.
  *
- * <h2><a name="StreamSources">Stream sources</a></h2>
- * TODO where does this section go?
+ * <p>Examples of associative operations include numeric addition, min, and
+ * max, and string concatenation.
+ *
+ * <h2><a name="StreamSources">Low-level stream construction</a></h2>
  *
- * XXX - change to section to stream construction gradually introducing more
- *       complex ways to construct
- *     - construction from Collection
- *     - construction from Iterator
- *     - construction from array
- *     - construction from generators
- *     - construction from spliterator
+ * So far, all the stream examples have used methods like
+ * {@link java.util.Collection#stream()} or {@link java.util.Arrays#stream(Object[])}
+ * to obtain a stream.  How are those stream-bearing methods implemented?
+ *
+ * <p>The class {@link java.util.stream.StreamSupport} has a number of
+ * low-level methods for creating a stream, all using some form of a
+ * {@link java.util.Spliterator}. A spliterator is the parallel analogue of an
+ * {@link java.util.Iterator}; it describes a (possibly infinite) collection of
+ * elements, with support for sequentially advancing, bulk traversal, and
+ * splitting off some portion of the input into another spliterator which can
+ * be processed in parallel.  At the lowest level, all streams are driven by a
+ * spliterator.
  *
- * XXX - the following is quite low-level but important aspect of stream constriction
- *
- * <p>A pipeline is initially constructed from a spliterator (see {@link java.util.Spliterator}) supplied by a stream source.
- * The spliterator covers elements of the source and provides element traversal operations
- * for a possibly-parallel computation.  See methods on {@link java.util.stream.Streams} for construction
- * of pipelines using spliterators.
+ * <p>There are a number of implementation choices in implementing a
+ * spliterator, nearly all of which are tradeoffs between simplicity of
+ * implementation and runtime performance of streams using that spliterator.
+ * The simplest, but least performant, way to create a spliterator is to
+ * create one from an iterator using
+ * {@link java.util.Spliterators#spliteratorUnknownSize(java.util.Iterator, int)}.
+ * While such a spliterator will work, it will likely offer poor parallel
+ * performance, since we have lost sizing information (how big is the
+ * underlying data set), as well as being constrained to a simplistic
+ * splitting algorithm.
  *
- * <p>A source may directly supply a spliterator.  If so, the spliterator is traversed, split, or queried
- * for estimated size after, and never before, the terminal operation commences. It is strongly recommended
- * that the spliterator report a characteristic of {@code IMMUTABLE} or {@code CONCURRENT}, or be
- * <em>late-binding</em> and not bind to the elements it covers until traversed, split or queried for
- * estimated size.
+ * <p>A higher-quality spliterator will provide balanced and known-size
+ * splits, accurate sizing information, and a number of other
+ * {@link java.util.Spliterator#characteristics() characteristics} of the
+ * spliterator or data that can be used by implementations to optimize
+ * execution.
  *
- * <p>If a source cannot directly supply a recommended spliterator then it may indirectly supply a spliterator
- * using a {@code Supplier}.  The spliterator is obtained from the supplier after, and never before, the terminal
+ * <p>Spliterators for mutable data sources have an additional challenge;
+ * timing of binding to the data, since the data could change between the time
+ * the spliterator is created and the time the stream pipeline is executed.
+ * Ideally, a spliterator for a stream would report a characteristic of
+
+ * {@code IMMUTABLE} or {@code CONCURRENT}; if not it should be
+ * <a href="../Spliterator.html#binding"><em>late-binding</em></a>. If a source
+ * cannot directly supply a recommended spliterator, it may indirectly supply
+ * a spliterator using a {@code Supplier}, and construct a stream via the
+ * {@code Supplier}-accepting versions of
+ * {@link java.util.stream.StreamSupport#stream(Supplier, int, boolean) stream()}.
+ * The spliterator is obtained from the supplier only after the terminal
  * operation of the stream pipeline commences.
  *
- * <p>Such requirements significantly reduce the scope of potential interference to the interval starting
- * with the commencing of the terminal operation and ending with the producing a result or side-effect.  See
- * <a href="package-summary.html#Non-Interference">Non-Interference</a> for
- * more details.
- *
- * XXX - move the following to the non-interference section
- *
- * <p>A source can be modified before the terminal operation commences and those modifications will be reflected in
- * the covered elements.  Afterwards, and depending on the properties of the source, further modifications
- * might not be reflected and the throwing of a {@code ConcurrentModificationException} may occur.
+ * <p>These requirements significantly reduce the scope of potential
+ * interference between mutations of the stream source and execution of stream
+ * pipelines. Streams based on spliterators with the desired characteristics,
+ * or those using the Supplier-based factory forms, are immune to
+ * modifications of the data source prior to commencement of the terminal
+ * operation (provided the behavioral parameters to the stream operations meet
+ * the required criteria for non-interference and statelessness).  See
+ * <a href="package-summary.html#Non-Interference">Non-Interference</a>
+ * for more details.
  *
- * <p>For example, consider the following code:
- * <pre>{@code
- *     List<String> l = new ArrayList(Arrays.asList("one", "two"));
- *     Stream<String> sl = l.stream();
- *     l.add("three");
- *     String s = sl.collect(joining(" "));
- * }</pre>
- * First a list is created consisting of two strings: "one"; and "two". Then a stream is created from that list.
- * Next the list is modified by adding a third string: "three".  Finally the elements of the stream are collected
- * and joined together.  Since the list was modified before the terminal {@code collect} operation commenced
- * the result will be a string of "one two three". However, if the list is modified after the terminal operation
- * commences, as in:
- * <pre>{@code
- *     List<String> l = new ArrayList(Arrays.asList("one", "two"));
- *     Stream<String> sl = l.stream();
- *     String s = sl.peek(s -> l.add("BAD LAMBDA")).collect(joining(" "));
- * }</pre>
- * then a {@code ConcurrentModificationException} will be thrown since the {@code peek} operation will attempt
- * to add the string "BAD LAMBDA" to the list after the terminal operation has commenced.
+ * @since 1.8
  */
+package java.util.stream;
 
-package java.util.stream;
+import java.util.function.BinaryOperator;
+import java.util.function.UnaryOperator;
--- a/jdk/src/share/classes/java/util/zip/Deflater.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/zip/Deflater.java	Wed Jul 05 19:11:53 2017 +0200
@@ -261,6 +261,12 @@
 
     /**
      * Sets the compression strategy to the specified value.
+     *
+     * <p> If the compression strategy is changed, the next invocation
+     * of {@code deflate} will compress the input available so far with
+     * the old strategy (and may be flushed); the new strategy will take
+     * effect only after that invocation.
+     *
      * @param strategy the new compression strategy
      * @exception IllegalArgumentException if the compression strategy is
      *                                     invalid
@@ -283,7 +289,13 @@
     }
 
     /**
-     * Sets the current compression level to the specified value.
+     * Sets the compression level to the specified value.
+     *
+     * <p> If the compression level is changed, the next invocation
+     * of {@code deflate} will compress the input available so far
+     * with the old level (and may be flushed); the new level will
+     * take effect only after that invocation.
+     *
      * @param level the new compression level (0-9)
      * @exception IllegalArgumentException if the compression level is invalid
      */
--- a/jdk/src/share/classes/java/util/zip/ZipConstants.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/zip/ZipConstants.java	Wed Jul 05 19:11:53 2017 +0200
@@ -69,21 +69,6 @@
     static final int EXTLEN = 12;       // uncompressed size
 
     /*
-     * Extra field header ID
-     */
-    static final int  EXTID_ZIP64 = 0x0001;    // Zip64
-    static final int  EXTID_NTFS  = 0x000a;    // NTFS
-    static final int  EXTID_UNIX  = 0x000d;    // UNIX
-    static final int  EXTID_EXTT  = 0x5455;    // Info-ZIP Extended Timestamp
-
-    /*
-     * EXTT timestamp flags
-     */
-    static final int  EXTT_FLAG_LMT = 0x1;       // LastModifiedTime
-    static final int  EXTT_FLAG_LAT = 0x2;       // LastAccessTime
-    static final int  EXTT_FLAT_CT  = 0x4;       // CreationTime
-
-    /*
      * Central directory (CEN) header field offsets
      */
     static final int CENVEM = 4;        // version made by
--- a/jdk/src/share/classes/java/util/zip/ZipConstants64.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/zip/ZipConstants64.java	Wed Jul 05 19:11:53 2017 +0200
@@ -80,5 +80,26 @@
                                         // comment fields for this file must be
                                         // encoded using UTF-8.
 
+    /*
+     * Constants below are defined here (instead of in ZipConstants)
+     * to avoid being exposed as public fields of ZipFile, ZipEntry,
+     * ZipInputStream and ZipOutputstream.
+     */
+
+    /*
+     * Extra field header ID
+     */
+    static final int  EXTID_ZIP64 = 0x0001;    // Zip64
+    static final int  EXTID_NTFS  = 0x000a;    // NTFS
+    static final int  EXTID_UNIX  = 0x000d;    // UNIX
+    static final int  EXTID_EXTT  = 0x5455;    // Info-ZIP Extended Timestamp
+
+    /*
+     * EXTT timestamp flags
+     */
+    static final int  EXTT_FLAG_LMT = 0x1;       // LastModifiedTime
+    static final int  EXTT_FLAG_LAT = 0x2;       // LastAccessTime
+    static final int  EXTT_FLAT_CT  = 0x4;       // CreationTime
+
     private ZipConstants64() {}
 }
--- a/jdk/src/share/classes/java/util/zip/ZipEntry.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/java/util/zip/ZipEntry.java	Wed Jul 05 19:11:53 2017 +0200
@@ -30,6 +30,8 @@
 import java.util.Objects;
 import java.util.concurrent.TimeUnit;
 
+import static java.util.zip.ZipConstants64.*;
+
 /**
  * This class is used to represent a ZIP file entry.
  *
--- a/jdk/src/share/classes/javax/management/MBeanAttributeInfo.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/javax/management/MBeanAttributeInfo.java	Wed Jul 05 19:11:53 2017 +0200
@@ -30,6 +30,7 @@
 
 import com.sun.jmx.mbeanserver.GetPropertyAction;
 import com.sun.jmx.mbeanserver.Introspector;
+import java.util.Objects;
 
 
 /**
@@ -301,7 +302,7 @@
        right and we needlessly hashed in the description and parameter
        array.  */
     public int hashCode() {
-        return getName().hashCode() ^ getType().hashCode();
+        return Objects.hash(getName(), getType());
     }
 
     private static boolean isIs(Method getter) {
--- a/jdk/src/share/classes/javax/management/MBeanConstructorInfo.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/javax/management/MBeanConstructorInfo.java	Wed Jul 05 19:11:53 2017 +0200
@@ -29,6 +29,7 @@
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Constructor;
 import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * Describes a constructor exposed by an MBean.  Instances of this
@@ -203,11 +204,7 @@
        quite long and yet the same between constructors.  Likewise for
        the descriptor.  */
     public int hashCode() {
-        int hash = getName().hashCode();
-        MBeanParameterInfo[] sig = fastGetSignature();
-        for (int i = 0; i < sig.length; i++)
-            hash ^= sig[i].hashCode();
-        return hash;
+        return Objects.hash(getName()) ^ Arrays.hashCode(fastGetSignature());
     }
 
     private static MBeanParameterInfo[] constructorSignature(Constructor<?> cn) {
--- a/jdk/src/share/classes/javax/management/MBeanInfo.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/javax/management/MBeanInfo.java	Wed Jul 05 19:11:53 2017 +0200
@@ -36,6 +36,7 @@
 import java.util.WeakHashMap;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.util.Objects;
 
 import static javax.management.ImmutableDescriptor.nonNullDescriptor;
 
@@ -515,24 +516,15 @@
         if (hashCode != 0)
             return hashCode;
 
-        hashCode =
-            getClassName().hashCode() ^
-            getDescriptor().hashCode() ^
-            arrayHashCode(fastGetAttributes()) ^
-            arrayHashCode(fastGetOperations()) ^
-            arrayHashCode(fastGetConstructors()) ^
-            arrayHashCode(fastGetNotifications());
+        hashCode = Objects.hash(getClassName(), getDescriptor())
+                ^ Arrays.hashCode(fastGetAttributes())
+                ^ Arrays.hashCode(fastGetOperations())
+                ^ Arrays.hashCode(fastGetConstructors())
+                ^ Arrays.hashCode(fastGetNotifications());
 
         return hashCode;
     }
 
-    private static int arrayHashCode(Object[] array) {
-        int hash = 0;
-        for (int i = 0; i < array.length; i++)
-            hash ^= array[i].hashCode();
-        return hash;
-    }
-
     /**
      * Cached results of previous calls to arrayGettersSafe.  This is
      * a WeakHashMap so that we don't prevent a class from being
--- a/jdk/src/share/classes/javax/management/MBeanOperationInfo.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/javax/management/MBeanOperationInfo.java	Wed Jul 05 19:11:53 2017 +0200
@@ -29,6 +29,7 @@
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
 import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * Describes a management operation exposed by an MBean.  Instances of
@@ -309,7 +310,7 @@
        parameter array.  */
     @Override
     public int hashCode() {
-        return getName().hashCode() ^ getReturnType().hashCode();
+        return Objects.hash(getName(), getReturnType());
     }
 
     private static MBeanParameterInfo[] methodSignature(Method method) {
--- a/jdk/src/share/classes/javax/management/MBeanParameterInfo.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/javax/management/MBeanParameterInfo.java	Wed Jul 05 19:11:53 2017 +0200
@@ -25,6 +25,7 @@
 
 package javax.management;
 
+import java.util.Objects;
 
 /**
  * Describes an argument of an operation exposed by an MBean.
@@ -143,6 +144,6 @@
     }
 
     public int hashCode() {
-        return getName().hashCode() ^ getType().hashCode();
+        return Objects.hash(getName(), getType());
     }
 }
--- a/jdk/src/share/classes/javax/management/openmbean/OpenMBeanInfoSupport.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/javax/management/openmbean/OpenMBeanInfoSupport.java	Wed Jul 05 19:11:53 2017 +0200
@@ -31,6 +31,7 @@
 //
 import java.util.Arrays;
 import java.util.HashSet;
+import java.util.Objects;
 
 import javax.management.Descriptor;
 import javax.management.MBeanAttributeInfo;
@@ -269,8 +270,9 @@
         //
 
         // their MBean className should be equal
-        if ( ! this.getClassName().equals(other.getClassName()) )
+        if (!Objects.equals(this.getClassName(), other.getClassName())) {
             return false;
+        }
 
         // their infos on attributes should be equal (order not
         // significant => equality between sets, not arrays or lists)
@@ -342,7 +344,9 @@
         //
         if (myHashCode == null) {
             int value = 0;
-            value += this.getClassName().hashCode();
+            if (this.getClassName() != null) {
+                value += this.getClassName().hashCode();
+            }
             value += arraySetHash(this.getAttributes());
             value += arraySetHash(this.getConstructors());
             value += arraySetHash(this.getOperations());
--- a/jdk/src/share/classes/javax/management/remote/rmi/RMIConnector.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnector.java	Wed Jul 05 19:11:53 2017 +0200
@@ -405,14 +405,7 @@
             throw new IOException("Not connected");
         }
 
-        MBeanServerConnection rmbsc = rmbscMap.get(delegationSubject);
-        if (rmbsc != null) {
-            return rmbsc;
-        }
-
-        rmbsc = new RemoteMBeanServerConnection(delegationSubject);
-        rmbscMap.put(delegationSubject, rmbsc);
-        return rmbsc;
+        return getConnectionWithSubject(delegationSubject);
     }
 
     public void
@@ -1831,7 +1824,7 @@
 
     // Initialization of transient variables.
     private void initTransients() {
-        rmbscMap = new WeakHashMap<Subject, MBeanServerConnection>();
+        rmbscMap = new WeakHashMap<Subject, WeakReference<MBeanServerConnection>>();
         connected = false;
         terminated = false;
 
@@ -2011,6 +2004,25 @@
         private final ClassLoader loader;
     }
 
+    private MBeanServerConnection getConnectionWithSubject(Subject delegationSubject) {
+        MBeanServerConnection conn = null;
+
+        if (delegationSubject == null) {
+            if (nullSubjectConnRef == null
+                    || (conn = nullSubjectConnRef.get()) == null) {
+                conn = new RemoteMBeanServerConnection(null);
+                nullSubjectConnRef = new WeakReference(conn);
+            }
+        } else {
+            WeakReference<MBeanServerConnection> wr = rmbscMap.get(delegationSubject);
+            if (wr == null || (conn = wr.get()) == null) {
+                conn = new RemoteMBeanServerConnection(delegationSubject);
+                rmbscMap.put(delegationSubject, new WeakReference(conn));
+            }
+        }
+        return conn;
+    }
+
     /*
        The following section of code avoids a class loading problem
        with RMI.  The problem is that an RMI stub, when deserializing
@@ -2551,7 +2563,8 @@
 
     private transient long clientNotifSeqNo = 0;
 
-    private transient WeakHashMap<Subject, MBeanServerConnection> rmbscMap;
+    private transient WeakHashMap<Subject, WeakReference<MBeanServerConnection>> rmbscMap;
+    private transient WeakReference<MBeanServerConnection> nullSubjectConnRef = null;
 
     private transient RMINotifClient rmiNotifClient;
     // = new RMINotifClient(new Integer(0));
--- a/jdk/src/share/classes/javax/net/ssl/SSLParameters.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/javax/net/ssl/SSLParameters.java	Wed Jul 05 19:11:53 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -40,7 +40,7 @@
  * the list of protocols to be allowed, the endpoint identification
  * algorithm during SSL/TLS handshaking, the Server Name Indication (SNI),
  * the algorithm constraints and whether SSL/TLS servers should request
- * or require client authentication.
+ * or require client authentication, etc.
  * <p>
  * SSLParameters can be created via the constructors in this class.
  * Objects can also be obtained using the <code>getSSLParameters()</code>
@@ -73,13 +73,14 @@
     private AlgorithmConstraints algorithmConstraints;
     private Map<Integer, SNIServerName> sniNames = null;
     private Map<Integer, SNIMatcher> sniMatchers = null;
+    private boolean preferLocalCipherSuites;
 
     /**
      * Constructs SSLParameters.
      * <p>
      * The values of cipherSuites, protocols, cryptographic algorithm
      * constraints, endpoint identification algorithm, server names and
-     * server name matchers are set to <code>null</code>,
+     * server name matchers are set to <code>null</code>, useCipherSuitesOrder,
      * wantClientAuth and needClientAuth are set to <code>false</code>.
      */
     public SSLParameters() {
@@ -434,5 +435,34 @@
 
         return null;
     }
+
+    /**
+     * Sets whether the local cipher suites preference should be honored.
+     *
+     * @param honorOrder whether local cipher suites order in
+     *        {@code #getCipherSuites} should be honored during
+     *        SSL/TLS handshaking.
+     *
+     * @see #getUseCipherSuitesOrder()
+     *
+     * @since 1.8
+     */
+    public final void setUseCipherSuitesOrder(boolean honorOrder) {
+        this.preferLocalCipherSuites = honorOrder;
+    }
+
+    /**
+     * Returns whether the local cipher suites preference should be honored.
+     *
+     * @return whether local cipher suites order in {@code #getCipherSuites}
+     *         should be honored during SSL/TLS handshaking.
+     *
+     * @see #setUseCipherSuitesOrder(boolean)
+     *
+     * @since 1.8
+     */
+    public final boolean getUseCipherSuitesOrder() {
+        return preferLocalCipherSuites;
+    }
 }
 
--- a/jdk/src/share/classes/javax/security/auth/Subject.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/javax/security/auth/Subject.java	Wed Jul 05 19:11:53 2017 +0200
@@ -1186,7 +1186,7 @@
         }
 
         public boolean removeAll(Collection<?> c) {
-
+            Objects.requireNonNull(c);
             boolean modified = false;
             final Iterator<E> e = iterator();
             while (e.hasNext()) {
@@ -1222,7 +1222,7 @@
         }
 
         public boolean retainAll(Collection<?> c) {
-
+            Objects.requireNonNull(c);
             boolean modified = false;
             boolean retain = false;
             final Iterator<E> e = iterator();
--- a/jdk/src/share/classes/javax/sql/rowset/Predicate.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/javax/sql/rowset/Predicate.java	Wed Jul 05 19:11:53 2017 +0200
@@ -56,44 +56,43 @@
  * <pre>{@code
  *    public class Range implements Predicate {
  *
- *       private Object lo[];
- *       private Object hi[];
- *       private int idx[];
+ *       private int[] lo;
+ *       private int[] hi;
+ *       private int[] idx;
  *
- *       public Range(Object[] lo, Object[] hi, int[] idx) {
+ *       public Range(int[] lo, int[] hi, int[] idx) {
  *          this.lo = lo;
  *          this.hi = hi;
  *          this.idx = idx;
  *       }
  *
  *      public boolean evaluate(RowSet rs) {
- *          CachedRowSet crs = (CachedRowSet)rs;
- *          boolean bool1,bool2;
  *
  *          // Check the present row determine if it lies
  *          // within the filtering criteria.
  *
  *          for (int i = 0; i < idx.length; i++) {
+ *             int value;
+ *             try {
+ *                 value = (Integer) rs.getObject(idx[i]);
+ *             } catch (SQLException ex) {
+ *                 Logger.getLogger(Range.class.getName()).log(Level.SEVERE, null, ex);
+ *                 return false;
+ *             }
  *
- *              if ((rs.getObject(idx[i]) >= lo[i]) &&
- *                  (rs.getObject(idx[i]) >= hi[i]) {
- *                  bool1 = true; // within filter constraints
- *              } else {
- *                  bool2 = true; // outside of filter constraints
- *              }
- *          }
- *
- *          if (bool2) {
- *             return false;
- *          } else {
- *             return true;
- *          }
+ *             if (value < lo[i] && value > hi[i]) {
+ *                 // outside of filter constraints
+ *                 return false;
+ *             }
+ *         }
+ *         // Within filter constraints
+ *        return true;
  *      }
- *  }
+ *   }
  * }</pre>
  * <P>
  * The example above implements a simple range predicate. Note, that
- * implementations should but are not required to provider <code>String</code>
+ * implementations should but are not required to provide <code>String</code>
  * and integer index based constructors to provide for JDBC RowSet Implementation
  * applications that use both column identification conventions.
  *
--- a/jdk/src/share/classes/sun/applet/AppletSecurity.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/applet/AppletSecurity.java	Wed Jul 05 19:11:53 2017 +0200
@@ -314,7 +314,7 @@
             // If we're about to allow access to the main EventQueue,
             // and anything untrusted is on the class context stack,
             // disallow access.
-            super.checkAwtEventQueueAccess();
+            super.checkPermission(SecurityConstants.AWT.CHECK_AWT_EVENTQUEUE_PERMISSION);
         }
     } // checkAwtEventQueueAccess()
 
--- a/jdk/src/share/classes/sun/awt/AppContext.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/awt/AppContext.java	Wed Jul 05 19:11:53 2017 +0200
@@ -838,21 +838,59 @@
             public boolean isMainAppContext() {
                 return (numAppContexts.get() == 1 && mainAppContext != null);
             }
-            public Object getContext() {
-                return getAppContext();
-            }
-            public Object getExecutionContext() {
-                return getExecutionAppContext();
+
+            /**
+             * Returns the AppContext used for applet logging isolation, or null if
+             * the default global context can be used.
+             * If there's no applet, or if the caller is a stand alone application,
+             * or running in the main app context, returns null.
+             * Otherwise, returns the AppContext of the calling applet.
+             * @return null if the global default context can be used,
+             *         an AppContext otherwise.
+             **/
+            public Object getAppletContext() {
+                // There's no AppContext: return null.
+                // No need to call getAppContext() if numAppContext == 0:
+                // it means that no AppContext has been created yet, and
+                // we don't want to trigger the creation of a main app
+                // context since we don't need it.
+                if (numAppContexts.get() == 0) return null;
+
+                // Get the context from the security manager
+                AppContext ecx = getExecutionAppContext();
+
+                // Not sure we really need to re-check numAppContexts here.
+                // If all applets have gone away then we could have a
+                // numAppContexts coming back to 0. So we recheck
+                // it here because we don't want to trigger the
+                // creation of a main AppContext in that case.
+                // This is probably not 100% MT-safe but should reduce
+                // the window of opportunity in which that issue could
+                // happen.
+                if (numAppContexts.get() > 0) {
+                   // Defaults to thread group caching.
+                   // This is probably not required as we only really need
+                   // isolation in a deployed applet environment, in which
+                   // case ecx will not be null when we reach here
+                   // However it helps emulate the deployed environment,
+                   // in tests for instance.
+                   ecx = ecx != null ? ecx : getAppContext();
+                }
+
+                // getAppletContext() may be called when initializing the main
+                // app context - in which case mainAppContext will still be
+                // null. To work around this issue we simply use
+                // AppContext.threadGroup.getParent() == null instead, since
+                // mainAppContext is the only AppContext which should have
+                // the root TG as its thread group.
+                // See: JDK-8023258
+                final boolean isMainAppContext = ecx == null
+                    || mainAppContext == ecx
+                    || mainAppContext == null && ecx.threadGroup.getParent() == null;
+
+                return isMainAppContext ? null : ecx;
             }
-            public Object get(Object context, Object key) {
-                return ((AppContext)context).get(key);
-            }
-            public void put(Object context, Object key, Object value) {
-                ((AppContext)context).put(key, value);
-            }
-            public void remove(Object context, Object key) {
-                ((AppContext)context).remove(key);
-            }
+
         });
     }
 }
--- a/jdk/src/share/classes/sun/awt/dnd/SunDropTargetContextPeer.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/awt/dnd/SunDropTargetContextPeer.java	Wed Jul 05 19:11:53 2017 +0200
@@ -57,6 +57,7 @@
 import sun.awt.SunToolkit;
 import sun.awt.datatransfer.DataTransferer;
 import sun.awt.datatransfer.ToolkitThreadBlockedHandler;
+import sun.security.util.SecurityConstants;
 
 /**
  * <p>
@@ -225,7 +226,7 @@
         SecurityManager sm = System.getSecurityManager();
         try {
             if (!dropInProcess && sm != null) {
-                sm.checkSystemClipboardAccess();
+                sm.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
             }
         } catch (Exception e) {
             Thread currentThread = Thread.currentThread();
--- a/jdk/src/share/classes/sun/java2d/cmm/CMSManager.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/java2d/cmm/CMSManager.java	Wed Jul 05 19:11:53 2017 +0200
@@ -104,53 +104,53 @@
             cName = tcmm.getClass().getName();
         }
 
-        public long loadProfile(byte[] data) {
+        public Profile loadProfile(byte[] data) {
             System.err.print(cName + ".loadProfile");
-            long profileID = tcmm.loadProfile(data);
-            System.err.printf("(ID=%x)\n", profileID);
-            return profileID;
+            Profile p = tcmm.loadProfile(data);
+            System.err.printf("(ID=%s)\n", p.toString());
+            return p;
         }
 
-        public void freeProfile(long profileID) {
-            System.err.printf(cName + ".freeProfile(ID=%x)\n", profileID);
-            tcmm.freeProfile(profileID);
+        public void freeProfile(Profile p) {
+            System.err.printf(cName + ".freeProfile(ID=%s)\n", p.toString());
+            tcmm.freeProfile(p);
         }
 
-        public int getProfileSize(long profileID) {
-            System.err.print(cName + ".getProfileSize(ID=" + profileID + ")");
-            int size = tcmm.getProfileSize(profileID);
+        public int getProfileSize(Profile p) {
+            System.err.print(cName + ".getProfileSize(ID=" + p + ")");
+            int size = tcmm.getProfileSize(p);
             System.err.println("=" + size);
             return size;
         }
 
-        public void getProfileData(long profileID, byte[] data) {
-            System.err.print(cName + ".getProfileData(ID=" + profileID + ") ");
+        public void getProfileData(Profile p, byte[] data) {
+            System.err.print(cName + ".getProfileData(ID=" + p + ") ");
             System.err.println("requested " + data.length + " byte(s)");
-            tcmm.getProfileData(profileID, data);
+            tcmm.getProfileData(p, data);
         }
 
-        public int getTagSize(long profileID, int tagSignature) {
+        public int getTagSize(Profile p, int tagSignature) {
             System.err.printf(cName + ".getTagSize(ID=%x, TagSig=%s)",
-                              profileID, signatureToString(tagSignature));
-            int size = tcmm.getTagSize(profileID, tagSignature);
+                              p, signatureToString(tagSignature));
+            int size = tcmm.getTagSize(p, tagSignature);
             System.err.println("=" + size);
             return size;
         }
 
-        public void getTagData(long profileID, int tagSignature,
+        public void getTagData(Profile p, int tagSignature,
                                byte[] data) {
             System.err.printf(cName + ".getTagData(ID=%x, TagSig=%s)",
-                              profileID, signatureToString(tagSignature));
+                              p, signatureToString(tagSignature));
             System.err.println(" requested " + data.length + " byte(s)");
-            tcmm.getTagData(profileID, tagSignature, data);
+            tcmm.getTagData(p, tagSignature, data);
         }
 
-        public void setTagData(long profileID, int tagSignature,
+        public void setTagData(Profile p, int tagSignature,
                                byte[] data) {
-            System.err.print(cName + ".setTagData(ID=" + profileID +
+            System.err.print(cName + ".setTagData(ID=" + p +
                              ", TagSig=" + tagSignature + ")");
             System.err.println(" sending " + data.length + " byte(s)");
-            tcmm.setTagData(profileID, tagSignature, data);
+            tcmm.setTagData(p, tagSignature, data);
         }
 
         /* methods for creating ColorTransforms */
--- a/jdk/src/share/classes/sun/java2d/cmm/PCMM.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/java2d/cmm/PCMM.java	Wed Jul 05 19:11:53 2017 +0200
@@ -32,13 +32,13 @@
 public interface PCMM {
 
     /* methods invoked from ICC_Profile */
-    public long loadProfile(byte[] data);
-    public void freeProfile(long profileID);
-    public int  getProfileSize(long profileID);
-    public void getProfileData(long profileID, byte[] data);
-    public void getTagData(long profileID, int tagSignature, byte[] data);
-    public int getTagSize(long profileID, int tagSignature);
-    public void setTagData(long profileID, int tagSignature, byte[] data);
+    public Profile loadProfile(byte[] data);
+    public void freeProfile(Profile p);
+    public int  getProfileSize(Profile p);
+    public void getProfileData(Profile p, byte[] data);
+    public void getTagData(Profile p, int tagSignature, byte[] data);
+    public int getTagSize(Profile p, int tagSignature);
+    public void setTagData(Profile p, int tagSignature, byte[] data);
 
     /* methods for creating ColorTransforms */
     public ColorTransform createTransform(ICC_Profile profile, int renderType,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/java2d/cmm/Profile.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.cmm;
+
+import java.awt.color.CMMException;
+
+public class Profile {
+    private final long nativePtr;
+
+    protected Profile(long ptr) {
+        nativePtr = ptr;
+    }
+
+    protected final long getNativePtr() {
+        if (nativePtr == 0L) {
+            throw new CMMException("Invalid profile: ptr is null");
+        }
+        return nativePtr;
+    }
+}
--- a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMS.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMS.java	Wed Jul 05 19:11:53 2017 +0200
@@ -25,96 +25,139 @@
 
 package sun.java2d.cmm.lcms;
 
+import java.awt.color.CMMException;
 import java.awt.color.ICC_Profile;
-import java.util.Arrays;
-import java.util.HashMap;
 import sun.java2d.cmm.ColorTransform;
 import sun.java2d.cmm.PCMM;
+import sun.java2d.cmm.Profile;
+import sun.java2d.cmm.lcms.LCMSProfile.TagData;
 
 public class LCMS implements PCMM {
 
     /* methods invoked from ICC_Profile */
     @Override
-    public long loadProfile(byte[] data) {
-        long id = loadProfileNative(data);
+    public Profile loadProfile(byte[] data) {
+        final Object disposerRef = new Object();
+
+        final long ptr = loadProfileNative(data, disposerRef);
 
-        if (id != 0L) {
-            if (profiles == null) {
-                profiles = new HashMap<>();
-            }
-            profiles.put(id, new TagCache(id));
+        if (ptr != 0L) {
+            return new LCMSProfile(ptr, disposerRef);
         }
-        return id;
+        return null;
     }
 
-    private native long loadProfileNative(byte[] data);
+    private native long loadProfileNative(byte[] data, Object ref);
+
+    private LCMSProfile getLcmsProfile(Profile p) {
+        if (p instanceof LCMSProfile) {
+            return (LCMSProfile)p;
+        }
+        throw new CMMException("Invalid profile: " + p);
+    }
+
 
     @Override
-    public void freeProfile(long profileID) {
-        TagCache c = profiles.remove(profileID);
-        if (c != null) {
-            c.clear();
+    public void freeProfile(Profile p) {
+        // we use disposer, so this method does nothing
+    }
+
+    @Override
+    public int getProfileSize(final Profile p) {
+        synchronized (p) {
+            return getProfileSizeNative(getLcmsProfile(p).getLcmsPtr());
         }
-        if (profiles.isEmpty()) {
-            profiles = null;
-        }
-        freeProfileNative(profileID);
     }
 
-    private native void freeProfileNative(long profileID);
+    private native int getProfileSizeNative(long ptr);
 
-    public native synchronized int getProfileSize(long profileID);
+    @Override
+    public void getProfileData(final Profile p, byte[] data) {
+        synchronized (p) {
+            getProfileDataNative(getLcmsProfile(p).getLcmsPtr(), data);
+        }
+    }
 
-    public native synchronized void getProfileData(long profileID, byte[] data);
+    private native void getProfileDataNative(long ptr, byte[] data);
 
     @Override
-    public synchronized int getTagSize(long profileID, int tagSignature) {
-        TagCache cache = profiles.get(profileID);
+    public int getTagSize(Profile p, int tagSignature) {
+        final LCMSProfile profile = getLcmsProfile(p);
 
-        if (cache ==  null) {
-            cache = new TagCache(profileID);
-            profiles.put(profileID, cache);
+        synchronized (profile) {
+            TagData t = profile.getTag(tagSignature);
+            return t == null ? 0 : t.getSize();
         }
-
-        TagData t = cache.getTag(tagSignature);
-        return t == null ? 0 : t.getSize();
     }
 
-    private static native byte[] getTagNative(long profileID, int signature);
+    static native byte[] getTagNative(long profileID, int signature);
 
     @Override
-    public synchronized void getTagData(long profileID, int tagSignature,
-                                               byte[] data)
+    public void getTagData(Profile p, int tagSignature, byte[] data)
     {
-        TagCache cache = profiles.get(profileID);
+        final LCMSProfile profile = getLcmsProfile(p);
 
-        if (cache ==  null) {
-            cache = new TagCache(profileID);
-            profiles.put(profileID, cache);
-        }
-
-        TagData t = cache.getTag(tagSignature);
-        if (t != null) {
-            t.copyDataTo(data);
+        synchronized (profile) {
+            TagData t = profile.getTag(tagSignature);
+            if (t != null) {
+                t.copyDataTo(data);
+            }
         }
     }
 
     @Override
-    public synchronized void setTagData(long profileID, int tagSignature, byte[] data) {
-        TagCache cache = profiles.get(profileID);
+    public synchronized void setTagData(Profile p, int tagSignature, byte[] data) {
+        final LCMSProfile profile = getLcmsProfile(p);
+
+        synchronized (profile) {
+            profile.clearTagCache();
 
-        if (cache != null) {
-            cache.clear();
+            // Now we are going to update the profile with new tag data
+            // In some cases, we may change the pointer to the native
+            // profile.
+            //
+            // If we fail to write tag data for any reason, the old pointer
+            // should be used.
+            setTagDataNative(profile.getLcmsPtr(),
+                    tagSignature, data);
         }
-        setTagDataNative(profileID, tagSignature, data);
     }
 
-    private native synchronized void setTagDataNative(long profileID, int tagSignature,
+    /**
+     * Writes supplied data as a tag into the profile.
+     * Destroys old profile, if new one was successfully
+     * created.
+     *
+     * Returns valid pointer to new profile.
+     *
+     * Throws CMMException if operation fails, preserve old profile from
+     * destruction.
+     */
+    private native void setTagDataNative(long ptr, int tagSignature,
                                                byte[] data);
 
-    public static native long getProfileID(ICC_Profile profile);
+    public synchronized static native LCMSProfile getProfileID(ICC_Profile profile);
+
+    /* Helper method used from LCMSColorTransfrom */
+    static long createTransform(
+        LCMSProfile[] profiles, int renderType,
+        int inFormatter, boolean isInIntPacked,
+        int outFormatter, boolean isOutIntPacked,
+        Object disposerRef)
+    {
+        long[] ptrs = new long[profiles.length];
 
-    public static native long createNativeTransform(
+        for (int i = 0; i < profiles.length; i++) {
+            if (profiles[i] == null) throw new CMMException("Unknown profile ID");
+
+            ptrs[i] = profiles[i].getLcmsPtr();
+        }
+
+        return createNativeTransform(ptrs, renderType, inFormatter,
+                isInIntPacked, outFormatter, isOutIntPacked, disposerRef);
+    }
+
+    private static native long createNativeTransform(
         long[] profileIDs, int renderType,
         int inFormatter, boolean isInIntPacked,
         int outFormatter, boolean isOutIntPacked,
@@ -175,59 +218,4 @@
 
         return theLcms;
     }
-
-    private static class TagData {
-        private int signature;
-        private byte[] data;
-
-        TagData(int sig, byte[] data) {
-            this.signature = sig;
-            this.data = data;
-        }
-
-        int getSize() {
-            return data.length;
-        }
-
-        byte[] getData() {
-            return Arrays.copyOf(data, data.length);
-        }
-
-        void copyDataTo(byte[] dst) {
-            System.arraycopy(data, 0, dst, 0, data.length);
-        }
-
-        int getSignature() {
-            return signature;
-        }
-    }
-
-    private static class TagCache  {
-        private long profileID;
-        private HashMap<Integer, TagData> tags;
-
-        TagCache(long id) {
-            profileID = id;
-
-            tags = new HashMap<>();
-        }
-
-        TagData getTag(int sig) {
-            TagData t = tags.get(sig);
-            if (t == null) {
-                byte[] tagData = getTagNative(profileID, sig);
-                if (tagData != null) {
-                    t = new TagData(sig, tagData);
-                    tags.put(sig, t);
-                }
-            }
-            return t;
-        }
-
-        void clear() {
-            tags.clear();
-        }
-    }
-
-    private static HashMap<Long, TagCache> profiles;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSProfile.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.java2d.cmm.lcms;
+
+import java.awt.color.CMMException;
+import java.util.Arrays;
+import java.util.HashMap;
+import sun.java2d.cmm.Profile;
+
+final class LCMSProfile extends Profile {
+    private final TagCache tagCache;
+
+    private final Object disposerReferent;
+
+    LCMSProfile(long ptr, Object ref) {
+        super(ptr);
+
+        disposerReferent = ref;
+
+        tagCache = new TagCache(this);
+    }
+
+    final long getLcmsPtr() {
+        return this.getNativePtr();
+    }
+
+    TagData getTag(int sig) {
+        return tagCache.getTag(sig);
+    }
+
+    void clearTagCache() {
+        tagCache.clear();
+    }
+
+    static class TagCache  {
+        final LCMSProfile profile;
+        private HashMap<Integer, TagData> tags;
+
+        TagCache(LCMSProfile p) {
+            profile = p;
+            tags = new HashMap<>();
+        }
+
+        TagData getTag(int sig) {
+            TagData t = tags.get(sig);
+            if (t == null) {
+                byte[] tagData = LCMS.getTagNative(profile.getNativePtr(), sig);
+                if (tagData != null) {
+                    t = new TagData(sig, tagData);
+                    tags.put(sig, t);
+                }
+            }
+            return t;
+        }
+
+        void clear() {
+            tags.clear();
+        }
+    }
+
+    static class TagData {
+        private int signature;
+        private byte[] data;
+
+        TagData(int sig, byte[] data) {
+            this.signature = sig;
+            this.data = data;
+        }
+
+        int getSize() {
+            return data.length;
+        }
+
+        byte[] getData() {
+            return Arrays.copyOf(data, data.length);
+        }
+
+        void copyDataTo(byte[] dst) {
+            System.arraycopy(data, 0, dst, 0, data.length);
+        }
+
+        int getSignature() {
+            return signature;
+        }
+    }
+}
--- a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java	Wed Jul 05 19:11:53 2017 +0200
@@ -62,7 +62,7 @@
     private boolean isOutIntPacked = false;
 
     ICC_Profile[] profiles;
-    long [] profileIDs;
+    LCMSProfile[] lcmsProfiles;
     int renderType;
     int transformType;
 
@@ -84,8 +84,8 @@
         /* Actually, it is not a complete transform but just part of it */
         profiles = new ICC_Profile[1];
         profiles[0] = profile;
-        profileIDs = new long[1];
-        profileIDs[0] = LCMS.getProfileID(profile);
+        lcmsProfiles = new LCMSProfile[1];
+        lcmsProfiles[0] = LCMS.getProfileID(profile);
         this.renderType = (renderType == ColorTransform.Any)?
                               ICC_Profile.icPerceptual : renderType;
         this.transformType = transformType;
@@ -105,14 +105,14 @@
             size+=((LCMSTransform)transforms[i]).profiles.length;
         }
         profiles = new ICC_Profile[size];
-        profileIDs = new long[size];
+        lcmsProfiles = new LCMSProfile[size];
         int j = 0;
         for (int i=0; i < transforms.length; i++) {
             LCMSTransform curTrans = (LCMSTransform)transforms[i];
             System.arraycopy(curTrans.profiles, 0, profiles, j,
                              curTrans.profiles.length);
-            System.arraycopy(curTrans.profileIDs, 0, profileIDs, j,
-                             curTrans.profileIDs.length);
+            System.arraycopy(curTrans.lcmsProfiles, 0, lcmsProfiles, j,
+                             curTrans.lcmsProfiles.length);
             j += curTrans.profiles.length;
         }
         renderType = ((LCMSTransform)transforms[0]).renderType;
@@ -152,7 +152,7 @@
             outFormatter = out.pixelType;
             isOutIntPacked = out.isIntPacked;
 
-            ID = LCMS.createNativeTransform(profileIDs, renderType,
+            ID = LCMS.createTransform(lcmsProfiles, renderType,
                                             inFormatter, isInIntPacked,
                                             outFormatter, isOutIntPacked,
                                             disposerReferent);
--- a/jdk/src/share/classes/sun/misc/JavaAWTAccess.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/misc/JavaAWTAccess.java	Wed Jul 05 19:11:53 2017 +0200
@@ -26,14 +26,16 @@
 package sun.misc;
 
 public interface JavaAWTAccess {
-    public Object getContext();
-    public Object getExecutionContext();
 
-    public Object get(Object context, Object key);
-    public void put(Object context, Object key, Object value);
-    public void remove(Object context, Object key);
+    // Returns the AppContext used for applet logging isolation, or null if
+    // no isolation is required.
+    // If there's no applet, or if the caller is a stand alone application,
+    // or running in the main app context, returns null.
+    // Otherwise, returns the AppContext of the calling applet.
+    public Object getAppletContext();
 
-    // convenience methods whose context is the object returned by getContext()
+    // convenience methods to cache objects in the current thread group's
+    // AppContext
     public Object get(Object key);
     public void put(Object key, Object value);
     public void remove(Object key);
--- a/jdk/src/share/classes/sun/misc/SharedSecrets.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/misc/SharedSecrets.java	Wed Jul 05 19:11:53 2017 +0200
@@ -170,7 +170,7 @@
     public static JavaAWTAccess getJavaAWTAccess() {
         // this may return null in which case calling code needs to
         // provision for.
-        if (javaAWTAccess == null || javaAWTAccess.getContext() == null) {
+        if (javaAWTAccess == null) {
             return null;
         }
         return javaAWTAccess;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/print/DocumentPropertiesUI.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.print;
+
+import java.awt.Window;
+import java.awt.print.PrinterJob;
+import javax.print.PrintService;
+import javax.print.ServiceUIFactory;
+import javax.print.attribute.PrintRequestAttributeSet;
+
+public abstract class DocumentPropertiesUI {
+
+    /**
+     * For Win32 doc properties sheet.
+     */
+    public static final int
+        DOCUMENTPROPERTIES_ROLE = ServiceUIFactory.RESERVED_UIROLE +100;
+
+    /**
+     * Name of (this) abstract class for Document Properties.
+     */
+    public static final String
+        DOCPROPERTIESCLASSNAME = DocumentPropertiesUI.class.getName();
+
+    /**
+     * Invokes whatever code is needed to display a native dialog
+     * with the specified owner. The owner should be the cross-platform
+     * dialog. If the user cancels the dialog the return value is null.
+     * A non-null return value is always a new attribute set (or is it?)
+     * The cross-platform dialog may need to be updated to reflect the
+     * updated properties.
+     */
+    public abstract PrintRequestAttributeSet
+        showDocumentProperties(PrinterJob job,
+                               Window owner,
+                               PrintService service,
+                               PrintRequestAttributeSet aset);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/print/PrinterJobWrapper.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.print;
+
+import java.awt.print.PrinterJob;
+import javax.print.attribute.PrintRequestAttribute;
+
+public class PrinterJobWrapper implements PrintRequestAttribute {
+
+    private static final long serialVersionUID = -8792124426995707237L;
+
+    private PrinterJob job;
+
+    public PrinterJobWrapper(PrinterJob job) {
+        this.job = job;
+    }
+
+    public PrinterJob getPrinterJob() {
+        return job;
+    }
+
+    public final Class getCategory() {
+        return PrinterJobWrapper.class;
+    }
+
+    public final String getName() {
+        return "printerjob-wrapper";
+    }
+
+    public String toString() {
+       return "printerjob-wrapper: " + job.toString();
+    }
+
+    public int hashCode() {
+        return job.hashCode();
+    }
+}
--- a/jdk/src/share/classes/sun/print/RasterPrinterJob.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/print/RasterPrinterJob.java	Wed Jul 05 19:11:53 2017 +0200
@@ -903,6 +903,9 @@
         int x = bounds.x+bounds.width/3;
         int y = bounds.y+bounds.height/3;
         PrintService newService;
+        // temporarily add an attribute pointing back to this job.
+        PrinterJobWrapper jobWrapper = new PrinterJobWrapper(this);
+        attributes.add(jobWrapper);
         try {
             newService =
             ServiceUI.printDialog(gc, x, y,
@@ -915,6 +918,7 @@
                                   DocFlavor.SERVICE_FORMATTED.PAGEABLE,
                                   attributes);
         }
+        attributes.remove(PrinterJobWrapper.class);
 
         if (newService == null) {
             return false;
--- a/jdk/src/share/classes/sun/print/ServiceDialog.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/print/ServiceDialog.java	Wed Jul 05 19:11:53 2017 +0200
@@ -46,6 +46,7 @@
 import java.awt.event.ItemListener;
 import java.awt.event.WindowEvent;
 import java.awt.event.WindowAdapter;
+import java.awt.print.PrinterJob;
 import java.io.File;
 import java.io.FilePermission;
 import java.io.IOException;
@@ -119,8 +120,6 @@
     private AppearancePanel pnlAppearance;
 
     private boolean isAWT = false;
-
-
     static {
         initResource();
     }
@@ -801,9 +800,32 @@
                     if (dialog != null) {
                         dialog.show();
                     } else {
-                        // REMIND: may want to notify the user why we're
-                        //         disabling the button
-                        btnProperties.setEnabled(false);
+                        DocumentPropertiesUI docPropertiesUI = null;
+                        try {
+                            docPropertiesUI =
+                                (DocumentPropertiesUI)uiFactory.getUI
+                                (DocumentPropertiesUI.DOCUMENTPROPERTIES_ROLE,
+                                 DocumentPropertiesUI.DOCPROPERTIESCLASSNAME);
+                        } catch (Exception ex) {
+                        }
+                        if (docPropertiesUI != null) {
+                            PrinterJobWrapper wrapper = (PrinterJobWrapper)
+                                asCurrent.get(PrinterJobWrapper.class);
+                            if (wrapper == null) {
+                                return; // should not happen, defensive only.
+                            }
+                            PrinterJob job = wrapper.getPrinterJob();
+                            if (job == null) {
+                                return;  // should not happen, defensive only.
+                            }
+                            PrintRequestAttributeSet newAttrs =
+                               docPropertiesUI.showDocumentProperties
+                               (job, ServiceDialog.this, psCurrent, asCurrent);
+                            if (newAttrs != null) {
+                                asCurrent.addAll(newAttrs);
+                                updatePanels();
+                            }
+                        }
                     }
                 }
             }
--- a/jdk/src/share/classes/sun/security/provider/certpath/OCSPResponse.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/security/provider/certpath/OCSPResponse.java	Wed Jul 05 19:11:53 2017 +0200
@@ -385,12 +385,12 @@
         switch (responseStatus) {
             case SUCCESSFUL:
                 break;
-            case UNAUTHORIZED:
             case TRY_LATER:
             case INTERNAL_ERROR:
                 throw new CertPathValidatorException(
                     "OCSP response error: " + responseStatus, null, null, -1,
                     BasicReason.UNDETERMINED_REVOCATION_STATUS);
+            case UNAUTHORIZED:
             default:
                 throw new CertPathValidatorException("OCSP response error: " +
                                                      responseStatus);
--- a/jdk/src/share/classes/sun/security/ssl/Handshaker.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/security/ssl/Handshaker.java	Wed Jul 05 19:11:53 2017 +0200
@@ -145,6 +145,14 @@
     /* True if it's OK to start a new SSL session */
     boolean             enableNewSession;
 
+    // Whether local cipher suites preference should be honored during
+    // handshaking?
+    //
+    // Note that in this provider, this option only applies to server side.
+    // Local cipher suites preference is always honored in client side in
+    // this provider.
+    boolean preferLocalCipherSuites = false;
+
     // Temporary storage for the individual keys. Set by
     // calculateConnectionKeys() and cleared once the ciphers are
     // activated.
@@ -463,6 +471,13 @@
     }
 
     /**
+     * Sets the cipher suites preference.
+     */
+    void setUseCipherSuitesOrder(boolean on) {
+        this.preferLocalCipherSuites = on;
+    }
+
+    /**
      * Prior to handshaking, activate the handshake and initialize the version,
      * input stream and output stream.
      */
@@ -533,7 +548,9 @@
     }
 
     /**
-     * Check if the given ciphersuite is enabled and available.
+     * Check if the given ciphersuite is enabled and available within the
+     * current active cipher suites.
+     *
      * Does not check if the required server certificates are available.
      */
     boolean isNegotiable(CipherSuite s) {
@@ -541,7 +558,17 @@
             activeCipherSuites = getActiveCipherSuites();
         }
 
-        return activeCipherSuites.contains(s) && s.isNegotiable();
+        return isNegotiable(activeCipherSuites, s);
+    }
+
+    /**
+     * Check if the given ciphersuite is enabled and available within the
+     * proposed cipher suite list.
+     *
+     * Does not check if the required server certificates are available.
+     */
+    final static boolean isNegotiable(CipherSuiteList proposed, CipherSuite s) {
+        return proposed.contains(s) && s.isNegotiable();
     }
 
     /**
--- a/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java	Wed Jul 05 19:11:53 2017 +0200
@@ -320,6 +320,12 @@
     private boolean isFirstAppOutputRecord = true;
 
     /*
+     * Whether local cipher suites preference in server side should be
+     * honored during handshaking?
+     */
+    private boolean preferLocalCipherSuites = false;
+
+    /*
      * Class and subclass dynamic debugging support
      */
     private static final Debug debug = Debug.getInstance("ssl");
@@ -470,6 +476,7 @@
                     protocolVersion, connectionState == cs_HANDSHAKE,
                     secureRenegotiation, clientVerifyData, serverVerifyData);
             handshaker.setSNIMatchers(sniMatchers);
+            handshaker.setUseCipherSuitesOrder(preferLocalCipherSuites);
         } else {
             handshaker = new ClientHandshaker(this, sslContext,
                     enabledProtocols,
@@ -2074,6 +2081,7 @@
         params.setAlgorithmConstraints(algorithmConstraints);
         params.setSNIMatchers(sniMatchers);
         params.setServerNames(serverNames);
+        params.setUseCipherSuitesOrder(preferLocalCipherSuites);
 
         return params;
     }
@@ -2088,6 +2096,7 @@
         // the super implementation does not handle the following parameters
         identificationProtocol = params.getEndpointIdentificationAlgorithm();
         algorithmConstraints = params.getAlgorithmConstraints();
+        preferLocalCipherSuites = params.getUseCipherSuitesOrder();
 
         List<SNIServerName> sniNames = params.getServerNames();
         if (sniNames != null) {
@@ -2104,6 +2113,7 @@
             handshaker.setAlgorithmConstraints(algorithmConstraints);
             if (roleIsServer) {
                 handshaker.setSNIMatchers(sniMatchers);
+                handshaker.setUseCipherSuitesOrder(preferLocalCipherSuites);
             } else {
                 handshaker.setSNIServerNames(serverNames);
             }
--- a/jdk/src/share/classes/sun/security/ssl/SSLServerSocketImpl.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/security/ssl/SSLServerSocketImpl.java	Wed Jul 05 19:11:53 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -92,6 +92,12 @@
     Collection<SNIMatcher>      sniMatchers =
                                     Collections.<SNIMatcher>emptyList();
 
+    /*
+     * Whether local cipher suites preference in server side should be
+     * honored during handshaking?
+     */
+    private boolean             preferLocalCipherSuites = false;
+
     /**
      * Create an SSL server socket on a port, using a non-default
      * authentication context and a specified connection backlog.
@@ -304,6 +310,8 @@
         params.setEndpointIdentificationAlgorithm(identificationProtocol);
         params.setAlgorithmConstraints(algorithmConstraints);
         params.setSNIMatchers(sniMatchers);
+        params.setUseCipherSuitesOrder(preferLocalCipherSuites);
+
 
         return params;
     }
@@ -318,6 +326,7 @@
         // the super implementation does not handle the following parameters
         identificationProtocol = params.getEndpointIdentificationAlgorithm();
         algorithmConstraints = params.getAlgorithmConstraints();
+        preferLocalCipherSuites = params.getUseCipherSuitesOrder();
         Collection<SNIMatcher> matchers = params.getSNIMatchers();
         if (matchers != null) {
             sniMatchers = params.getSNIMatchers();
@@ -334,7 +343,7 @@
         SSLSocketImpl s = new SSLSocketImpl(sslContext, useServerMode,
             enabledCipherSuites, doClientAuth, enableSessionCreation,
             enabledProtocols, identificationProtocol, algorithmConstraints,
-            sniMatchers);
+            sniMatchers, preferLocalCipherSuites);
 
         implAccept(s);
         s.doneConnect();
--- a/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java	Wed Jul 05 19:11:53 2017 +0200
@@ -377,6 +377,12 @@
      */
     private ByteArrayOutputStream heldRecordBuffer = null;
 
+    /*
+     * Whether local cipher suites preference in server side should be
+     * honored during handshaking?
+     */
+    private boolean preferLocalCipherSuites = false;
+
     //
     // CONSTRUCTORS AND INITIALIZATION CODE
     //
@@ -482,7 +488,8 @@
             boolean sessionCreation, ProtocolList protocols,
             String identificationProtocol,
             AlgorithmConstraints algorithmConstraints,
-            Collection<SNIMatcher> sniMatchers) throws IOException {
+            Collection<SNIMatcher> sniMatchers,
+            boolean preferLocalCipherSuites) throws IOException {
 
         super();
         doClientAuth = clientAuth;
@@ -490,6 +497,7 @@
         this.identificationProtocol = identificationProtocol;
         this.algorithmConstraints = algorithmConstraints;
         this.sniMatchers = sniMatchers;
+        this.preferLocalCipherSuites = preferLocalCipherSuites;
         init(context, serverMode);
 
         /*
@@ -1284,6 +1292,7 @@
                     protocolVersion, connectionState == cs_HANDSHAKE,
                     secureRenegotiation, clientVerifyData, serverVerifyData);
             handshaker.setSNIMatchers(sniMatchers);
+            handshaker.setUseCipherSuitesOrder(preferLocalCipherSuites);
         } else {
             handshaker = new ClientHandshaker(this, sslContext,
                     enabledProtocols,
@@ -2502,6 +2511,7 @@
         params.setAlgorithmConstraints(algorithmConstraints);
         params.setSNIMatchers(sniMatchers);
         params.setServerNames(serverNames);
+        params.setUseCipherSuitesOrder(preferLocalCipherSuites);
 
         return params;
     }
@@ -2516,6 +2526,7 @@
         // the super implementation does not handle the following parameters
         identificationProtocol = params.getEndpointIdentificationAlgorithm();
         algorithmConstraints = params.getAlgorithmConstraints();
+        preferLocalCipherSuites = params.getUseCipherSuitesOrder();
 
         List<SNIServerName> sniNames = params.getServerNames();
         if (sniNames != null) {
@@ -2532,6 +2543,7 @@
             handshaker.setAlgorithmConstraints(algorithmConstraints);
             if (roleIsServer) {
                 handshaker.setSNIMatchers(sniMatchers);
+                handshaker.setUseCipherSuitesOrder(preferLocalCipherSuites);
             } else {
                 handshaker.setSNIServerNames(serverNames);
             }
--- a/jdk/src/share/classes/sun/security/ssl/ServerHandshaker.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/security/ssl/ServerHandshaker.java	Wed Jul 05 19:11:53 2017 +0200
@@ -932,8 +932,18 @@
      * the cipherSuite and keyExchange variables.
      */
     private void chooseCipherSuite(ClientHello mesg) throws IOException {
-        for (CipherSuite suite : mesg.getCipherSuites().collection()) {
-            if (isNegotiable(suite) == false) {
+        CipherSuiteList prefered;
+        CipherSuiteList proposed;
+        if (preferLocalCipherSuites) {
+            prefered = getActiveCipherSuites();
+            proposed = mesg.getCipherSuites();
+        } else {
+            prefered = mesg.getCipherSuites();
+            proposed = getActiveCipherSuites();
+        }
+
+        for (CipherSuite suite : prefered.collection()) {
+            if (isNegotiable(proposed, suite) == false) {
                 continue;
             }
 
@@ -948,8 +958,7 @@
             }
             return;
         }
-        fatalSE(Alerts.alert_handshake_failure,
-                    "no cipher suites in common");
+        fatalSE(Alerts.alert_handshake_failure, "no cipher suites in common");
     }
 
     /**
--- a/jdk/src/share/classes/sun/swing/SwingUtilities2.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/swing/SwingUtilities2.java	Wed Jul 05 19:11:53 2017 +0200
@@ -1184,7 +1184,7 @@
                canAccess = true;
            } else {
                try {
-                   sm.checkSystemClipboardAccess();
+                   sm.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
                    canAccess = true;
                } catch (SecurityException e) {
                }
--- a/jdk/src/share/classes/sun/tools/jar/resources/jar.properties	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/tools/jar/resources/jar.properties	Wed Jul 05 19:11:53 2017 +0200
@@ -61,7 +61,7 @@
 out.extracted=\
         extracted: {0}
 out.inflated=\
-        \ \inflated: {0}
+        \ inflated: {0}
 out.size=\
         (in = {0}) (out= {1})
 
--- a/jdk/src/share/classes/sun/tools/jconsole/Resources.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/tools/jconsole/Resources.java	Wed Jul 05 19:11:53 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,7 +30,7 @@
 import java.lang.reflect.Modifier;
 import java.text.MessageFormat;
 import java.util.Collections;
-import java.util.HashMap;
+import java.util.IdentityHashMap;
 import java.util.Map;
 import java.util.MissingResourceException;
 import java.util.ResourceBundle;
@@ -40,7 +40,7 @@
  */
 public final class Resources {
     private static Map<String, Integer> MNEMONIC_LOOKUP = Collections
-            .synchronizedMap(new HashMap<String, Integer>());
+            .synchronizedMap(new IdentityHashMap<String, Integer>());
 
     private Resources() {
         throw new AssertionError();
--- a/jdk/src/share/classes/sun/tracing/ProviderSkeleton.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/tracing/ProviderSkeleton.java	Wed Jul 05 19:11:53 2017 +0200
@@ -164,7 +164,10 @@
                     declaringClass == Object.class) {
                     return method.invoke(this, args);
                 } else {
-                    assert false;
+                    // assert false : "this should never happen"
+                    //    reaching here would indicate a breach
+                    //    in security in the higher layers
+                    throw new SecurityException();
                 }
             } catch (IllegalAccessException e) {
                 assert false;
--- a/jdk/src/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/util/locale/provider/JRELocaleProviderAdapter.java	Wed Jul 05 19:11:53 2017 +0200
@@ -361,7 +361,7 @@
         while (tokens.hasMoreTokens()) {
             String token = tokens.nextToken();
             if (token.equals("|")) {
-                if (isNonUSLangSupported()) {
+                if (isNonENLangSupported()) {
                     continue;
                 }
                 break;
@@ -398,7 +398,7 @@
          */
         int barIndex = supportedLocaleString.indexOf('|');
         StringTokenizer localeStringTokenizer;
-        if (isNonUSLangSupported()) {
+        if (isNonENLangSupported()) {
             localeStringTokenizer = new StringTokenizer(supportedLocaleString.substring(0, barIndex)
                     + supportedLocaleString.substring(barIndex + 1));
         } else {
@@ -427,17 +427,17 @@
         return locales;
     }
 
-    private static volatile Boolean isNonUSSupported = null;
+    private static volatile Boolean isNonENSupported = null;
 
     /*
-     * Returns true if the non US resources jar file exists in jre
+     * Returns true if the non EN resources jar file exists in jre
      * extension directory. @returns true if the jar file is there. Otherwise,
      * returns false.
      */
-    private static boolean isNonUSLangSupported() {
-        if (isNonUSSupported == null) {
+    private static boolean isNonENLangSupported() {
+        if (isNonENSupported == null) {
             synchronized (JRELocaleProviderAdapter.class) {
-                if (isNonUSSupported == null) {
+                if (isNonENSupported == null) {
                     final String sep = File.separator;
                     String localeDataJar =
                             java.security.AccessController.doPrivileged(
@@ -449,7 +449,7 @@
                      * localedata.jar is installed or not.
                      */
                     final File f = new File(localeDataJar);
-                    isNonUSSupported =
+                    isNonENSupported =
                         AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
                             @Override
                             public Boolean run() {
@@ -459,6 +459,6 @@
                }
             }
         }
-        return isNonUSSupported;
+        return isNonENSupported;
     }
 }
--- a/jdk/src/share/classes/sun/util/locale/provider/LocaleDataMetaInfo-XLocales.java.template	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/util/locale/provider/LocaleDataMetaInfo-XLocales.java.template	Wed Jul 05 19:11:53 2017 +0200
@@ -52,25 +52,25 @@
            look up locale string such as "en" could be based on if it contains " en ".
         */
         resourceNameToLocales.put("FormatData",
-                                  " #FormatData_USLocales# | #FormatData_NonUSLocales# ");
+                                  " #FormatData_ENLocales# | #FormatData_NonENLocales# ");
 
         resourceNameToLocales.put("CollationData",
-                                  " #CollationData_USLocales# | #CollationData_NonUSLocales# ");
+                                  " #CollationData_ENLocales# | #CollationData_NonENLocales# ");
 
         resourceNameToLocales.put("TimeZoneNames",
-                                  " #TimeZoneNames_USLocales# | #TimeZoneNames_NonUSLocales# ");
+                                  " #TimeZoneNames_ENLocales# | #TimeZoneNames_NonENLocales# ");
 
         resourceNameToLocales.put("LocaleNames",
-                                  " #LocaleNames_USLocales# | #LocaleNames_NonUSLocales# ");
+                                  " #LocaleNames_ENLocales# | #LocaleNames_NonENLocales# ");
 
         resourceNameToLocales.put("CurrencyNames",
-                                  " #CurrencyNames_USLocales# | #CurrencyNames_NonUSLocales# ");
+                                  " #CurrencyNames_ENLocales# | #CurrencyNames_NonENLocales# ");
 
         resourceNameToLocales.put("CalendarData",
-                                  " #CalendarData_USLocales# | #CalendarData_NonUSLocales# ");
+                                  " #CalendarData_ENLocales# | #CalendarData_NonENLocales# ");
 
         resourceNameToLocales.put("AvailableLocales",
-                                  " #AvailableLocales_USLocales# | #AvailableLocales_NonUSLocales# ");
+                                  " #AvailableLocales_ENLocales# | #AvailableLocales_NonENLocales# ");
     }
 
     /*
--- a/jdk/src/share/classes/sun/util/locale/provider/LocaleResources.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/util/locale/provider/LocaleResources.java	Wed Jul 05 19:11:53 2017 +0200
@@ -252,7 +252,7 @@
 
     String[] getTimeZoneNames(String key, int size) {
         String[] names = null;
-        String cacheKey = TIME_ZONE_NAMES + key;
+        String cacheKey = TIME_ZONE_NAMES + size + '.' + key;
 
         removeEmptyReferences();
         ResourceReference data = cache.get(cacheKey);
--- a/jdk/src/share/classes/sun/util/logging/resources/logging.properties	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/util/logging/resources/logging.properties	Wed Jul 05 19:11:53 2017 +0200
@@ -27,20 +27,20 @@
 # these are the same as the non-localized level name.
 
 # The following ALL CAPS words should be translated.
-ALL=ALL
+ALL=All
 # The following ALL CAPS words should be translated.
-SEVERE=SEVERE
+SEVERE=Severe
 # The following ALL CAPS words should be translated.
-WARNING=WARNING
+WARNING=Warning
 # The following ALL CAPS words should be translated.
-INFO=INFO
+INFO=Info
 # The following ALL CAPS words should be translated.
-CONFIG= CONFIG
+CONFIG= Config
 # The following ALL CAPS words should be translated.
-FINE=FINE
+FINE=Fine
 # The following ALL CAPS words should be translated.
-FINER=FINER
+FINER=Finer
 # The following ALL CAPS words should be translated.
-FINEST=FINEST
+FINEST=Finest
 # The following ALL CAPS words should be translated.
-OFF=OFF
+OFF=Off
--- a/jdk/src/share/classes/sun/util/logging/resources/logging_de.properties	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/util/logging/resources/logging_de.properties	Wed Jul 05 19:11:53 2017 +0200
@@ -27,20 +27,20 @@
 # these are the same as the non-localized level name.
 
 # The following ALL CAPS words should be translated.
-ALL=ALL
+ALL=Alle
 # The following ALL CAPS words should be translated.
-SEVERE=SEVERE
+SEVERE=Schwerwiegend
 # The following ALL CAPS words should be translated.
-WARNING=WARNING
+WARNING=Warnung
 # The following ALL CAPS words should be translated.
-INFO=INFO
+INFO=Information
 # The following ALL CAPS words should be translated.
-CONFIG= CONFIG
+CONFIG= Konfiguration
 # The following ALL CAPS words should be translated.
-FINE=FINE
+FINE=Fein
 # The following ALL CAPS words should be translated.
-FINER=FINER
+FINER=Feiner
 # The following ALL CAPS words should be translated.
-FINEST=FINEST
+FINEST=Am feinsten
 # The following ALL CAPS words should be translated.
-OFF=OFF
+OFF=Deaktiviert
--- a/jdk/src/share/classes/sun/util/logging/resources/logging_es.properties	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/util/logging/resources/logging_es.properties	Wed Jul 05 19:11:53 2017 +0200
@@ -27,20 +27,20 @@
 # these are the same as the non-localized level name.
 
 # The following ALL CAPS words should be translated.
-ALL=ALL
+ALL=Todo
 # The following ALL CAPS words should be translated.
-SEVERE=SEVERE
+SEVERE=Grave
 # The following ALL CAPS words should be translated.
-WARNING=WARNING
+WARNING=Advertencia
 # The following ALL CAPS words should be translated.
-INFO=INFO
+INFO=Informaci\u00F3n
 # The following ALL CAPS words should be translated.
-CONFIG= CONFIG
+CONFIG= Configurar
 # The following ALL CAPS words should be translated.
-FINE=FINE
+FINE=Detallado
 # The following ALL CAPS words should be translated.
-FINER=FINER
+FINER=Muy Detallado
 # The following ALL CAPS words should be translated.
-FINEST=FINEST
+FINEST=M\u00E1s Detallado
 # The following ALL CAPS words should be translated.
-OFF=OFF
+OFF=Desactivado
--- a/jdk/src/share/classes/sun/util/logging/resources/logging_fr.properties	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/util/logging/resources/logging_fr.properties	Wed Jul 05 19:11:53 2017 +0200
@@ -27,20 +27,20 @@
 # these are the same as the non-localized level name.
 
 # The following ALL CAPS words should be translated.
-ALL=ALL
+ALL=Tout
 # The following ALL CAPS words should be translated.
-SEVERE=SEVERE
+SEVERE=Grave
 # The following ALL CAPS words should be translated.
-WARNING=WARNING
+WARNING=Avertissement
 # The following ALL CAPS words should be translated.
-INFO=INFO
+INFO=Infos
 # The following ALL CAPS words should be translated.
-CONFIG= CONFIG
+CONFIG= Config
 # The following ALL CAPS words should be translated.
-FINE=FINE
+FINE=Pr\u00E9cis
 # The following ALL CAPS words should be translated.
-FINER=FINER
+FINER=Plus pr\u00E9cis
 # The following ALL CAPS words should be translated.
-FINEST=FINEST
+FINEST=Le plus pr\u00E9cis
 # The following ALL CAPS words should be translated.
-OFF=OFF
+OFF=D\u00E9sactiv\u00E9
--- a/jdk/src/share/classes/sun/util/logging/resources/logging_it.properties	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/util/logging/resources/logging_it.properties	Wed Jul 05 19:11:53 2017 +0200
@@ -27,20 +27,20 @@
 # these are the same as the non-localized level name.
 
 # The following ALL CAPS words should be translated.
-ALL=ALL
+ALL=Tutto
 # The following ALL CAPS words should be translated.
-SEVERE=SEVERE
+SEVERE=Grave
 # The following ALL CAPS words should be translated.
-WARNING=WARNING
+WARNING=Avvertenza
 # The following ALL CAPS words should be translated.
-INFO=INFO
+INFO=Informazioni
 # The following ALL CAPS words should be translated.
-CONFIG= CONFIG
+CONFIG= Configurazione
 # The following ALL CAPS words should be translated.
-FINE=FINE
+FINE=Buono
 # The following ALL CAPS words should be translated.
-FINER=FINER
+FINER=Migliore
 # The following ALL CAPS words should be translated.
-FINEST=FINEST
+FINEST=Ottimale
 # The following ALL CAPS words should be translated.
-OFF=OFF
+OFF=Non attivo
--- a/jdk/src/share/classes/sun/util/logging/resources/logging_ja.properties	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/util/logging/resources/logging_ja.properties	Wed Jul 05 19:11:53 2017 +0200
@@ -29,18 +29,18 @@
 # The following ALL CAPS words should be translated.
 ALL=\u3059\u3079\u3066
 # The following ALL CAPS words should be translated.
-SEVERE=SEVERE
+SEVERE=\u91CD\u5927
 # The following ALL CAPS words should be translated.
-WARNING=WARNING
+WARNING=\u8B66\u544A
 # The following ALL CAPS words should be translated.
 INFO=\u60C5\u5831
 # The following ALL CAPS words should be translated.
-CONFIG= CONFIG
+CONFIG= \u69CB\u6210
 # The following ALL CAPS words should be translated.
-FINE=\u8A73\u7D30\u30EC\u30D9\u30EB(\u4F4E)
+FINE=\u666E\u901A
 # The following ALL CAPS words should be translated.
-FINER=FINER
+FINER=\u8A73\u7D30
 # The following ALL CAPS words should be translated.
-FINEST=FINEST
+FINEST=\u6700\u3082\u8A73\u7D30
 # The following ALL CAPS words should be translated.
 OFF=\u30AA\u30D5
--- a/jdk/src/share/classes/sun/util/logging/resources/logging_ko.properties	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/util/logging/resources/logging_ko.properties	Wed Jul 05 19:11:53 2017 +0200
@@ -27,20 +27,20 @@
 # these are the same as the non-localized level name.
 
 # The following ALL CAPS words should be translated.
-ALL=ALL
+ALL=\uBAA8\uB450
 # The following ALL CAPS words should be translated.
-SEVERE=SEVERE
+SEVERE=\uC2EC\uAC01
 # The following ALL CAPS words should be translated.
-WARNING=WARNING
+WARNING=\uACBD\uACE0
 # The following ALL CAPS words should be translated.
-INFO=INFO
+INFO=\uC815\uBCF4
 # The following ALL CAPS words should be translated.
-CONFIG= CONFIG
+CONFIG= \uAD6C\uC131
 # The following ALL CAPS words should be translated.
-FINE=FINE
+FINE=\uBBF8\uC138
 # The following ALL CAPS words should be translated.
-FINER=FINER
+FINER=\uBCF4\uB2E4 \uBBF8\uC138
 # The following ALL CAPS words should be translated.
-FINEST=FINEST
+FINEST=\uAC00\uC7A5 \uBBF8\uC138
 # The following ALL CAPS words should be translated.
-OFF=OFF
+OFF=\uD574\uC81C
--- a/jdk/src/share/classes/sun/util/logging/resources/logging_pt_BR.properties	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/util/logging/resources/logging_pt_BR.properties	Wed Jul 05 19:11:53 2017 +0200
@@ -27,20 +27,20 @@
 # these are the same as the non-localized level name.
 
 # The following ALL CAPS words should be translated.
-ALL=ALL
+ALL=Tudo
 # The following ALL CAPS words should be translated.
-SEVERE=SEVERE
+SEVERE=Grave
 # The following ALL CAPS words should be translated.
-WARNING=WARNING
+WARNING=Advert\u00EAncia
 # The following ALL CAPS words should be translated.
-INFO=INFO
+INFO=Informa\u00E7\u00F5es
 # The following ALL CAPS words should be translated.
-CONFIG= CONFIG
+CONFIG= Configura\u00E7\u00E3o
 # The following ALL CAPS words should be translated.
-FINE=FINE
+FINE=Detalhado
 # The following ALL CAPS words should be translated.
-FINER=FINER
+FINER=Mais Detalhado
 # The following ALL CAPS words should be translated.
-FINEST=FINEST
+FINEST=O Mais Detalhado
 # The following ALL CAPS words should be translated.
-OFF=OFF
+OFF=Desativado
--- a/jdk/src/share/classes/sun/util/logging/resources/logging_sv.properties	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/util/logging/resources/logging_sv.properties	Wed Jul 05 19:11:53 2017 +0200
@@ -27,20 +27,20 @@
 # these are the same as the non-localized level name.
 
 # The following ALL CAPS words should be translated.
-ALL=ALLA
+ALL=Alla
 # The following ALL CAPS words should be translated.
-SEVERE=SEVERE
+SEVERE=Allvarlig
 # The following ALL CAPS words should be translated.
-WARNING=WARNING
+WARNING=Varning
 # The following ALL CAPS words should be translated.
-INFO=INFO
+INFO=Info
 # The following ALL CAPS words should be translated.
-CONFIG= CONFIG
+CONFIG= Konfig
 # The following ALL CAPS words should be translated.
-FINE=FINE
+FINE=Fin
 # The following ALL CAPS words should be translated.
-FINER=FINER
+FINER=Finare
 # The following ALL CAPS words should be translated.
-FINEST=FINEST
+FINEST=Finaste
 # The following ALL CAPS words should be translated.
-OFF=OFF
+OFF=Av
--- a/jdk/src/share/classes/sun/util/logging/resources/logging_zh_CN.properties	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/util/logging/resources/logging_zh_CN.properties	Wed Jul 05 19:11:53 2017 +0200
@@ -27,20 +27,20 @@
 # these are the same as the non-localized level name.
 
 # The following ALL CAPS words should be translated.
-ALL=ALL
+ALL=\u5168\u90E8
 # The following ALL CAPS words should be translated.
-SEVERE=SEVERE
+SEVERE=\u4E25\u91CD
 # The following ALL CAPS words should be translated.
-WARNING=WARNING
+WARNING=\u8B66\u544A
 # The following ALL CAPS words should be translated.
-INFO=INFO
+INFO=\u4FE1\u606F
 # The following ALL CAPS words should be translated.
-CONFIG= CONFIG
+CONFIG= \u914D\u7F6E
 # The following ALL CAPS words should be translated.
-FINE=FINE
+FINE=\u8BE6\u7EC6
 # The following ALL CAPS words should be translated.
-FINER=FINER
+FINER=\u8F83\u8BE6\u7EC6
 # The following ALL CAPS words should be translated.
-FINEST=FINEST
+FINEST=\u975E\u5E38\u8BE6\u7EC6
 # The following ALL CAPS words should be translated.
-OFF=OFF
+OFF=\u7981\u7528
--- a/jdk/src/share/classes/sun/util/logging/resources/logging_zh_TW.properties	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/classes/sun/util/logging/resources/logging_zh_TW.properties	Wed Jul 05 19:11:53 2017 +0200
@@ -27,20 +27,20 @@
 # these are the same as the non-localized level name.
 
 # The following ALL CAPS words should be translated.
-ALL=\u6240\u6709
+ALL=\u5168\u90E8
 # The following ALL CAPS words should be translated.
-SEVERE=SEVERE
+SEVERE=\u56B4\u91CD
 # The following ALL CAPS words should be translated.
-WARNING=WARNING
+WARNING=\u8B66\u544A
 # The following ALL CAPS words should be translated.
 INFO=\u8CC7\u8A0A
 # The following ALL CAPS words should be translated.
-CONFIG= CONFIG
+CONFIG= \u7D44\u614B
 # The following ALL CAPS words should be translated.
 FINE=\u8A73\u7D30
 # The following ALL CAPS words should be translated.
-FINER=FINER
+FINER=\u8F03\u8A73\u7D30
 # The following ALL CAPS words should be translated.
-FINEST=FINEST
+FINEST=\u6700\u8A73\u7D30
 # The following ALL CAPS words should be translated.
 OFF=\u95DC\u9589
--- a/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c	Wed Jul 05 19:11:53 2017 +0200
@@ -930,9 +930,10 @@
      * Now fill a complete buffer, or as much of one as the stream
      * will give us if we are near the end.
      */
+    RELEASE_ARRAYS(env, data, src->next_input_byte);
+
     GET_IO_REF(input);
 
-    RELEASE_ARRAYS(env, data, src->next_input_byte);
     ret = (*env)->CallIntMethod(env,
                                 input,
                                 JPEGImageReader_readInputDataID,
@@ -1017,9 +1018,11 @@
         memcpy(sb->buf, src->next_input_byte, offset);
     }
 
-    GET_IO_REF(input);
 
     RELEASE_ARRAYS(env, data, src->next_input_byte);
+
+    GET_IO_REF(input);
+
     buflen = sb->bufferLength - offset;
     if (buflen <= 0) {
         if (!GET_ARRAYS(env, data, &(src->next_input_byte))) {
@@ -1121,9 +1124,10 @@
         return;
     }
 
+    RELEASE_ARRAYS(env, data, src->next_input_byte);
+
     GET_IO_REF(input);
 
-    RELEASE_ARRAYS(env, data, src->next_input_byte);
     ret = (*env)->CallLongMethod(env,
                                  input,
                                  JPEGImageReader_skipInputBytesID,
@@ -2306,10 +2310,10 @@
     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
     jobject output = NULL;
 
+    RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
+
     GET_IO_REF(output);
 
-    RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
-
     (*env)->CallVoidMethod(env,
                            output,
                            JPEGImageWriter_writeOutputDataID,
@@ -2348,10 +2352,10 @@
     if (datacount != 0) {
         jobject output = NULL;
 
+        RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
+
         GET_IO_REF(output);
 
-        RELEASE_ARRAYS(env, data, (const JOCTET *)(dest->next_output_byte));
-
         (*env)->CallVoidMethod(env,
                                output,
                                JPEGImageWriter_writeOutputDataID,
--- a/jdk/src/share/native/sun/font/layout/SunLayoutEngine.cpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/native/sun/font/layout/SunLayoutEngine.cpp	Wed Jul 05 19:11:53 2017 +0200
@@ -179,6 +179,10 @@
   FontInstanceAdapter fia(env, font2d, strike, mat, 72, 72, (le_int32) upem, (TTLayoutTableCache *) layoutTables);
   LEErrorCode success = LE_NO_ERROR;
   LayoutEngine *engine = LayoutEngine::layoutEngineFactory(&fia, script, lang, typo_flags & TYPO_MASK, success);
+  if (engine == NULL) {
+    env->SetIntField(gvdata, gvdCountFID, -1); // flag failure
+    return;
+  }
 
   if (min < 0) min = 0; if (max < min) max = min; /* defensive coding */
   // have to copy, yuck, since code does upcalls now.  this will be soooo slow
--- a/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/share/native/sun/java2d/cmm/lcms/LCMS.c	Wed Jul 05 19:11:53 2017 +0200
@@ -94,8 +94,12 @@
 # endif
 #endif
 
+typedef struct lcmsProfile_s {
+    cmsHPROFILE pf;
+} lcmsProfile_t, *lcmsProfile_p;
+
 typedef union storeID_s {    /* store SProfile stuff in a Java Long */
-    cmsHPROFILE pf;
+    lcmsProfile_p lcmsPf;
     cmsHTRANSFORM xf;
     jobject jobj;
     jlong j;
@@ -106,7 +110,6 @@
     jint j;
 } TagSignature_t, *TagSignature_p;
 
-static jfieldID Trans_profileIDs_fID;
 static jfieldID Trans_renderType_fID;
 static jfieldID Trans_ID_fID;
 static jfieldID IL_isIntPacked_fID;
@@ -118,7 +121,6 @@
 static jfieldID IL_width_fID;
 static jfieldID IL_height_fID;
 static jfieldID IL_imageAtOnce_fID;
-static jfieldID PF_ID_fID;
 
 JavaVM *javaVM;
 
@@ -145,6 +147,18 @@
     return JNI_VERSION_1_6;
 }
 
+void LCMS_freeProfile(JNIEnv *env, jlong ptr) {
+    storeID_t sProfile;
+    sProfile.j = ptr;
+
+    if (sProfile.lcmsPf != NULL) {
+        if (sProfile.lcmsPf->pf != NULL) {
+            cmsCloseProfile(sProfile.lcmsPf->pf);
+        }
+        free(sProfile.lcmsPf);
+    }
+}
+
 void LCMS_freeTransform(JNIEnv *env, jlong ID)
 {
     storeID_t sTrans;
@@ -170,7 +184,7 @@
     jlong* ids;
 
     size = (*env)->GetArrayLength (env, profileIDs);
-    ids = (*env)->GetPrimitiveArrayCritical(env, profileIDs, 0);
+    ids = (*env)->GetLongArrayElements(env, profileIDs, 0);
 
 #ifdef _LITTLE_ENDIAN
     /* Reversing data packed into int for LE archs */
@@ -186,6 +200,8 @@
         iccArray = (cmsHPROFILE*) malloc(
             size*2*sizeof(cmsHPROFILE));
         if (iccArray == NULL) {
+            (*env)->ReleaseLongArrayElements(env, profileIDs, ids, 0);
+
             J2dRlsTraceLn(J2D_TRACE_ERROR, "getXForm: iccArray == NULL");
             return 0L;
         }
@@ -197,7 +213,7 @@
         cmsColorSpaceSignature cs;
 
         sTrans.j = ids[i];
-        icc = sTrans.pf;
+        icc = sTrans.lcmsPf->pf;
         iccArray[j++] = icc;
 
         /* Middle non-abstract profiles should be doubled before passing to
@@ -215,13 +231,15 @@
     sTrans.xf = cmsCreateMultiprofileTransform(iccArray, j,
         inFormatter, outFormatter, renderType, 0);
 
-    (*env)->ReleasePrimitiveArrayCritical(env, profileIDs, ids, 0);
+    (*env)->ReleaseLongArrayElements(env, profileIDs, ids, 0);
 
     if (sTrans.xf == NULL) {
         J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_createNativeTransform: "
                                        "sTrans.xf == NULL");
-        JNU_ThrowByName(env, "java/awt/color/CMMException",
-                        "Cannot get color transform");
+        if ((*env)->ExceptionOccurred(env) == NULL) {
+            JNU_ThrowByName(env, "java/awt/color/CMMException",
+                            "Cannot get color transform");
+        }
     } else {
         Disposer_AddRecord(env, disposerRef, LCMS_freeTransform, sTrans.j);
     }
@@ -236,20 +254,23 @@
 /*
  * Class:     sun_java2d_cmm_lcms_LCMS
  * Method:    loadProfile
- * Signature: ([B)J
+ * Signature: ([B,Lsun/java2d/cmm/lcms/LCMSProfile;)V
  */
 JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_loadProfileNative
-  (JNIEnv *env, jobject obj, jbyteArray data)
+  (JNIEnv *env, jobject obj, jbyteArray data, jobject disposerRef)
 {
     jbyte* dataArray;
     jint dataSize;
     storeID_t sProf;
+    cmsHPROFILE pf;
 
     if (JNU_IsNull(env, data)) {
         JNU_ThrowIllegalArgumentException(env, "Invalid profile data");
         return 0L;
     }
 
+    sProf.j = 0L;
+
     dataArray = (*env)->GetByteArrayElements (env, data, 0);
     dataSize = (*env)->GetArrayLength (env, data);
 
@@ -258,22 +279,37 @@
         return 0L;
     }
 
-    sProf.pf = cmsOpenProfileFromMem((const void *)dataArray,
+    pf = cmsOpenProfileFromMem((const void *)dataArray,
                                      (cmsUInt32Number) dataSize);
 
     (*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
 
-    if (sProf.pf == NULL) {
+    if (pf == NULL) {
         JNU_ThrowIllegalArgumentException(env, "Invalid profile data");
     } else {
         /* Sanity check: try to save the profile in order
          * to force basic validation.
          */
         cmsUInt32Number pfSize = 0;
-        if (!cmsSaveProfileToMem(sProf.pf, NULL, &pfSize) ||
+        if (!cmsSaveProfileToMem(pf, NULL, &pfSize) ||
             pfSize < sizeof(cmsICCHeader))
         {
             JNU_ThrowIllegalArgumentException(env, "Invalid profile data");
+
+            cmsCloseProfile(pf);
+            pf = NULL;
+        }
+    }
+
+    if (pf != NULL) {
+        // create profile holder
+        sProf.lcmsPf = (lcmsProfile_p)malloc(sizeof(lcmsProfile_t));
+        if (sProf.lcmsPf != NULL) {
+            // register the disposer record
+            sProf.lcmsPf->pf = pf;
+            Disposer_AddRecord(env, disposerRef, LCMS_freeProfile, sProf.j);
+        } else {
+            cmsCloseProfile(pf);
         }
     }
 
@@ -282,37 +318,17 @@
 
 /*
  * Class:     sun_java2d_cmm_lcms_LCMS
- * Method:    freeProfile
- * Signature: (J)V
- */
-JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_freeProfileNative
-  (JNIEnv *env, jobject obj, jlong id)
-{
-    storeID_t sProf;
-
-    sProf.j = id;
-    if (cmsCloseProfile(sProf.pf) == 0) {
-        J2dRlsTraceLn1(J2D_TRACE_ERROR, "LCMS_freeProfile: cmsCloseProfile(%d)"
-                       "== 0", id);
-        JNU_ThrowByName(env, "java/awt/color/CMMException",
-                        "Cannot close profile");
-    }
-
-}
-
-/*
- * Class:     sun_java2d_cmm_lcms_LCMS
- * Method:    getProfileSize
+ * Method:    getProfileSizeNative
  * Signature: (J)I
  */
-JNIEXPORT jint JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileSize
+JNIEXPORT jint JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileSizeNative
   (JNIEnv *env, jobject obj, jlong id)
 {
     storeID_t sProf;
     cmsUInt32Number pfSize = 0;
     sProf.j = id;
 
-    if (cmsSaveProfileToMem(sProf.pf, NULL, &pfSize) && ((jint)pfSize > 0)) {
+    if (cmsSaveProfileToMem(sProf.lcmsPf->pf, NULL, &pfSize) && ((jint)pfSize > 0)) {
         return (jint)pfSize;
     } else {
       JNU_ThrowByName(env, "java/awt/color/CMMException",
@@ -323,10 +339,10 @@
 
 /*
  * Class:     sun_java2d_cmm_lcms_LCMS
- * Method:    getProfileData
+ * Method:    getProfileDataNative
  * Signature: (J[B)V
  */
-JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileData
+JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileDataNative
   (JNIEnv *env, jobject obj, jlong id, jbyteArray data)
 {
     storeID_t sProf;
@@ -338,7 +354,7 @@
     sProf.j = id;
 
     // determine actual profile size
-    if (!cmsSaveProfileToMem(sProf.pf, NULL, &pfSize)) {
+    if (!cmsSaveProfileToMem(sProf.lcmsPf->pf, NULL, &pfSize)) {
         JNU_ThrowByName(env, "java/awt/color/CMMException",
                         "Can not access specified profile.");
         return;
@@ -354,7 +370,7 @@
 
     dataArray = (*env)->GetByteArrayElements (env, data, 0);
 
-    status = cmsSaveProfileToMem(sProf.pf, dataArray, &pfSize);
+    status = cmsSaveProfileToMem(sProf.lcmsPf->pf, dataArray, &pfSize);
 
     (*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
 
@@ -368,7 +384,7 @@
 /* Get profile header info */
 static cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize);
 static cmsBool _setHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize);
-static cmsBool _writeCookedTag(cmsHPROFILE pfTarget, cmsTagSignature sig, jbyte *pData, jint size);
+static cmsHPROFILE _writeCookedTag(cmsHPROFILE pfTarget, cmsTagSignature sig, jbyte *pData, jint size);
 
 
 /*
@@ -412,7 +428,7 @@
            return NULL;
         }
 
-        status = _getHeaderInfo(sProf.pf, dataArray, bufSize);
+        status = _getHeaderInfo(sProf.lcmsPf->pf, dataArray, bufSize);
 
         (*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
 
@@ -425,8 +441,8 @@
         return data;
     }
 
-    if (cmsIsTag(sProf.pf, sig.cms)) {
-        tagSize = cmsReadRawTag(sProf.pf, sig.cms, NULL, 0);
+    if (cmsIsTag(sProf.lcmsPf->pf, sig.cms)) {
+        tagSize = cmsReadRawTag(sProf.lcmsPf->pf, sig.cms, NULL, 0);
     } else {
         JNU_ThrowByName(env, "java/awt/color/CMMException",
                         "ICC profile tag not found");
@@ -449,7 +465,7 @@
         return NULL;
     }
 
-    bufSize = cmsReadRawTag(sProf.pf, sig.cms, dataArray, tagSize);
+    bufSize = cmsReadRawTag(sProf.lcmsPf->pf, sig.cms, dataArray, tagSize);
 
     (*env)->ReleaseByteArrayElements (env, data, dataArray, 0);
 
@@ -470,8 +486,10 @@
   (JNIEnv *env, jobject obj, jlong id, jint tagSig, jbyteArray data)
 {
     storeID_t sProf;
+    cmsHPROFILE pfReplace = NULL;
+
     TagSignature_t sig;
-    cmsBool status;
+    cmsBool status = FALSE;
     jbyte* dataArray;
     int tagSize;
 
@@ -493,15 +511,24 @@
     }
 
     if (tagSig == SigHead) {
-        status = _setHeaderInfo(sProf.pf, dataArray, tagSize);
+        status  = _setHeaderInfo(sProf.lcmsPf->pf, dataArray, tagSize);
     } else {
-        status = _writeCookedTag(sProf.pf, sig.cms, dataArray, tagSize);
+        /*
+        * New strategy for generic tags: create a place holder,
+        * dump all existing tags there, dump externally supplied
+        * tag, and return the new profile to the java.
+        */
+        pfReplace = _writeCookedTag(sProf.lcmsPf->pf, sig.cms, dataArray, tagSize);
+        status = (pfReplace != NULL);
     }
 
     (*env)->ReleaseByteArrayElements(env, data, dataArray, 0);
 
     if (!status) {
         JNU_ThrowIllegalArgumentException(env, "Can not write tag data.");
+    } else if (pfReplace != NULL) {
+        cmsCloseProfile(sProf.lcmsPf->pf);
+        sProf.lcmsPf->pf = pfReplace;
     }
 }
 
@@ -624,12 +651,27 @@
 /*
  * Class:     sun_java2d_cmm_lcms_LCMS
  * Method:    getProfileID
- * Signature: (Ljava/awt/color/ICC_Profile;)J
+ * Signature: (Ljava/awt/color/ICC_Profile;)Lsun/java2d/cmm/lcms/LCMSProfile
  */
-JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileID
+JNIEXPORT jobject JNICALL Java_sun_java2d_cmm_lcms_LCMS_getProfileID
   (JNIEnv *env, jclass cls, jobject pf)
 {
-    return (*env)->GetLongField (env, pf, PF_ID_fID);
+    jfieldID fid = (*env)->GetFieldID (env,
+        (*env)->GetObjectClass(env, pf),
+        "cmmProfile", "Lsun/java2d/cmm/Profile;");
+
+    jclass clsLcmsProfile = (*env)->FindClass(env,
+            "sun/java2d/cmm/lcms/LCMSProfile");
+
+    jobject cmmProfile = (*env)->GetObjectField (env, pf, fid);
+
+    if (JNU_IsNull(env, cmmProfile)) {
+        return NULL;
+    }
+    if ((*env)->IsInstanceOf(env, cmmProfile, clsLcmsProfile)) {
+        return cmmProfile;
+    }
+    return NULL;
 }
 
 /*
@@ -644,7 +686,6 @@
      * corresponding classes to avoid problems with invalidating ids by class
      * unloading
      */
-    Trans_profileIDs_fID = (*env)->GetFieldID (env, Trans, "profileIDs", "[J");
     Trans_renderType_fID = (*env)->GetFieldID (env, Trans, "renderType", "I");
     Trans_ID_fID = (*env)->GetFieldID (env, Trans, "ID", "J");
 
@@ -658,8 +699,6 @@
     IL_offset_fID = (*env)->GetFieldID (env, IL, "offset", "I");
     IL_imageAtOnce_fID = (*env)->GetFieldID (env, IL, "imageAtOnce", "Z");
     IL_nextRowOffset_fID = (*env)->GetFieldID (env, IL, "nextRowOffset", "I");
-
-    PF_ID_fID = (*env)->GetFieldID (env, Pf, "ID", "J");
 }
 
 static cmsBool _getHeaderInfo(cmsHPROFILE pf, jbyte* pBuffer, jint bufferSize)
@@ -714,76 +753,114 @@
   return TRUE;
 }
 
-static cmsBool _writeCookedTag(cmsHPROFILE pfTarget,
-                               cmsTagSignature sig,
+/* Returns new profile handler, if it was created successfully,
+   NULL otherwise.
+   */
+static cmsHPROFILE _writeCookedTag(const cmsHPROFILE pfTarget,
+                               const cmsTagSignature sig,
                                jbyte *pData, jint size)
 {
-    cmsBool status;
     cmsUInt32Number pfSize = 0;
-    cmsUInt8Number* pfBuffer = NULL;
+    const cmsInt32Number tagCount = cmsGetTagCount(pfTarget);
+    cmsInt32Number i;
+    cmsHPROFILE pfSanity = NULL;
+
+    cmsICCHeader hdr = { 0 };
 
     cmsHPROFILE p = cmsCreateProfilePlaceholder(NULL);
-    if (NULL != p) {
-        cmsICCHeader hdr = { 0 };
+
+    if (NULL == p) {
+        return NULL;
+    }
 
-        /* Populate the placeholder's header according to target profile */
-        hdr.flags = cmsGetHeaderFlags(pfTarget);
-        hdr.renderingIntent = cmsGetHeaderRenderingIntent(pfTarget);
-        hdr.manufacturer = cmsGetHeaderManufacturer(pfTarget);
-        hdr.model = cmsGetHeaderModel(pfTarget);
-        hdr.pcs = cmsGetPCS(pfTarget);
-        hdr.colorSpace = cmsGetColorSpace(pfTarget);
-        hdr.deviceClass = cmsGetDeviceClass(pfTarget);
-        hdr.version = cmsGetEncodedICCversion(pfTarget);
-        cmsGetHeaderAttributes(pfTarget, &hdr.attributes);
-        cmsGetHeaderProfileID(pfTarget, (cmsUInt8Number*)&hdr.profileID);
+    // Populate the placeholder's header according to target profile
+    hdr.flags = cmsGetHeaderFlags(pfTarget);
+    hdr.renderingIntent = cmsGetHeaderRenderingIntent(pfTarget);
+    hdr.manufacturer = cmsGetHeaderManufacturer(pfTarget);
+    hdr.model = cmsGetHeaderModel(pfTarget);
+    hdr.pcs = cmsGetPCS(pfTarget);
+    hdr.colorSpace = cmsGetColorSpace(pfTarget);
+    hdr.deviceClass = cmsGetDeviceClass(pfTarget);
+    hdr.version = cmsGetEncodedICCversion(pfTarget);
+    cmsGetHeaderAttributes(pfTarget, &hdr.attributes);
+    cmsGetHeaderProfileID(pfTarget, (cmsUInt8Number*)&hdr.profileID);
 
-        cmsSetHeaderFlags(p, hdr.flags);
-        cmsSetHeaderManufacturer(p, hdr.manufacturer);
-        cmsSetHeaderModel(p, hdr.model);
-        cmsSetHeaderAttributes(p, hdr.attributes);
-        cmsSetHeaderProfileID(p, (cmsUInt8Number*)&(hdr.profileID));
-        cmsSetHeaderRenderingIntent(p, hdr.renderingIntent);
-        cmsSetPCS(p, hdr.pcs);
-        cmsSetColorSpace(p, hdr.colorSpace);
-        cmsSetDeviceClass(p, hdr.deviceClass);
-        cmsSetEncodedICCversion(p, hdr.version);
+    cmsSetHeaderFlags(p, hdr.flags);
+    cmsSetHeaderManufacturer(p, hdr.manufacturer);
+    cmsSetHeaderModel(p, hdr.model);
+    cmsSetHeaderAttributes(p, hdr.attributes);
+    cmsSetHeaderProfileID(p, (cmsUInt8Number*)&(hdr.profileID));
+    cmsSetHeaderRenderingIntent(p, hdr.renderingIntent);
+    cmsSetPCS(p, hdr.pcs);
+    cmsSetColorSpace(p, hdr.colorSpace);
+    cmsSetDeviceClass(p, hdr.deviceClass);
+    cmsSetEncodedICCversion(p, hdr.version);
+
+    // now write the user supplied tag
+    if (size <= 0 || !cmsWriteRawTag(p, sig, pData, size)) {
+        cmsCloseProfile(p);
+        return NULL;
+    }
 
+    // copy tags from the original profile
+    for (i = 0; i < tagCount; i++) {
+        cmsBool isTagReady = FALSE;
+        const cmsTagSignature s = cmsGetTagSignature(pfTarget, i);
+        const cmsInt32Number tagSize = cmsReadRawTag(pfTarget, s, NULL, 0);
 
-        if (cmsWriteRawTag(p, sig, pData, size)) {
-            if (cmsSaveProfileToMem(p, NULL, &pfSize)) {
-                pfBuffer = malloc(pfSize);
-                if (pfBuffer != NULL) {
-                    /* load raw profile data into the buffer */
-                    if (!cmsSaveProfileToMem(p, pfBuffer, &pfSize)) {
-                        free(pfBuffer);
-                        pfBuffer = NULL;
-                    }
+        if (s == sig) {
+            // skip the user supplied tag
+            continue;
+        }
+
+        // read raw tag from the original profile
+        if (tagSize > 0) {
+            cmsUInt8Number* buf = (cmsUInt8Number*)malloc(tagSize);
+            if (buf != NULL) {
+                if (tagSize ==  cmsReadRawTag(pfTarget, s, buf, tagSize)) {
+                    // now we are ready to write the tag
+                    isTagReady = cmsWriteRawTag(p, s, buf, tagSize);
                 }
+                free(buf);
             }
         }
-        cmsCloseProfile(p);
+
+        if (!isTagReady) {
+            cmsCloseProfile(p);
+            return NULL;
+        }
     }
 
-    if (pfBuffer == NULL) {
-        return FALSE;
+    // now we have all tags moved to the new profile.
+    // do some sanity checks: write it to a memory buffer and read again.
+    if (cmsSaveProfileToMem(p, NULL, &pfSize)) {
+        void* buf = malloc(pfSize);
+        if (buf != NULL) {
+            // load raw profile data into the buffer
+            if (cmsSaveProfileToMem(p, buf, &pfSize)) {
+                pfSanity = cmsOpenProfileFromMem(buf, pfSize);
+            }
+            free(buf);
+        }
     }
 
-    /* re-open the placeholder profile */
-    p = cmsOpenProfileFromMem(pfBuffer, pfSize);
-    free(pfBuffer);
-    status = FALSE;
+    if (pfSanity == NULL) {
+        // for some reason, we failed to save and read the updated profile
+        // It likely indicates that the profile is not correct, so we report
+        // a failure here.
+        cmsCloseProfile(p);
+        p =  NULL;
+    } else {
+        // do final check whether we can read and handle the the target tag.
+        const void* pTag = cmsReadTag(pfSanity, sig);
+        if (pTag == NULL) {
+            // the tag can not be cooked
+            cmsCloseProfile(p);
+            p = NULL;
+        }
+        cmsCloseProfile(pfSanity);
+        pfSanity = NULL;
+    }
 
-    if (p != NULL) {
-        /* Note that pCookedTag points to internal structures of the placeholder,
-         * so this data is valid only while the placeholder is open.
-         */
-        void *pCookedTag = cmsReadTag(p, sig);
-        if (pCookedTag != NULL) {
-            status = cmsWriteTag(pfTarget, sig, pCookedTag);
-        }
-        pCookedTag = NULL;
-        cmsCloseProfile(p);
-    }
-    return status;
+    return p;
 }
--- a/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/solaris/classes/sun/awt/X11/XToolkit.java	Wed Jul 05 19:11:53 2017 +0200
@@ -54,6 +54,7 @@
 import sun.security.action.GetPropertyAction;
 import sun.security.action.GetBooleanAction;
 import sun.util.logging.PlatformLogger;
+import sun.security.util.SecurityConstants;
 
 public final class XToolkit extends UNIXToolkit implements Runnable {
     private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XToolkit");
@@ -1152,7 +1153,7 @@
     public  Clipboard getSystemClipboard() {
         SecurityManager security = System.getSecurityManager();
         if (security != null) {
-            security.checkSystemClipboardAccess();
+            security.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
         }
         synchronized (this) {
             if (clipboard == null) {
@@ -1165,7 +1166,7 @@
     public Clipboard getSystemSelection() {
         SecurityManager security = System.getSecurityManager();
         if (security != null) {
-            security.checkSystemClipboardAccess();
+            security.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
         }
         synchronized (this) {
             if (selection == null) {
--- a/jdk/src/solaris/classes/sun/font/XRTextRenderer.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/solaris/classes/sun/font/XRTextRenderer.java	Wed Jul 05 19:11:53 2017 +0200
@@ -142,7 +142,7 @@
             }
 
             int maskFormat = containsLCDGlyphs ? XRUtils.PictStandardARGB32 : XRUtils.PictStandardA8;
-            maskBuffer.compositeText(x11sd.picture, 0, maskFormat, eltList);
+            maskBuffer.compositeText(x11sd, (int) gl.getX(), (int) gl.getY(), 0, maskFormat, eltList);
 
             eltList.clear();
         } finally {
--- a/jdk/src/solaris/classes/sun/java2d/xr/XRBackendNative.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/solaris/classes/sun/java2d/xr/XRBackendNative.java	Wed Jul 05 19:11:53 2017 +0200
@@ -267,8 +267,9 @@
 
     private static native void
         XRenderCompositeTextNative(int op, int src, int dst,
-                                   long maskFormat, int[] eltArray,
-                                   int[] glyphIDs, int eltCnt, int glyphCnt);
+                                   int srcX, int srcY, long maskFormat,
+                                   int[] eltArray, int[] glyphIDs, int eltCnt,
+                                   int glyphCnt);
 
     public int XRenderCreateGlyphSet(int formatID) {
         return XRenderCreateGlyphSetNative(getFormatPtr(formatID));
@@ -278,11 +279,11 @@
 
     public void XRenderCompositeText(byte op, int src, int dst,
                                      int maskFormatID,
-                                     int src2, int src3, int dst2, int dst3,
+                                     int sx, int sy, int dx, int dy,
                                      int glyphset, GrowableEltArray elts) {
 
         GrowableIntArray glyphs = elts.getGlyphs();
-        XRenderCompositeTextNative(op, src, dst, 0, elts.getArray(),
+        XRenderCompositeTextNative(op, src, dst, sx, sy, 0, elts.getArray(),
                                    glyphs.getArray(), elts.getSize(),
                                    glyphs.getSize());
     }
--- a/jdk/src/solaris/classes/sun/java2d/xr/XRCompositeManager.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/solaris/classes/sun/java2d/xr/XRCompositeManager.java	Wed Jul 05 19:11:53 2017 +0200
@@ -285,7 +285,12 @@
         if (xorEnabled) {
             con.GCRectangles(dst.getXid(), dst.getGC(), rects);
         } else {
-            con.renderRectangles(dst.getPicture(), compRule, solidColor, rects);
+            if (rects.getSize() == 1) {
+                con.renderRectangle(dst.getPicture(), compRule, solidColor,
+                        rects.getX(0), rects.getY(0), rects.getWidth(0), rects.getHeight(0));
+            } else {
+                con.renderRectangles(dst.getPicture(), compRule, solidColor, rects);
+            }
         }
     }
 
@@ -295,10 +300,10 @@
                 sy, 0, 0, dx, dy, w, h);
     }
 
-    public void compositeText(int dst, int glyphSet, int maskFormat,
-            GrowableEltArray elts) {
-        con.XRenderCompositeText(compRule, src.picture, dst, maskFormat, 0, 0,
-                0, 0, glyphSet, elts);
+    public void compositeText(XRSurfaceData dst, int sx, int sy,
+            int glyphSet, int maskFormat, GrowableEltArray elts) {
+        con.XRenderCompositeText(compRule, src.picture, dst.picture,
+                maskFormat, sx, sy, 0, 0, glyphSet, elts);
     }
 
     public XRColor getMaskColor() {
--- a/jdk/src/solaris/classes/sun/java2d/xr/XRPMBlitLoops.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/solaris/classes/sun/java2d/xr/XRPMBlitLoops.java	Wed Jul 05 19:11:53 2017 +0200
@@ -225,6 +225,9 @@
  * @author Clemens Eisserer
  */
 class XRPMTransformedBlit extends TransformBlit {
+    final Rectangle compositeBounds = new Rectangle();
+    final double[] srcCoords = new double[8];
+    final double[] dstCoords = new double[8];
 
     public XRPMTransformedBlit(SurfaceType srcType, SurfaceType dstType) {
         super(srcType, CompositeType.AnyAlpha, dstType);
@@ -235,61 +238,68 @@
      * method is functionally equal to: Shape shp =
      * xform.createTransformedShape(rect); Rectangle bounds = shp.getBounds();
      * but performs significantly better.
+     * Returns true if the destination shape is parallel to x/y axis
      */
-    public Rectangle getCompositeBounds(AffineTransform tr, int dstx, int dsty, int width, int height) {
-        double[] compBounds = new double[8];
-        compBounds[0] = dstx;
-        compBounds[1] = dsty;
-        compBounds[2] = dstx + width;
-        compBounds[3] = dsty;
-        compBounds[4] = dstx + width;
-        compBounds[5] = dsty + height;
-        compBounds[6] = dstx;
-        compBounds[7] = dsty + height;
+    protected boolean adjustCompositeBounds(AffineTransform tr, int dstx, int dsty, int width, int height) {
+        srcCoords[0] = dstx;
+        srcCoords[1] = dsty;
+        srcCoords[2] = dstx + width;
+        srcCoords[3] = dsty;
+        srcCoords[4] = dstx + width;
+        srcCoords[5] = dsty + height;
+        srcCoords[6] = dstx;
+        srcCoords[7] = dsty + height;
+
+        tr.transform(srcCoords, 0, dstCoords, 0, 4);
 
-        tr.transform(compBounds, 0, compBounds, 0, 4);
+        double minX = Math.min(dstCoords[0], Math.min(dstCoords[2], Math.min(dstCoords[4], dstCoords[6])));
+        double minY = Math.min(dstCoords[1], Math.min(dstCoords[3], Math.min(dstCoords[5], dstCoords[7])));
+        double maxX = Math.max(dstCoords[0], Math.max(dstCoords[2], Math.max(dstCoords[4], dstCoords[6])));
+        double maxY = Math.max(dstCoords[1], Math.max(dstCoords[3], Math.max(dstCoords[5], dstCoords[7])));
 
-        double minX = Math.min(compBounds[0], Math.min(compBounds[2], Math.min(compBounds[4], compBounds[6])));
-        double minY = Math.min(compBounds[1], Math.min(compBounds[3], Math.min(compBounds[5], compBounds[7])));
-        double maxX = Math.max(compBounds[0], Math.max(compBounds[2], Math.max(compBounds[4], compBounds[6])));
-        double maxY = Math.max(compBounds[1], Math.max(compBounds[3], Math.max(compBounds[5], compBounds[7])));
+        minX = Math.round(minX);
+        minY = Math.round(minY);
+        maxX = Math.round(maxX);
+        maxY = Math.round(maxY);
 
-        minX = Math.floor(minX);
-        minY = Math.floor(minY);
-        maxX = Math.ceil(maxX);
-        maxY = Math.ceil(maxY);
+        compositeBounds.x = (int) minX;
+        compositeBounds.y = (int) minY;
+        compositeBounds.width = (int) (maxX - minX);
+        compositeBounds.height = (int) (maxY - minY);
 
-        return new Rectangle((int) minX, (int) minY, (int) (maxX - minX), (int) (maxY - minY));
+        boolean is0or180 = (dstCoords[1] == dstCoords[3]) && (dstCoords[2] == dstCoords[4]);
+        boolean is90or270 = (dstCoords[0] == dstCoords[2]) && (dstCoords[3] == dstCoords[5]);
+
+        return is0or180 || is90or270;
     }
 
-    public void Transform(SurfaceData src, SurfaceData dst, Composite comp, Region clip, AffineTransform xform, int hint, int srcx, int srcy,
-            int dstx, int dsty, int width, int height) {
+    public void Transform(SurfaceData src, SurfaceData dst, Composite comp, Region clip, AffineTransform xform,
+            int hint, int srcx, int srcy, int dstx, int dsty, int width, int height) {
         try {
             SunToolkit.awtLock();
 
-            int filter = XRUtils.ATransOpToXRQuality(hint);
+            XRSurfaceData x11sdDst = (XRSurfaceData) dst;
+            XRSurfaceData x11sdSrc = (XRSurfaceData) src;
 
-            XRSurfaceData x11sdDst = (XRSurfaceData) dst;
+            int filter = XRUtils.ATransOpToXRQuality(hint);
+            boolean isAxisAligned = adjustCompositeBounds(xform, dstx, dsty, width, height);
+
             x11sdDst.validateAsDestination(null, clip);
-            XRSurfaceData x11sdSrc = (XRSurfaceData) src;
             x11sdDst.maskBuffer.validateCompositeState(comp, null, null, null);
 
-            Rectangle bounds = getCompositeBounds(xform, dstx, dsty, width, height);
-
-            AffineTransform trx = AffineTransform.getTranslateInstance((-bounds.x), (-bounds.y));
+            AffineTransform trx = AffineTransform.getTranslateInstance(-compositeBounds.x, -compositeBounds.y);
             trx.concatenate(xform);
             AffineTransform maskTX = (AffineTransform) trx.clone();
-
             trx.translate(-srcx, -srcy);
 
             try {
                 trx.invert();
             } catch (NoninvertibleTransformException ex) {
                 trx.setToIdentity();
-                System.err.println("Reseted to identity!");
             }
 
-            boolean omitMask = isMaskOmittable(trx, comp, filter);
+            boolean omitMask = (filter == XRUtils.FAST)
+                    || (isAxisAligned && ((AlphaComposite) comp).getAlpha() == 1.0f);
 
             if (!omitMask) {
                 XRMaskImage mask = x11sdSrc.maskBuffer.getMaskImage();
@@ -297,33 +307,17 @@
                 x11sdSrc.validateAsSource(trx, XRUtils.RepeatPad, filter);
                 int maskPicture = mask.prepareBlitMask(x11sdDst, maskTX, width, height);
                 x11sdDst.maskBuffer.con.renderComposite(XRCompositeManager.getInstance(x11sdSrc).getCompRule(), x11sdSrc.picture, maskPicture, x11sdDst.picture,
-                        0, 0, 0, 0, bounds.x, bounds.y, bounds.width, bounds.height);
+                        0, 0, 0, 0, compositeBounds.x, compositeBounds.y, compositeBounds.width, compositeBounds.height);
             } else {
                 int repeat = filter == XRUtils.FAST ? XRUtils.RepeatNone : XRUtils.RepeatPad;
 
                 x11sdSrc.validateAsSource(trx, repeat, filter);
-                x11sdDst.maskBuffer.compositeBlit(x11sdSrc, x11sdDst, 0, 0, bounds.x, bounds.y, bounds.width, bounds.height);
+                x11sdDst.maskBuffer.compositeBlit(x11sdSrc, x11sdDst, 0, 0, compositeBounds.x, compositeBounds.y, compositeBounds.width, compositeBounds.height);
             }
         } finally {
             SunToolkit.awtUnlock();
         }
     }
-
-    /* TODO: Is mask ever omitable??? ... should be for 90 degree rotation and no shear, but we always need to use RepeatPad */
-    protected static boolean isMaskOmittable(AffineTransform trx, Composite comp, int filter) {
-        return (filter == XRUtils.FAST || trx.getTranslateX() == (int) trx.getTranslateX() /*
-                                                                                            * If
-                                                                                            * translate
-                                                                                            * is
-                                                                                            * integer
-                                                                                            * only
-                                                                                            */
-                && trx.getTranslateY() == (int) trx.getTranslateY() && (trx.getShearX() == 0 && trx.getShearY() == 0 // Only
-                // 90 degree
-                // rotation
-                || trx.getShearX() == -trx.getShearY())) && ((AlphaComposite) comp).getAlpha() == 1.0f; // No
-        // ExtraAlpha!=1
-    }
 }
 
 class XrSwToPMBlit extends Blit {
--- a/jdk/src/solaris/native/java/lang/java_props_macosx.c	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/solaris/native/java/lang/java_props_macosx.c	Wed Jul 05 19:11:53 2017 +0200
@@ -31,6 +31,7 @@
 #include <Security/AuthSession.h>
 #include <CoreFoundation/CoreFoundation.h>
 #include <SystemConfiguration/SystemConfiguration.h>
+#include <Foundation/Foundation.h>
 
 #include "java_props_macosx.h"
 
@@ -271,9 +272,20 @@
     return c_exception;
 }
 
+/*
+ * Method for fetching the user.home path and storing it in the property list.
+ * For signed .apps running in the Mac App Sandbox, user.home is set to the
+ * app's sandbox container.
+ */
+void setUserHome(java_props_t *sprops) {
+    if (sprops == NULL) { return; }
+    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+    sprops->user_home = createUTF8CString((CFStringRef)NSHomeDirectory());
+    [pool drain];
+}
 
 /*
- * Method for fetching proxy info and storing it in the propery list.
+ * Method for fetching proxy info and storing it in the property list.
  */
 void setProxyProperties(java_props_t *sProps) {
     if (sProps == NULL) return;
--- a/jdk/src/solaris/native/java/lang/java_props_macosx.h	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/solaris/native/java/lang/java_props_macosx.h	Wed Jul 05 19:11:53 2017 +0200
@@ -27,6 +27,7 @@
 
 char *setupMacOSXLocale(int cat);
 void setOSNameAndVersion(java_props_t *sprops);
+void setUserHome(java_props_t *sprops);
 void setProxyProperties(java_props_t *sProps);
 
 enum PreferredToolkit_enum {
--- a/jdk/src/solaris/native/java/lang/java_props_md.c	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/solaris/native/java/lang/java_props_md.c	Wed Jul 05 19:11:53 2017 +0200
@@ -591,7 +591,14 @@
     {
         struct passwd *pwent = getpwuid(getuid());
         sprops.user_name = pwent ? strdup(pwent->pw_name) : "?";
-        sprops.user_home = pwent ? strdup(pwent->pw_dir) : "?";
+#ifdef MACOSX
+        setUserHome(&sprops);
+#else
+        sprops.user_home = pwent ? strdup(pwent->pw_dir) : NULL;
+#endif
+        if (sprops.user_home == NULL) {
+            sprops.user_home = "?";
+        }
     }
 
     /* User TIMEZONE */
--- a/jdk/src/solaris/native/sun/java2d/x11/XRBackendNative.c	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/solaris/native/sun/java2d/x11/XRBackendNative.c	Wed Jul 05 19:11:53 2017 +0200
@@ -911,8 +911,9 @@
 
 JNIEXPORT void JNICALL
 Java_sun_java2d_xr_XRBackendNative_XRenderCompositeTextNative
- (JNIEnv *env, jclass cls, jint op, jint src, jint dst, jlong maskFmt,
-  jintArray eltArray, jintArray  glyphIDArray, jint eltCnt, jint glyphCnt) {
+ (JNIEnv *env, jclass cls, jint op, jint src, jint dst,
+  jint sx, jint sy, jlong maskFmt, jintArray eltArray,
+  jintArray  glyphIDArray, jint eltCnt, jint glyphCnt) {
     jint i;
     jint *ids;
     jint *elts;
@@ -991,7 +992,7 @@
 
     XRenderCompositeText32(awt_display, op, (Picture) src, (Picture) dst,
                            (XRenderPictFormat *) jlong_to_ptr(maskFmt),
-                            0, 0, 0, 0, xelts, eltCnt);
+                            sx, sy, 0, 0, xelts, eltCnt);
 
     (*env)->ReleasePrimitiveArrayCritical(env, glyphIDArray, ids, JNI_ABORT);
     (*env)->ReleasePrimitiveArrayCritical(env, eltArray, elts, JNI_ABORT);
--- a/jdk/src/windows/classes/sun/awt/windows/WPrinterJob.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/windows/classes/sun/awt/windows/WPrinterJob.java	Wed Jul 05 19:11:53 2017 +0200
@@ -179,6 +179,7 @@
     private static final int SET_RES_LOW = 0x00000080;
     private static final int SET_COLOR = 0x00000200;
     private static final int SET_ORIENTATION = 0x00004000;
+    private static final int SET_COLLATED    = 0x00008000;
 
     /**
      * Values must match those defined in wingdi.h & commdlg.h
@@ -189,10 +190,33 @@
     private static final int PD_NOSELECTION = 0x00000004;
     private static final int PD_COLLATE = 0x00000010;
     private static final int PD_PRINTTOFILE = 0x00000020;
-    private static final int DM_ORIENTATION = 0x00000001;
-    private static final int DM_PRINTQUALITY = 0x00000400;
-    private static final int DM_COLOR = 0x00000800;
-    private static final int DM_DUPLEX = 0x00001000;
+    private static final int DM_ORIENTATION   = 0x00000001;
+    private static final int DM_PAPERSIZE     = 0x00000002;
+    private static final int DM_COPIES        = 0x00000100;
+    private static final int DM_DEFAULTSOURCE = 0x00000200;
+    private static final int DM_PRINTQUALITY  = 0x00000400;
+    private static final int DM_COLOR         = 0x00000800;
+    private static final int DM_DUPLEX        = 0x00001000;
+    private static final int DM_YRESOLUTION   = 0x00002000;
+    private static final int DM_COLLATE       = 0x00008000;
+
+    private static final short DMCOLLATE_FALSE  = 0;
+    private static final short DMCOLLATE_TRUE   = 1;
+
+    private static final short DMORIENT_PORTRAIT  = 1;
+    private static final short DMORIENT_LANDSCAPE = 2;
+
+    private static final short DMCOLOR_MONOCHROME = 1;
+    private static final short DMCOLOR_COLOR      = 2;
+
+    private static final short DMRES_DRAFT  = -1;
+    private static final short DMRES_LOW    = -2;
+    private static final short DMRES_MEDIUM = -3;
+    private static final short DMRES_HIGH   = -4;
+
+    private static final short DMDUP_SIMPLEX    = 1;
+    private static final short DMDUP_VERTICAL   = 2;
+    private static final short DMDUP_HORIZONTAL = 3;
 
     /**
      * Pageable MAX pages
@@ -592,13 +616,23 @@
         }
         driverDoesMultipleCopies = false;
         driverDoesCollation = false;
-        setNativePrintService(service.getName());
+        setNativePrintServiceIfNeeded(service.getName());
     }
 
     /* associates this job with the specified native service */
     private native void setNativePrintService(String name)
         throws PrinterException;
 
+    private String lastNativeService = null;
+    private void setNativePrintServiceIfNeeded(String name)
+        throws PrinterException {
+
+        if (name != null && !(name.equals(lastNativeService))) {
+            setNativePrintService(name);
+            lastNativeService = name;
+        }
+    }
+
     public PrintService getPrintService() {
         if (myService == null) {
             String printerName = getNativePrintService();
@@ -616,7 +650,7 @@
             myService = PrintServiceLookup.lookupDefaultPrintService();
             if (myService != null) {
                 try {
-                    setNativePrintService(myService.getName());
+                    setNativePrintServiceIfNeeded(myService.getName());
                 } catch (Exception e) {
                     myService = null;
                 }
@@ -1754,8 +1788,13 @@
         mAttMediaSizeName = ((Win32PrintService)myService).findPaperID(msn);
     }
 
-    private void setWin32MediaAttrib(int dmIndex, int width, int length) {
-       MediaSizeName msn =
+    private void addPaperSize(PrintRequestAttributeSet aset,
+                              int dmIndex, int width, int length) {
+
+        if (aset == null) {
+            return;
+        }
+        MediaSizeName msn =
            ((Win32PrintService)myService).findWin32Media(dmIndex);
         if (msn == null) {
             msn = ((Win32PrintService)myService).
@@ -1763,10 +1802,12 @@
         }
 
         if (msn != null) {
-            if (attributes != null) {
-                attributes.add(msn);
-            }
+            aset.add(msn);
         }
+    }
+
+    private void setWin32MediaAttrib(int dmIndex, int width, int length) {
+        addPaperSize(attributes, dmIndex, width, length);
         mAttMediaSizeName = dmIndex;
     }
 
@@ -1788,7 +1829,7 @@
             // no equivalent predefined value
             mAttMediaTray = 7;              // DMBIN_AUTO
         } else if (attr == MediaTray.TOP) {
-            mAttMediaTray =1;               // DMBIN_UPPER
+            mAttMediaTray = 1;              // DMBIN_UPPER
         } else {
             if (attr instanceof Win32MediaTray) {
                 mAttMediaTray = ((Win32MediaTray)attr).winID;
@@ -1914,6 +1955,254 @@
         }
     }
 
+    private static final class DevModeValues {
+        int dmFields;
+        short copies;
+        short collate;
+        short color;
+        short duplex;
+        short orient;
+        short paper;
+        short bin;
+        short xres_quality;
+        short yres;
+    }
+
+    private void getDevModeValues(PrintRequestAttributeSet aset,
+                                  DevModeValues info) {
+
+        Copies c = (Copies)aset.get(Copies.class);
+        if (c != null) {
+            info.dmFields |= DM_COPIES;
+            info.copies = (short)c.getValue();
+        }
+
+        SheetCollate sc = (SheetCollate)aset.get(SheetCollate.class);
+        if (sc != null) {
+            info.dmFields |= DM_COLLATE;
+            info.collate = (sc == SheetCollate.COLLATED) ?
+                DMCOLLATE_TRUE : DMCOLLATE_FALSE;
+        }
+
+        Chromaticity ch = (Chromaticity)aset.get(Chromaticity.class);
+        if (ch != null) {
+            info.dmFields |= DM_COLOR;
+            if (ch == Chromaticity.COLOR) {
+                info.color = DMCOLOR_COLOR;
+            } else {
+                info.color = DMCOLOR_MONOCHROME;
+            }
+        }
+
+        Sides s = (Sides)aset.get(Sides.class);
+        if (s != null) {
+            info.dmFields |= DM_DUPLEX;
+            if (s == Sides.TWO_SIDED_LONG_EDGE) {
+                info.duplex = DMDUP_VERTICAL;
+            } else if (s == Sides.TWO_SIDED_SHORT_EDGE) {
+                info.duplex = DMDUP_HORIZONTAL;
+            } else { // Sides.ONE_SIDED
+                info.duplex = DMDUP_SIMPLEX;
+            }
+        }
+
+        OrientationRequested or =
+            (OrientationRequested)aset.get(OrientationRequested.class);
+        if (or != null) {
+            info.dmFields |= DM_ORIENTATION;
+            info.orient = (or == OrientationRequested.LANDSCAPE)
+                ? DMORIENT_LANDSCAPE : DMORIENT_PORTRAIT;
+        }
+
+        Media m = (Media)aset.get(Media.class);
+        if (m instanceof MediaSizeName) {
+            info.dmFields |= DM_PAPERSIZE;
+            MediaSizeName msn = (MediaSizeName)m;
+            info.paper =
+                (short)((Win32PrintService)myService).findPaperID(msn);
+        }
+
+        MediaTray mt = null;
+        if (m instanceof MediaTray) {
+            mt = (MediaTray)m;
+        }
+        if (mt == null) {
+            SunAlternateMedia sam =
+                (SunAlternateMedia)aset.get(SunAlternateMedia.class);
+            if (sam != null && (sam.getMedia() instanceof MediaTray)) {
+                mt = (MediaTray)sam.getMedia();
+            }
+        }
+
+        if (mt != null) {
+            info.dmFields |= DM_DEFAULTSOURCE;
+            info.bin = (short)(((Win32PrintService)myService).findTrayID(mt));
+        }
+
+        PrintQuality q = (PrintQuality)aset.get(PrintQuality.class);
+        if (q != null) {
+            info.dmFields |= DM_PRINTQUALITY;
+            if (q == PrintQuality.DRAFT) {
+                info.xres_quality = DMRES_DRAFT;
+            } else if (q == PrintQuality.HIGH) {
+                info.xres_quality = DMRES_HIGH;
+            } else {
+                info.xres_quality = DMRES_MEDIUM;
+            }
+        }
+
+        PrinterResolution r =
+            (PrinterResolution)aset.get(PrinterResolution.class);
+        if (r != null) {
+            info.dmFields |= DM_PRINTQUALITY | DM_YRESOLUTION;
+            info.xres_quality =
+                (short)r.getCrossFeedResolution(PrinterResolution.DPI);
+            info.yres = (short)r.getFeedResolution(PrinterResolution.DPI);
+        }
+    }
+
+    /* This method is called from native to update the values in the
+     * attribute set which originates from the cross-platform dialog,
+     * but updated by the native DocumentPropertiesUI which updates the
+     * devmode. This syncs the devmode back in to the attributes so that
+     * we can update the cross-platform dialog.
+     * The attribute set here is a temporary one installed whilst this
+     * happens,
+     */
+    private final void setJobAttributes(PrintRequestAttributeSet attributes,
+                                        int fields, int values,
+                                        short copies,
+                                        short dmPaperSize,
+                                        short dmPaperWidth,
+                                        short dmPaperLength,
+                                        short dmDefaultSource,
+                                        short xRes,
+                                        short yRes) {
+
+        if (attributes == null) {
+            return;
+        }
+
+        if ((fields & DM_COPIES) != 0) {
+            attributes.add(new Copies(copies));
+        }
+
+        if ((fields & DM_COLLATE) != 0) {
+            if ((values & SET_COLLATED) != 0) {
+                attributes.add(SheetCollate.COLLATED);
+            } else {
+                attributes.add(SheetCollate.UNCOLLATED);
+            }
+        }
+
+        if ((fields & DM_ORIENTATION) != 0) {
+            if ((values & SET_ORIENTATION) != 0) {
+                attributes.add(OrientationRequested.LANDSCAPE);
+            } else {
+                attributes.add(OrientationRequested.PORTRAIT);
+            }
+        }
+
+        if ((fields & DM_COLOR) != 0) {
+            if ((values & SET_COLOR) != 0) {
+                attributes.add(Chromaticity.COLOR);
+            } else {
+                attributes.add(Chromaticity.MONOCHROME);
+            }
+        }
+
+        if ((fields & DM_PRINTQUALITY) != 0) {
+            /* value < 0 indicates quality setting.
+             * value > 0 indicates X resolution. In that case
+             * hopefully we will also find y-resolution specified.
+             * If its not, assume its the same as x-res.
+             * Maybe Java code should try to reconcile this against
+             * the printers claimed set of supported resolutions.
+             */
+            if (xRes < 0) {
+                PrintQuality quality;
+                if ((values & SET_RES_LOW) != 0) {
+                    quality = PrintQuality.DRAFT;
+                } else if ((fields & SET_RES_HIGH) != 0) {
+                    quality = PrintQuality.HIGH;
+                } else {
+                    quality = PrintQuality.NORMAL;
+                }
+                attributes.add(quality);
+            } else if (xRes > 0 && yRes > 0) {
+                attributes.add(
+                    new PrinterResolution(xRes, yRes, PrinterResolution.DPI));
+            }
+        }
+
+        if ((fields & DM_DUPLEX) != 0) {
+            Sides sides;
+            if ((values & SET_DUP_VERTICAL) != 0) {
+                sides = Sides.TWO_SIDED_LONG_EDGE;
+            } else if ((values & SET_DUP_HORIZONTAL) != 0) {
+                sides = Sides.TWO_SIDED_SHORT_EDGE;
+            } else {
+                sides = Sides.ONE_SIDED;
+            }
+            attributes.add(sides);
+        }
+
+        if ((fields & DM_PAPERSIZE) != 0) {
+            addPaperSize(attributes, dmPaperSize, dmPaperWidth, dmPaperLength);
+        }
+
+        if ((fields & DM_DEFAULTSOURCE) != 0) {
+            MediaTray tray =
+                ((Win32PrintService)myService).findMediaTray(dmDefaultSource);
+            attributes.add(new SunAlternateMedia(tray));
+        }
+    }
+
+    private native boolean showDocProperties(long hWnd,
+                                             PrintRequestAttributeSet aset,
+                                             int dmFields,
+                                             short copies,
+                                             short collate,
+                                             short color,
+                                             short duplex,
+                                             short orient,
+                                             short paper,
+                                             short bin,
+                                             short xres_quality,
+                                             short yres);
+
+    @SuppressWarnings("deprecation")
+    public PrintRequestAttributeSet
+        showDocumentProperties(Window owner,
+                               PrintService service,
+                               PrintRequestAttributeSet aset)
+    {
+        try {
+            setNativePrintServiceIfNeeded(service.getName());
+        } catch (PrinterException e) {
+        }
+        long hWnd = ((WWindowPeer)(owner.getPeer())).getHWnd();
+        DevModeValues info = new DevModeValues();
+        getDevModeValues(aset, info);
+        boolean ok =
+            showDocProperties(hWnd, aset,
+                              info.dmFields,
+                              info.copies,
+                              info.collate,
+                              info.color,
+                              info.duplex,
+                              info.orient,
+                              info.paper,
+                              info.bin,
+                              info.xres_quality,
+                              info.yres);
+
+        if (ok) {
+            return aset;
+        } else {
+            return null;
+        }
+    }
 
     /* Printer Resolution. See also getXRes() and getYRes() */
     private final void setResolutionDPI(int xres, int yres) {
@@ -1956,7 +2245,7 @@
         }
     //** END Functions called by native code for querying/updating attributes
 
-   }
+    }
 
 class PrintToFileErrorDialog extends Dialog implements ActionListener{
     public PrintToFileErrorDialog(Frame parent, String title, String message,
--- a/jdk/src/windows/classes/sun/awt/windows/WToolkit.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/windows/classes/sun/awt/windows/WToolkit.java	Wed Jul 05 19:11:53 2017 +0200
@@ -64,6 +64,7 @@
 import sun.font.SunFontManager;
 import sun.misc.PerformanceLogger;
 import sun.util.logging.PlatformLogger;
+import sun.security.util.SecurityConstants;
 
 public class WToolkit extends SunToolkit implements Runnable {
 
@@ -681,7 +682,7 @@
     public Clipboard getSystemClipboard() {
         SecurityManager security = System.getSecurityManager();
         if (security != null) {
-          security.checkSystemClipboardAccess();
+            security.checkPermission(SecurityConstants.AWT.ACCESS_CLIPBOARD_PERMISSION);
         }
         synchronized (this) {
             if (clipboard == null) {
--- a/jdk/src/windows/classes/sun/print/Win32MediaTray.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/windows/classes/sun/print/Win32MediaTray.java	Wed Jul 05 19:11:53 2017 +0200
@@ -70,6 +70,10 @@
         winEnumTable.add(this);
     }
 
+    public int getDMBinID() {
+        return winID;
+    }
+
     private static final String[] myStringTable ={
         "Manual-Envelope",
         "Automatic-Feeder",
--- a/jdk/src/windows/classes/sun/print/Win32PrintService.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/windows/classes/sun/print/Win32PrintService.java	Wed Jul 05 19:11:53 2017 +0200
@@ -25,6 +25,8 @@
 
 package sun.print;
 
+import java.awt.Window;
+import java.awt.print.PrinterJob;
 import java.io.File;
 import java.net.URI;
 import java.net.URISyntaxException;
@@ -39,6 +41,7 @@
 import javax.print.attribute.AttributeSetUtilities;
 import javax.print.attribute.EnumSyntax;
 import javax.print.attribute.HashAttributeSet;
+import javax.print.attribute.PrintRequestAttributeSet;
 import javax.print.attribute.PrintServiceAttribute;
 import javax.print.attribute.PrintServiceAttributeSet;
 import javax.print.attribute.HashPrintServiceAttributeSet;
@@ -69,6 +72,7 @@
 import javax.print.attribute.standard.PrinterResolution;
 import javax.print.attribute.standard.SheetCollate;
 import javax.print.event.PrintServiceAttributeListener;
+import sun.awt.windows.WPrinterJob;
 
 public class Win32PrintService implements PrintService, AttributeUpdater,
                                           SunPrinterJobService {
@@ -282,6 +286,22 @@
         return 0;
     }
 
+    public int findTrayID(MediaTray tray) {
+
+        getMediaTrays(); // make sure they are initialised.
+
+        if (tray instanceof Win32MediaTray) {
+            Win32MediaTray winTray = (Win32MediaTray)tray;
+            return winTray.getDMBinID();
+        }
+        for (int id=0; id<dmPaperBinToPrintService.length; id++) {
+            if (tray.equals(dmPaperBinToPrintService[id])) {
+                return id+1; // DMBIN_FIRST = 1;
+            }
+        }
+        return 0; // didn't find the tray
+    }
+
     public MediaTray findMediaTray(int dmBin) {
         if (dmBin >= 1 && dmBin <= dmPaperBinToPrintService.length) {
             return dmPaperBinToPrintService[dmBin-1];
@@ -673,7 +693,6 @@
         return arr2;
     }
 
-
     private PrinterIsAcceptingJobs getPrinterIsAcceptingJobs() {
         if (getJobStatus(printer, 2) != 1) {
             return PrinterIsAcceptingJobs.NOT_ACCEPTING_JOBS;
@@ -1596,8 +1615,76 @@
         }
     }
 
-    public ServiceUIFactory getServiceUIFactory() {
-        return null;
+    private Win32DocumentPropertiesUI docPropertiesUI = null;
+
+    private static class Win32DocumentPropertiesUI
+        extends DocumentPropertiesUI {
+
+        Win32PrintService service;
+
+        private Win32DocumentPropertiesUI(Win32PrintService s) {
+            service = s;
+        }
+
+        public PrintRequestAttributeSet
+            showDocumentProperties(PrinterJob job,
+                                   Window owner,
+                                   PrintService service,
+                                   PrintRequestAttributeSet aset) {
+
+            if (!(job instanceof WPrinterJob)) {
+                return null;
+            }
+            WPrinterJob wJob = (WPrinterJob)job;
+            return wJob.showDocumentProperties(owner, service, aset);
+        }
+    }
+
+    private synchronized DocumentPropertiesUI getDocumentPropertiesUI() {
+        return new Win32DocumentPropertiesUI(this);
+    }
+
+    private static class Win32ServiceUIFactory extends ServiceUIFactory {
+
+        Win32PrintService service;
+
+        Win32ServiceUIFactory(Win32PrintService s) {
+            service = s;
+        }
+
+        public Object getUI(int role, String ui) {
+            if (role <= ServiceUIFactory.MAIN_UIROLE) {
+                return null;
+            }
+            if (role == DocumentPropertiesUI.DOCUMENTPROPERTIES_ROLE &&
+                DocumentPropertiesUI.DOCPROPERTIESCLASSNAME.equals(ui))
+            {
+                return service.getDocumentPropertiesUI();
+            }
+            throw new IllegalArgumentException("Unsupported role");
+        }
+
+        public String[] getUIClassNamesForRole(int role) {
+
+            if (role <= ServiceUIFactory.MAIN_UIROLE) {
+                return null;
+            }
+            if (role == DocumentPropertiesUI.DOCUMENTPROPERTIES_ROLE) {
+                String[] names = new String[0];
+                names[0] = DocumentPropertiesUI.DOCPROPERTIESCLASSNAME;
+                return names;
+            }
+            throw new IllegalArgumentException("Unsupported role");
+        }
+    }
+
+    private Win32ServiceUIFactory uiFactory = null;
+
+    public synchronized ServiceUIFactory getServiceUIFactory() {
+        if (uiFactory == null) {
+            uiFactory = new Win32ServiceUIFactory(this);
+        }
+        return uiFactory;
     }
 
     public String toString() {
--- a/jdk/src/windows/classes/sun/security/mscapi/Key.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/windows/classes/sun/security/mscapi/Key.java	Wed Jul 05 19:11:53 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -39,6 +39,7 @@
  */
 abstract class Key implements java.security.Key, Length
 {
+    private static final long serialVersionUID = -1088859394025049194L;
 
     // Native handle
     protected long hCryptProv = 0;
--- a/jdk/src/windows/native/java/net/NetworkInterface.c	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/windows/native/java/net/NetworkInterface.c	Wed Jul 05 19:11:53 2017 +0200
@@ -900,7 +900,7 @@
     MIB_IFROW *ifRowP;
     ifRowP = getIF(index);
     if (ifRowP != NULL) {
-      ret = ifRowP->dwAdminStatus == 1 &&
+      ret = ifRowP->dwAdminStatus == MIB_IF_ADMIN_STATUS_UP &&
             (ifRowP->dwOperStatus == MIB_IF_OPER_STATUS_OPERATIONAL ||
              ifRowP->dwOperStatus == MIB_IF_OPER_STATUS_CONNECTED);
       free(ifRowP);
--- a/jdk/src/windows/native/java/net/NetworkInterface_winXP.c	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/windows/native/java/net/NetworkInterface_winXP.c	Wed Jul 05 19:11:53 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -82,7 +82,6 @@
     IP_ADAPTER_ADDRESSES *adapterInfo;
     ULONG len;
     adapterInfo = (IP_ADAPTER_ADDRESSES *)malloc (bufsize);
-
     if (adapterInfo == NULL) {
         JNU_ThrowByName(env, "java/lang/OutOfMemoryError", "Native heap allocation failure");
         return -1;
@@ -160,8 +159,12 @@
     ptr = adapterInfo;
     ret = NULL;
     while (ptr != NULL) {
-      // IPv4 interface
-      if (ptr->Ipv6IfIndex == index) {
+      // in theory the IPv4 index and the IPv6 index can be the same
+      // where an interface is enabled for v4 and v6
+      // IfIndex == 0 IPv4 not available on this interface
+      // Ipv6IfIndex == 0 IPv6 not available on this interface
+      if (((ptr->IfIndex != 0)&&(ptr->IfIndex == index)) ||
+          ((ptr->Ipv6IfIndex !=0) && (ptr->Ipv6IfIndex == index))) {
         ret = (IP_ADAPTER_ADDRESSES *) malloc(sizeof(IP_ADAPTER_ADDRESSES));
         if (ret == NULL) {
             free(adapterInfo);
@@ -172,6 +175,7 @@
         //copy the memory and break out of the while loop.
         memcpy(ret, ptr, sizeof(IP_ADAPTER_ADDRESSES));
         break;
+
       }
       ptr=ptr->Next;
     }
@@ -192,7 +196,6 @@
     int tun=0, net=0;
 
     *netifPP = NULL;
-
    /*
     * Get the IPv4 interfaces. This information is the same
     * as what previous JDK versions would return.
@@ -264,7 +267,7 @@
                          * set the index to the IPv6 index and add the
                          * IPv6 addresses
                          */
-                        nif->index = ptr->Ipv6IfIndex;
+                        nif->ipv6Index = ptr->Ipv6IfIndex;
                         c = getAddrsFromAdapter(ptr, &nif->addrs);
                         nif->naddrs += c;
                         break;
@@ -309,6 +312,9 @@
                         strcpy (nif->name, newname);
                         wcscpy ((PWCHAR)nif->displayName, ptr->FriendlyName);
                         nif->dNameIsUnicode = TRUE;
+
+                        // the java.net.NetworkInterface abstraction only has index
+                        // so the Ipv6IfIndex needs to map onto index
                         nif->index = ptr->Ipv6IfIndex;
                         nif->ipv6Index = ptr->Ipv6IfIndex;
                         nif->hasIpv6Address = TRUE;
@@ -487,7 +493,6 @@
     (*env)->SetObjectField(env, netifObj, ni_nameID, name);
     (*env)->SetObjectField(env, netifObj, ni_displayNameID, displayName);
     (*env)->SetIntField(env, netifObj, ni_indexID, ifs->index);
-
     /*
      * Get the IP addresses for this interface if necessary
      * Note that 0 is a valid number of addresses.
--- a/jdk/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/windows/native/java/net/TwoStacksPlainDatagramSocketImpl.c	Wed Jul 05 19:11:53 2017 +0200
@@ -43,6 +43,7 @@
 #include "java_net_SocketOptions.h"
 #include "java_net_NetworkInterface.h"
 
+#include "NetworkInterface.h"
 #include "jvm.h"
 #include "jni_util.h"
 #include "net_util.h"
@@ -1644,6 +1645,33 @@
     return (*env)->GetIntField(env, nif, ni_indexID);
 }
 
+static int isAdapterIpv6Enabled(JNIEnv *env, int index) {
+  netif *ifList, *curr;
+  int ipv6Enabled = 0;
+  if (getAllInterfacesAndAddresses (env, &ifList) < 0) {
+      return ipv6Enabled;
+  }
+
+  /* search by index */
+  curr = ifList;
+  while (curr != NULL) {
+      if (index == curr->index) {
+          break;
+      }
+      curr = curr->next;
+  }
+
+  /* if found ipv6Index != 0 then interface is configured with IPV6 */
+  if ((curr != NULL) && (curr->ipv6Index !=0)) {
+      ipv6Enabled = 1;
+  }
+
+  /* release the interface list */
+  free_netif(ifList);
+
+  return ipv6Enabled;
+}
+
 /*
  * Sets the multicast interface.
  *
@@ -1703,7 +1731,6 @@
             struct in_addr in;
 
             in.s_addr = htonl(getInetAddress_addr(env, value));
-
             if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
                                (const char*)&in, sizeof(in)) < 0) {
                 NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
@@ -1734,19 +1761,20 @@
             }
             index = (*env)->GetIntField(env, value, ni_indexID);
 
-            if (setsockopt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF,
+            if ( isAdapterIpv6Enabled(env, index) != 0 ) {
+                if (setsockopt(fd1, IPPROTO_IPV6, IPV6_MULTICAST_IF,
                                (const char*)&index, sizeof(index)) < 0) {
-                if (errno == EINVAL && index > 0) {
-                    JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
-                        "IPV6_MULTICAST_IF failed (interface has IPv4 "
-                        "address only?)");
-                } else {
-                    NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
+                    if (errno == EINVAL && index > 0) {
+                        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+                            "IPV6_MULTICAST_IF failed (interface has IPv4 "
+                            "address only?)");
+                    } else {
+                        NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
                                    "Error setting socket option");
+                    }
+                    return;
                 }
-                return;
             }
-
             /* If there are any IPv4 addresses on this interface then
              * repeat the operation on the IPv4 fd */
 
@@ -1797,7 +1825,6 @@
         char c;
     } optval;
     int ipv6_supported = ipv6_available();
-
     fd = getFD(env, this);
 
     if (ipv6_supported) {
@@ -1898,42 +1925,21 @@
 }
 
 /*
- * Return the multicast interface:
- *
- * SocketOptions.IP_MULTICAST_IF
- *      IPv4:   Query IPPROTO_IP/IP_MULTICAST_IF
- *              Create InetAddress
- *              IP_MULTICAST_IF returns struct ip_mreqn on 2.2
- *              kernel but struct in_addr on 2.4 kernel
- *      IPv6:   Query IPPROTO_IPV6 / IPV6_MULTICAST_IF or
- *              obtain from impl is Linux 2.2 kernel
- *              If index == 0 return InetAddress representing
- *              anyLocalAddress.
- *              If index > 0 query NetworkInterface by index
- *              and returns addrs[0]
  *
- * SocketOptions.IP_MULTICAST_IF2
- *      IPv4:   Query IPPROTO_IP/IP_MULTICAST_IF
- *              Query NetworkInterface by IP address and
- *              return the NetworkInterface that the address
- *              is bound too.
- *      IPv6:   Query IPPROTO_IPV6 / IPV6_MULTICAST_IF
- *              (except Linux .2 kernel)
- *              Query NetworkInterface by index and
- *              return NetworkInterface.
+ * called by getMulticastInterface to retrieve a NetworkInterface
+ * configured for IPv4.
+ * The ipv4Mode parameter, is a closet boolean, which allows for a NULL return,
+ * or forces the creation of a NetworkInterface object with null data.
+ * It relates to its calling context in getMulticastInterface.
+ * ipv4Mode == 1, the context is IPV4 processing only.
+ * ipv4Mode == 0, the context is IPV6 processing
+ *
  */
-jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1, jint opt) {
-    jboolean isIPV4 = !ipv6_available() || fd1 == -1;
-
-    /*
-     * IPv4 implementation
-     */
-    if (isIPV4) {
+static jobject getIPv4NetworkInterface (JNIEnv *env, jobject this, int fd, jint opt, int ipv4Mode) {
         static jclass inet4_class;
         static jmethodID inet4_ctrID;
 
-        static jclass ni_class;
-        static jmethodID ni_ctrID;
+        static jclass ni_class; static jmethodID ni_ctrID;
         static jfieldID ni_indexID;
         static jfieldID ni_addrsID;
 
@@ -1944,7 +1950,6 @@
         struct in_addr in;
         struct in_addr *inP = &in;
         int len = sizeof(struct in_addr);
-
         if (getsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
                            (char *)inP, &len) < 0) {
             NET_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
@@ -1996,24 +2001,58 @@
         if (ni) {
             return ni;
         }
+        if (ipv4Mode) {
+            ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0);
+            CHECK_NULL_RETURN(ni, NULL);
 
-        /*
-         * The address doesn't appear to be bound at any known
-         * NetworkInterface. Therefore we construct a NetworkInterface
-         * with this address.
-         */
-        ni = (*env)->NewObject(env, ni_class, ni_ctrID, 0);
-        CHECK_NULL_RETURN(ni, NULL);
+            (*env)->SetIntField(env, ni, ni_indexID, -1);
+            addrArray = (*env)->NewObjectArray(env, 1, inet4_class, NULL);
+            CHECK_NULL_RETURN(addrArray, NULL);
+            (*env)->SetObjectArrayElement(env, addrArray, 0, addr);
+            (*env)->SetObjectField(env, ni, ni_addrsID, addrArray);
+        } else {
+            ni = NULL;
+        }
+        return ni;
+}
 
-        (*env)->SetIntField(env, ni, ni_indexID, -1);
-        addrArray = (*env)->NewObjectArray(env, 1, inet4_class, NULL);
-        CHECK_NULL_RETURN(addrArray, NULL);
-        (*env)->SetObjectArrayElement(env, addrArray, 0, addr);
-        (*env)->SetObjectField(env, ni, ni_addrsID, addrArray);
-        return ni;
+/*
+ * Return the multicast interface:
+ *
+ * SocketOptions.IP_MULTICAST_IF
+ *      IPv4:   Query IPPROTO_IP/IP_MULTICAST_IF
+ *              Create InetAddress
+ *              IP_MULTICAST_IF returns struct ip_mreqn on 2.2
+ *              kernel but struct in_addr on 2.4 kernel
+ *      IPv6:   Query IPPROTO_IPV6 / IPV6_MULTICAST_IF or
+ *              obtain from impl is Linux 2.2 kernel
+ *              If index == 0 return InetAddress representing
+ *              anyLocalAddress.
+ *              If index > 0 query NetworkInterface by index
+ *              and returns addrs[0]
+ *
+ * SocketOptions.IP_MULTICAST_IF2
+ *      IPv4:   Query IPPROTO_IP/IP_MULTICAST_IF
+ *              Query NetworkInterface by IP address and
+ *              return the NetworkInterface that the address
+ *              is bound too.
+ *      IPv6:   Query IPPROTO_IPV6 / IPV6_MULTICAST_IF
+ *              (except Linux .2 kernel)
+ *              Query NetworkInterface by index and
+ *              return NetworkInterface.
+ */
+jobject getMulticastInterface(JNIEnv *env, jobject this, int fd, int fd1, jint opt) {
+    jboolean isIPV4 = !ipv6_available() || fd1 == -1;
+
+    /*
+     * IPv4 implementation
+     */
+    if (isIPV4) {
+        jobject netObject = NULL; // return is either an addr or a netif
+        netObject = getIPv4NetworkInterface(env, this, fd, opt, 1);
+        return netObject;
     }
 
-
     /*
      * IPv6 implementation
      */
@@ -2103,6 +2142,13 @@
 
             addr = (*env)->GetObjectArrayElement(env, addrArray, 0);
             return addr;
+        } else if (index == 0) { // index == 0 typically means IPv6 not configured on the interfaces
+            // falling back to treat interface as configured for IPv4
+            jobject netObject = NULL;
+            netObject = getIPv4NetworkInterface(env, this, fd, opt, 0);
+            if (netObject != NULL) {
+                return netObject;
+            }
         }
 
         /*
@@ -2127,6 +2173,8 @@
     }
     return NULL;
 }
+
+
 /*
  * Returns relevant info as a jint.
  *
--- a/jdk/src/windows/native/sun/windows/awt_PrintControl.cpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/windows/native/sun/windows/awt_PrintControl.cpp	Wed Jul 05 19:11:53 2017 +0200
@@ -81,6 +81,7 @@
 jmethodID AwtPrintControl::setNativeAttID;
 jmethodID AwtPrintControl::setRangeCopiesID;
 jmethodID AwtPrintControl::setResID;
+jmethodID AwtPrintControl::setJobAttributesID;
 
 
 BOOL AwtPrintControl::IsSupportedLevel(HANDLE hPrinter, DWORD dwLevel) {
@@ -297,6 +298,10 @@
     AwtPrintControl::setPrinterID =
       env->GetMethodID(cls, "setPrinterNameAttrib", "(Ljava/lang/String;)V");
 
+    AwtPrintControl::setJobAttributesID =
+        env->GetMethodID(cls, "setJobAttributes",
+        "(Ljavax/print/attribute/PrintRequestAttributeSet;IISSSSSSS)V");
+
     DASSERT(AwtPrintControl::driverDoesMultipleCopiesID != NULL);
     DASSERT(AwtPrintControl::getPrintDCID != NULL);
     DASSERT(AwtPrintControl::setPrintDCID != NULL);
@@ -327,6 +332,7 @@
     DASSERT(AwtPrintControl::getSidesID != NULL);
     DASSERT(AwtPrintControl::getSelectID != NULL);
     DASSERT(AwtPrintControl::getPrintToFileEnabledID != NULL);
+    DASSERT(AwtPrintControl::setJobAttributesID != NULL);
 
 
     CATCH_BAD_ALLOC;
--- a/jdk/src/windows/native/sun/windows/awt_PrintControl.h	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/windows/native/sun/windows/awt_PrintControl.h	Wed Jul 05 19:11:53 2017 +0200
@@ -47,7 +47,6 @@
     static jmethodID setDevmodeID;
     static jmethodID getDevnamesID;
     static jmethodID setDevnamesID;
-
     static jmethodID getWin32MediaID;
     static jmethodID setWin32MediaID;
     static jmethodID getWin32MediaTrayID;
@@ -73,6 +72,7 @@
     static jmethodID setNativeAttID;
     static jmethodID setRangeCopiesID;
     static jmethodID setResID;
+    static jmethodID setJobAttributesID;
 
     static void initIDs(JNIEnv *env, jclass cls);
     static BOOL FindPrinter(jstring printerName, LPBYTE pPrinterEnum,
--- a/jdk/src/windows/native/sun/windows/awt_PrintJob.cpp	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/src/windows/native/sun/windows/awt_PrintJob.cpp	Wed Jul 05 19:11:53 2017 +0200
@@ -329,6 +329,156 @@
 static int embolden(int currentWeight);
 static BOOL getPrintableArea(HDC pdc, HANDLE hDevMode, RectDouble *margin);
 
+
+
+/************************************************************************
+ * DocumentProperties native support
+ */
+
+/* Values must match those defined in WPrinterJob.java */
+static const DWORD SET_COLOR = 0x00000200;
+static const DWORD SET_ORIENTATION = 0x00004000;
+static const DWORD SET_COLLATED    = 0x00008000;
+static const DWORD SET_DUP_VERTICAL = 0x00000010;
+static const DWORD SET_DUP_HORIZONTAL = 0x00000020;
+static const DWORD SET_RES_HIGH = 0x00000040;
+static const DWORD SET_RES_LOW = 0x00000080;
+
+/*
+ * Copy DEVMODE state back into JobAttributes.
+ */
+
+static void UpdateJobAttributes(JNIEnv *env,
+                                jobject wJob,
+                                jobject attrSet,
+                                DEVMODE *devmode) {
+
+    DWORD dmValues = 0;
+    int xRes = 0, yRes = 0;
+
+    if (devmode->dmFields & DM_COLOR) {
+        if (devmode->dmColor == DMCOLOR_COLOR) {
+            dmValues |= SET_COLOR;
+        }
+    }
+
+    if (devmode->dmFields & DM_ORIENTATION) {
+        if (devmode->dmOrientation == DMORIENT_LANDSCAPE) {
+            dmValues |= SET_ORIENTATION;
+        }
+    }
+
+    if (devmode->dmFields & DM_COLLATE &&
+        devmode->dmCollate == DMCOLLATE_TRUE) {
+            dmValues |= SET_COLLATED;
+    }
+
+    if (devmode->dmFields & DM_PRINTQUALITY) {
+        /* value < 0 indicates quality setting.
+         * value > 0 indicates X resolution. In that case
+         * hopefully we will also find y-resolution specified.
+         * If its not, assume its the same as x-res.
+         * Maybe Java code should try to reconcile this against
+          * the printers claimed set of supported resolutions.
+         */
+        if (devmode->dmPrintQuality < 0) {
+            if (devmode->dmPrintQuality == DMRES_HIGH) {
+                dmValues |= SET_RES_HIGH;
+            } else if ((devmode->dmPrintQuality == DMRES_LOW) ||
+                       (devmode->dmPrintQuality == DMRES_DRAFT)) {
+                dmValues |= SET_RES_LOW;
+            }
+            /* else if (devmode->dmPrintQuality == DMRES_MEDIUM)
+             * will set to NORMAL.
+             */
+        } else {
+            xRes = devmode->dmPrintQuality;
+            yRes = (devmode->dmFields & DM_YRESOLUTION) ?
+                devmode->dmYResolution : devmode->dmPrintQuality;
+        }
+    }
+
+    if (devmode->dmFields & DM_DUPLEX) {
+        if (devmode->dmDuplex == DMDUP_HORIZONTAL) {
+            dmValues |= SET_DUP_HORIZONTAL;
+        } else if (devmode->dmDuplex == DMDUP_VERTICAL) {
+            dmValues |= SET_DUP_VERTICAL;
+        }
+    }
+
+    env->CallVoidMethod(wJob, AwtPrintControl::setJobAttributesID, attrSet,
+                        devmode->dmFields, dmValues, devmode->dmCopies,
+                        devmode->dmPaperSize, devmode->dmPaperWidth,
+                        devmode->dmPaperLength, devmode->dmDefaultSource,
+                        xRes, yRes);
+
+}
+
+JNIEXPORT jboolean JNICALL
+Java_sun_awt_windows_WPrinterJob_showDocProperties(JNIEnv *env,
+                                                   jobject wJob,
+                                                   jlong hWndParent,
+                                                   jobject attrSet,
+                                                   jint dmFields,
+                                                   jshort copies,
+                                                   jshort collate,
+                                                   jshort color,
+                                                   jshort duplex,
+                                                   jshort orient,
+                                                   jshort paper,
+                                                   jshort bin,
+                                                   jshort xres_quality,
+                                                   jshort yres)
+{
+    TRY;
+
+    HGLOBAL hDevMode = AwtPrintControl::getPrintHDMode(env, wJob);
+    HGLOBAL hDevNames = AwtPrintControl::getPrintHDName(env, wJob);
+    DEVMODE *devmode = NULL;
+    DEVNAMES *devnames = NULL;
+    LONG rval = IDCANCEL;
+    jboolean ret = JNI_FALSE;
+
+    if (hDevMode != NULL && hDevNames != NULL) {
+        devmode = (DEVMODE *)::GlobalLock(hDevMode);
+        devnames = (DEVNAMES *)::GlobalLock(hDevNames);
+
+        LPTSTR lpdevnames = (LPTSTR)devnames;
+        // No need to call _tcsdup as we won't unlock until we are done.
+        LPTSTR printerName = lpdevnames+devnames->wDeviceOffset;
+        LPTSTR portName = lpdevnames+devnames->wOutputOffset;
+
+        HANDLE hPrinter;
+        if (::OpenPrinter(printerName, &hPrinter, NULL) == TRUE) {
+            devmode->dmFields |= dmFields;
+            devmode->dmCopies = copies;
+            devmode->dmCollate = collate;
+            devmode->dmColor = color;
+            devmode->dmDuplex = duplex;
+            devmode->dmOrientation = orient;
+            devmode->dmPrintQuality = xres_quality;
+            devmode->dmYResolution = yres;
+            devmode->dmPaperSize = paper;
+            devmode->dmDefaultSource = bin;
+
+            rval = ::DocumentProperties((HWND)hWndParent,
+                           hPrinter, printerName, devmode, devmode,
+                           DM_IN_BUFFER | DM_OUT_BUFFER | DM_IN_PROMPT);
+            if (rval == IDOK) {
+                UpdateJobAttributes(env, wJob, attrSet, devmode);
+                ret = JNI_TRUE;
+            }
+            VERIFY(::ClosePrinter(hPrinter));
+        }
+        ::GlobalUnlock(hDevNames);
+        ::GlobalUnlock(hDevMode);
+    }
+
+    return ret;
+
+    CATCH_BAD_ALLOC_RET(0);
+}
+
 /************************************************************************
  * WPageDialog native methods
  */
@@ -732,7 +882,6 @@
         memset(&pd, 0, sizeof(PRINTDLG));
         pd.lStructSize = sizeof(PRINTDLG);
         pd.Flags = PD_RETURNDEFAULT | PD_RETURNDC;
-
         if (::PrintDlg(&pd)) {
             printDC = pd.hDC;
             hDevMode = pd.hDevMode;
@@ -792,8 +941,19 @@
     jint imgPixelWid = GetDeviceCaps(printDC, HORZRES);
     jint imgPixelHgt = GetDeviceCaps(printDC, VERTRES);
 
+    // The DC may be obtained when we first selected the printer as a
+    // result of a call to setNativePrintService.
+    // If the Devmode was obtained later on from the DocumentProperties dialog
+    // the DC won't have been updated and its settings may be for PORTRAIT.
+    // This may happen in other cases too, but was observed for the above.
+    // To get a DC compatible with this devmode we should really call
+    // CreateDC() again to get a DC for the devmode we are using.
+    // The changes for that are a lot more risk, so to minimise that
+    // risk, assume its not LANDSCAPE unless width > height, even if the
+    // devmode says its LANDSCAPE.
     // if the values were obtained from a rotated device, swap.
-    if (getOrientationFromDevMode2(hDevMode) == DMORIENT_LANDSCAPE) {
+    if ((getOrientationFromDevMode2(hDevMode) == DMORIENT_LANDSCAPE) &&
+        (imgPixelWid > imgPixelHgt)) {
       jint tmp;
       tmp = xPixelRes;
       xPixelRes = yPixelRes;
@@ -941,6 +1101,9 @@
             setBooleanField(env, self, DRIVER_COLLATE_STR, JNI_FALSE);
         }
 
+        if (dmFields & DM_COPIES) {
+            setBooleanField(env, self, DRIVER_COPIES_STR, JNI_TRUE);
+        }
     }
 
     CATCH_BAD_ALLOC;
--- a/jdk/test/ProblemList.txt	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/ProblemList.txt	Wed Jul 05 19:11:53 2017 +0200
@@ -212,13 +212,6 @@
 
 ############################################################################
 
-# jdk_io
-
-# 7160013
-#java/io/File/MaxPathLength.java                                 windows-all
-
-############################################################################
-
 # jdk_nio
 
 # 6963118
@@ -319,10 +312,6 @@
 # 6461635
 com/sun/tools/attach/BasicTests.sh                              generic-all
 
-# 7172176
-sun/tools/jconsole/ResourceCheckTest.sh                         generic-all
-sun/tools/jconsole/ImmutableResourceTest.sh                     generic-all
-
 # 7132203
 sun/jvmstat/monitor/MonitoredVm/CR6672135.java                  generic-all
 
--- a/jdk/test/TEST.groups	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/TEST.groups	Wed Jul 05 19:11:53 2017 +0200
@@ -20,6 +20,7 @@
 #  questions.
 #
 
+# java.lang package and VM runtime support
 jdk_lang = \
     java/lang \
     -java/lang/management \
@@ -27,11 +28,67 @@
     sun/invoke \
     sun/misc \
     sun/reflect \
+    jdk/lambda \
     vm
 
+# All of the java.util package
 jdk_util = \
+    :jdk_util_other \
+    :jdk_collections \
+    :jdk_concurrent \
+    :jdk_stream
+
+# All util components not part of some other util category
+jdk_util_other = \
     java/util \
-    sun/util
+    sun/util \
+    -:jdk_collections \
+    -:jdk_concurrent \
+    -:jdk_stream
+
+# java.util.concurrent (JSR-166)
+# Maintained by JSR-166 EG (Doug Lea et al)
+# Deque and PriorityQueue are also generally maintained by JSR-166
+jdk_concurrent = \
+    java/util/concurrent \
+    java/util/Deque \
+    java/util/PriorityQueue
+
+# Java Collections Framework
+jdk_collections = \
+    java/util/AbstractCollection \
+    java/util/AbstractList \
+    java/util/AbstractMap \
+    java/util/AbstractSequentialList \
+    java/util/ArrayList \
+    java/util/Arrays \
+    java/util/BitSet \
+    java/util/Collection \
+    java/util/Collections \
+    java/util/EnumMap \
+    java/util/EnumSet \
+    java/util/Comparator \
+    java/util/Iterator \
+    java/util/HashMap \
+    java/util/Hashtable \
+    java/util/IdentityHashMap \
+    java/util/List \
+    java/util/LinkedHashMap \
+    java/util/LinkedHashSet \
+    java/util/LinkedList \
+    java/util/Map \
+    java/util/NavigableMap \
+    java/util/TimSort \
+    java/util/TreeMap \
+    java/util/Vector \
+    java/util/WeakHashMap
+
+# java.util.stream (JSR-335)
+jdk_stream = \
+    java/util/Optional \
+    java/util/SummaryStatistics \
+    java/util/function \
+    java/util/stream
 
 jdk_math = \
     java/math
@@ -133,7 +190,6 @@
     javax/xml \
     -javax/xml/crypto \
     jdk/asm \
-    jdk/lambda \
     com/sun/jndi \
     com/sun/corba \
     lib/testlibrary \
@@ -212,3 +268,341 @@
     :jdk_swing \
     :jdk_sound \
     :jdk_imageio
+
+###############################################################################
+# Profile-based Test Group Definitions
+#
+# These groups define the tests that cover the different possible runtimes:
+# - compact1, compact2, compact3, full JRE, JDK
+#
+# In addition they support testing of the minimal VM on compact1 and compact2.
+# Essentially this defines groups based around the specified API's and VM 
+# services available in the runtime.
+#
+# The groups are defined hierarchically in two forms:
+# - The need_xxx groups list all the tests that have a dependency on
+# a specific profile. This is either because it tests a feature in
+# that profile, or the test infrastructure uses a feature in that
+# profile.
+# - The primary groups are defined in terms of the other primary groups
+# combined with the needs_xxx groups (including and excluding them as
+# appropriate). For example the jre can run all tests from compact3, plus
+# those from needs_jre, but excluding those from need_jdk.
+#
+# The bottom group defines all the actual tests to be considered, simply
+# by listing the top-level test directories.
+
+# Full JDK can run all tests
+#
+jdk = \
+  :jre \
+  :needs_jdk
+
+# Tests that require a full JDK to execute. Either they test a feature
+# only in the JDK or they use tools that are only in the JDK. The latter
+# can be resolved in some cases by using tools from the compile-jdk.
+#
+needs_jdk = \
+  :jdk_jdi \
+  com/sun/tools \
+  demo \
+  sun/security/tools/jarsigner \
+  sun/rmi/rmic \
+  sun/tools \
+  sun/jvmstat \
+  tools \
+  com/sun/jmx/remote/NotificationMarshalVersions/TestSerializationMismatch.java \
+  java/io/Serializable/serialver \
+  java/lang/invoke/lambda/LambdaAccessControlDoPrivilegedTest.java \
+  java/lang/invoke/lambda/LambdaAccessControlTest.java \
+  java/lang/System/MacEncoding/TestFileEncoding.java \
+  java/net/URLClassLoader/closetest/GetResourceAsStream.java \
+  java/util/Collections/EmptyIterator.java \
+  java/util/concurrent/locks/Lock/TimedAcquireLeak.java \
+  java/util/jar/Manifest/CreateManifest.java \
+  java/util/jar/JarInputStream/ExtraFileInMetaInf.java \
+  java/util/logging/AnonLoggerWeakRefLeak.sh \
+  java/util/logging/LoggerWeakRefLeak.sh \
+  java/util/zip/3GBZipFiles.sh \
+  jdk/lambda/FDTest.java \
+  jdk/lambda/separate/Compiler.java \
+  sun/management/jdp/JdpTest.sh \
+  sun/management/jmxremote/bootstrap/JvmstatCountersTest.java \
+  sun/management/jmxremote/bootstrap/LocalManagementTest.sh \
+  sun/misc/JarIndex/metaInfFilenames/Basic.java \
+  sun/misc/JarIndex/JarIndexMergeForClassLoaderTest.java \
+  sun/reflect/CallerSensitive/CallerSensitiveFinder.java \
+  sun/reflect/CallerSensitive/MissingCallerSensitive.java \
+  sun/security/util/Resources/NewNamesFormat.java \
+  vm/verifier/defaultMethods/DefaultMethodRegressionTestsRun.java
+
+# JRE adds further tests to compact3
+#
+jre = \
+  :compact3 \
+  :needs_jre \
+ -:needs_jdk
+
+# Tests that require the full JRE
+#
+needs_jre = \
+  :needs_charsets \
+  :jdk_desktop \
+  com/sun/corba \
+  com/sun/jndi/cosnaming \
+  sun/net/ftp \
+  sun/net/www/protocol/ftp \
+  sun/security/tools/policytool \
+  java/net/URI/URItoURLTest.java \
+  java/net/URL/URIToURLTest.java \
+  java/net/URLConnection/HandleContentTypeWithAttrs.java \
+  java/security/Security/ClassLoaderDeadlock/ClassLoaderDeadlock.sh \
+  java/security/Security/ClassLoaderDeadlock/Deadlock.sh \
+  java/util/logging/Listeners.java \
+  java/util/logging/ListenersWithSM.java \
+  java/util/ResourceBundle/Control/Bug6530694.java \
+  java/text/Bidi/BidiConformance.java \
+  java/text/Bidi/BidiEmbeddingTest.java \
+  java/text/Bidi/Bug6665028.java \
+  java/text/Bidi/Bug7042148.java \
+  java/text/Bidi/Bug7051769.java \
+  javax/crypto/Cipher/CipherStreamClose.java \
+  javax/management/monitor/AttributeArbitraryDataTypeTest.java \
+  jdk/lambda/vm/InterfaceAccessFlagsTest.java \
+  sun/misc/URLClassPath/ClassnameCharTest.java
+
+# Tests dependent on the optional charsets.jar
+# These are isolated for easy exclusions
+#
+needs_charsets = \
+  java/io/OutputStreamWriter/TestWrite.java \
+  java/nio/charset/RemovingSunIO/SunioAlias.java \
+  java/nio/charset/coders/Check.java \
+  java/nio/charset/Charset/CharsetContainmentTest.java \
+  java/nio/charset/Charset/Contains.java \
+  java/nio/charset/Charset/NIOCharsetAvailabilityTest.java \
+  java/nio/charset/Charset/RegisteredCharsets.java \
+  java/nio/charset/CharsetEncoder/Flush.java \
+  java/nio/charset/coders/CheckSJISMappingProp.sh \
+  java/nio/charset/coders/ResetISO2022JP.java \
+  java/util/Locale/InternationalBAT.java \
+  java/util/Locale/LocaleProviders.sh \
+  java/util/Calendar/CldrFormatNamesTest.java \
+  java/util/TimeZone/CLDRDisplayNamesTest.java \
+  java/util/zip/ZipCoding.java \
+  sun/nio/cs/EucJpLinux0212.java \
+  sun/nio/cs/EUCJPUnderflowDecodeTest.java \
+  sun/nio/cs/EuroConverter.java \
+  sun/nio/cs/JISAutoDetectTest.java \
+  sun/nio/cs/OLD/TestIBMDB.java \
+  sun/nio/cs/SJISCanEncode.java \
+  sun/nio/cs/Test6254467.java \
+  sun/nio/cs/TestCompoundTest.java \
+  sun/nio/cs/TestCp834_SBCS.java \
+  sun/nio/cs/TestEUC_TW.java \
+  sun/nio/cs/TestISO2022CNDecoder.java \
+  sun/nio/cs/TestISO2022JPEncoder.java \
+  sun/nio/cs/TestISO2022JPSubBytes.java \
+  sun/nio/cs/TestIllegalSJIS.java \
+  sun/nio/cs/TestJIS0208Decoder.java \
+  sun/nio/cs/TestJIS0212Decoder.java \
+  sun/nio/cs/TestMiscEUC_JP.java \
+  sun/nio/cs/TestSJIS0213_SM.java \
+  sun/nio/cs/BufferUnderflowEUCTWTest.java \
+  sun/nio/cs/CheckCaseInsensitiveEncAliases.java \
+  sun/nio/cs/CheckHistoricalNames.java \
+  sun/nio/cs/EucJpLinuxDecoderRecoveryTest.java \
+  sun/nio/cs/HWKatakanaMS932EncodeTest.java \
+  sun/nio/cs/ISCIITest.java \
+  sun/nio/cs/LatinCharReplacementTWTest.java \
+  sun/nio/cs/NIOJISAutoDetectTest.java \
+  sun/nio/cs/StreamEncoderClose.java \
+  sun/nio/cs/SurrogateGB18030Test.java \
+  sun/nio/cs/SurrogateTestEUCTW.java \
+  sun/nio/cs/SurrogateTestHKSCS.java \
+  sun/nio/cs/TestConverterDroppedCharacters.java \
+  sun/nio/cs/TestCp93xSISO.java \
+  sun/nio/cs/TestIBM1364.java \
+  sun/nio/cs/TestIBMBugs.java \
+  sun/nio/cs/TestIllegalISO2022Esc.java \
+  sun/nio/cs/TestISO2022JP.java \
+  sun/nio/cs/TestMS5022X.java \
+  sun/nio/cs/TestSJIS0213.java \
+  sun/nio/cs/TestTrailingEscapesISO2022JP.java \
+  sun/nio/cs/TestUni2HKSCS.java \
+  sun/nio/cs/ZeroedByteArrayEUCTWTest.java
+
+# Compact 3 adds further tests to compact2
+#
+compact3 = \
+  :compact2 \
+  :needs_compact3 \
+ -:needs_jre \
+ -:needs_jdk
+
+
+# Tests that require compact3 API's
+#
+needs_compact3 = \
+  :jdk_instrument \
+  :jdk_jmx \
+  :jdk_management \
+  :jdk_sctp \
+  com/sun/jndi \
+  com/sun/org/apache/xml/internal/security \
+  com/sun/security/auth \
+  com/sun/security/sasl \
+  com/sun/security/jgss \
+  com/sun/tracing \
+  java/util/prefs \
+  javax/naming \
+  javax/security \
+  javax/smartcardio \
+  javax/sql/rowset \
+  javax/xml/crypto \
+  sun/security/acl \
+  sun/security/jgss \
+  sun/security/krb5 \
+  java/lang/System/MacEncoding/TestFileEncoding.java \
+  java/nio/channels/AsynchronousSocketChannel/Leaky.java \
+  java/security/PermissionCollection/Concurrent.java \
+  java/security/Principal/Implies.java \
+  java/security/cert/GetInstance.java \
+  java/util/logging/DrainFindDeadlockTest.java \
+  java/util/logging/LoggingMXBeanTest.java \
+  sun/net/www/http/KeepAliveCache/B5045306.java \
+  sun/security/provider/PolicyFile/Alias.java \
+  sun/security/provider/PolicyFile/Comparator.java \
+  sun/security/provider/PolicyFile/SelfWildcard.java \
+  sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/SSLEngineDeadlock.java \
+  sun/security/util/Oid/OidFormat.java \
+  sun/security/util/Resources/Format.java \
+  sun/security/util/Resources/NewNamesFormat.java
+
+# Compact 2 adds full VM tests
+compact2 = \
+  :compact2_minimal \
+  :compact1 \
+  :needs_full_vm_compact2 \
+ -:needs_compact3 \
+ -:needs_jre \
+ -:needs_jdk
+
+# Tests that require compact2 API's and a full VM
+#  
+needs_full_vm_compact2 =
+
+# Minimal VM on Compact 2 adds in some compact2 tests
+#
+compact2_minimal = \
+  :compact1_minimal \
+  :needs_compact2 \
+ -:needs_compact3 \
+ -:needs_jre \
+ -:needs_jdk
+
+# Tests that require compact2 API's
+#
+needs_compact2 = \
+  :jdk_rmi \
+  :jdk_time \
+  com/sun/org/apache \
+  com/sun/net/httpserver \
+  java/sql \
+  javax/sql \
+  javax/xml \
+  jdk/lambda \
+  sun/net/www/http \
+  sun/net/www/protocol/http \
+  java/io/BufferedReader/Lines.java  \
+  java/lang/reflect/DefaultStaticTest/DefaultStaticInvokeTest.java \
+  java/lang/CharSequence/DefaultTest.java  \
+  java/lang/IntegralPrimitiveToString.java  \
+  java/lang/PrimitiveSumMinMaxTest.java  \
+  java/lang/String/StringJoinTest.java  \
+  java/lang/Thread/StopThrowable.java  \
+  java/net/Authenticator/Deadlock.java \
+  java/net/CookieHandler/LocalHostCookie.java \
+  java/net/CookieHandler/CookieManagerTest.java \
+  java/net/CookieHandler/EmptyCookieHeader.java \
+  java/net/HttpCookie/IllegalCookieNameTest.java \
+  java/net/HttpURLConnection/UnmodifiableMaps.java \
+  java/net/HttpURLPermission/URLTest.java \
+  java/net/ResponseCache/Test.java \
+  java/net/URLClassLoader/ClassLoad.java \
+  java/net/URLClassLoader/closetest/CloseTest.java \
+  java/nio/Buffer/Chars.java  \
+  java/nio/file/Files/StreamTest.java  \
+  java/security/BasicPermission/Wildcard.java \
+  java/util/Arrays/ParallelPrefix.java  \
+  java/util/Arrays/SetAllTest.java  \
+  java/util/BitSet/BitSetStreamTest.java  \
+  java/util/Collection/CollectionDefaults.java  \
+  java/util/Collection/ListDefaults.java  \
+  java/util/Collections/CheckedIdentityMap.java  \
+  java/util/Collections/CheckedMapBash.java  \
+  java/util/Collections/CheckedSetBash.java  \
+  java/util/Collections/EmptyCollectionSerialization.java  \
+  java/util/Collections/EmptyNavigableMap.java  \
+  java/util/Collections/EmptyNavigableSet.java  \
+  java/util/Collections/UnmodifiableMapEntrySet.java  \
+  java/util/Comparator/BasicTest.java  \
+  java/util/Comparator/TypeTest.java  \
+  java/util/Iterator/IteratorDefaults.java  \
+  java/util/Iterator/PrimitiveIteratorDefaults.java  \
+  java/util/Map/BasicSerialization.java  \
+  java/util/Map/Defaults.java  \
+  java/util/Map/EntryComparators.java  \
+  java/util/Optional/Basic.java  \
+  java/util/Optional/BasicDouble.java  \
+  java/util/Optional/BasicInt.java  \
+  java/util/Optional/BasicLong.java  \
+  java/util/Random/RandomStreamTest.java  \
+  java/util/ResourceBundle/Bug6359330.java  \
+  java/util/Spliterator/SpliteratorCharacteristics.java  \
+  java/util/Spliterator/SpliteratorCollisions.java  \
+  java/util/Spliterator/SpliteratorLateBindingFailFastTest.java  \
+  java/util/Spliterator/SpliteratorTraversingAndSplittingTest.java  \
+  java/util/StringJoiner/MergeTest.java  \
+  java/util/StringJoiner/StringJoinerTest.java  \
+  java/util/concurrent/atomic/AtomicReferenceTest.java  \
+  java/util/function/BinaryOperator/BasicTest.java  \
+  java/util/logging/LoggerSupplierAPIsTest.java  \
+  java/util/zip/ZipFile/StreamZipEntriesTest.java \
+  java/util/zip/ZipFile/DeleteTempJar.java \
+  javax/crypto/Cipher/CipherStreamClose.java \
+  sun/misc/URLClassPath/ClassnameCharTest.java \
+  sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/HttpsCreateSockTest.java \
+  sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/HttpsSocketFacTest.java 
+
+# Compact 1 adds full VM tests
+#
+compact1 = \
+  :compact1_minimal \
+  :needs_full_vm_compact1 \
+ -:needs_compact2 \
+ -:needs_full_vm_compact2 \
+ -:needs_compact3 \
+ -:needs_jre \
+ -:needs_jdk
+
+# Tests that require compact1 API's and a full VM
+#
+needs_full_vm_compact1 =
+
+# All tests that run on the most minimal configuration: Minimal VM on Compact 1
+compact1_minimal = \
+  com \
+  java \
+  javax \
+  jdk \
+  lib \
+  sample \
+  sun \
+  vm \
+ -:needs_full_vm_compact1 \
+ -:needs_full_vm_compact2 \
+ -:needs_compact2 \
+ -:needs_compact3 \
+ -:needs_jre \
+ -:needs_jdk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/corba/transport/KeepAliveSockets.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8017195
+ * @summary Introduce option to setKeepAlive parameter on CORBA sockets
+ *
+ * @run main/othervm KeepAliveSockets
+ * @run main/othervm -Dcom.sun.CORBA.transport.enableTcpKeepAlive KeepAliveSockets
+ * @run main/othervm -Dcom.sun.CORBA.transport.enableTcpKeepAlive=true KeepAliveSockets
+ * @run main/othervm -Dcom.sun.CORBA.transport.enableTcpKeepAlive=false KeepAliveSockets
+ */
+
+import java.lang.*;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.nio.channels.ServerSocketChannel;
+import java.util.*;
+import com.sun.corba.se.impl.orb.*;
+
+import com.sun.corba.se.impl.transport.*;
+
+public class KeepAliveSockets {
+
+    public static void main(String[] args) throws Exception {
+
+        boolean keepAlive = false;
+        String prop = System.getProperty("com.sun.CORBA.transport.enableTcpKeepAlive");
+        if (prop != null)
+            keepAlive = !"false".equalsIgnoreCase(prop);
+
+        DefaultSocketFactoryImpl sfImpl = new DefaultSocketFactoryImpl();
+        ORBImpl orb = new ORBImpl();
+        orb.set_parameters(null);
+        sfImpl.setORB(orb);
+
+        ServerSocketChannel ssc = ServerSocketChannel.open();
+        ssc.socket().bind(new InetSocketAddress(0));
+
+        InetSocketAddress isa = new InetSocketAddress("localhost", ssc.socket().getLocalPort());
+        Socket s = sfImpl.createSocket("ignore", isa);
+        System.out.println("Received factory socket" + s);
+        if (keepAlive != s.getKeepAlive())
+            throw new RuntimeException("KeepAlive value not honoured in CORBA socket");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/security/Permissions.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 8008981
+ * @summary Test that selected Toolkit and Window methods/constructors do
+ *   the appropriate permission check
+ * @run main/othervm Permissions
+ */
+
+import java.awt.AWTPermission;
+import java.awt.Frame;
+import java.awt.GraphicsConfiguration;
+import java.awt.Toolkit;
+import java.awt.Window;
+import java.util.ArrayList;
+import java.util.List;
+import java.security.Permission;
+
+public class Permissions {
+
+    static class MySecurityManager extends SecurityManager {
+        private List<Permission> permissionsChecked = new ArrayList<>();
+
+        static MySecurityManager install() {
+            MySecurityManager sm = new MySecurityManager();
+            System.setSecurityManager(sm);
+            return sm;
+        }
+
+        @Override
+        public void checkPermission(Permission perm) {
+            permissionsChecked.add(perm);
+        }
+
+        void prepare(String msg) {
+            System.out.println(msg);
+            permissionsChecked.clear();
+        }
+
+        /**
+         * Checks the security manager's checkPermission method was invoked
+         * to check the given permission and target name.
+         */
+        void assertChecked(Class<? extends Permission> type, String name) {
+            for (Permission perm: permissionsChecked) {
+                if (type.isInstance(perm) && perm.getName().equals(name))
+                    return;
+            }
+            throw new RuntimeException(type.getName() + "(\"" + name + "\") not checked");
+        }
+    }
+
+    public static void main(String[] args) {
+        MySecurityManager sm = MySecurityManager.install();
+
+        Toolkit toolkit = Toolkit.getDefaultToolkit();
+
+        sm.prepare("Toolkit.getSystemClipboard()");
+        toolkit.getSystemClipboard();
+        sm.assertChecked(AWTPermission.class, "accessClipboard");
+
+        sm.prepare("Toolkit.getSystemEventQueue()");
+        toolkit.getSystemEventQueue();
+        sm.assertChecked(AWTPermission.class, "accessEventQueue");
+
+        sm.prepare("Toolkit.getSystemSelection()");
+        toolkit.getSystemSelection();
+        //sm.assertChecked(AWTPermission.class, "accessClipboard");
+
+        sm.prepare("Window(Frame)");
+        new Window((Frame)null);
+        sm.assertChecked(AWTPermission.class, "showWindowWithoutWarningBanner");
+
+        sm.prepare("Window(Window)");
+        new Window((Window)null);
+        sm.assertChecked(AWTPermission.class, "showWindowWithoutWarningBanner");
+
+        sm.prepare("Window(Window,GraphicsConfiguration)");
+        new Window((Window)null, (GraphicsConfiguration)null);
+        sm.assertChecked(AWTPermission.class, "showWindowWithoutWarningBanner");
+    }
+}
--- a/jdk/test/java/io/File/MaxPathLength.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/io/File/MaxPathLength.java	Wed Jul 05 19:11:53 2017 +0200
@@ -22,7 +22,7 @@
  */
 
 /* @test
-   @bug 4759207 4403166 4165006 4403166 6182812 6274272
+   @bug 4759207 4403166 4165006 4403166 6182812 6274272 7160013
    @summary Test to see if win32 path length can be greater than 260
  */
 
@@ -37,6 +37,10 @@
                  "areallylongfilenamethatsforsur";
     private static boolean isWindows = false;
 
+    private final static int MAX_LENGTH = 256;
+
+    private static int counter = 0;
+
     public static void main(String[] args) throws Exception {
         String osName = System.getProperty("os.name");
         if (osName.startsWith("Windows")) {
@@ -45,33 +49,39 @@
 
         for (int i = 4; i < 7; i++) {
             String name = fileName;
-            while (name.length() < 256) {
+            while (name.length() < MAX_LENGTH) {
                 testLongPath (i, name, false);
                 testLongPath (i, name, true);
-                name += "A";
+                name = getNextName(name);
             }
         }
 
         // test long paths on windows
+        // And these long pathes cannot be handled on Solaris and Mac platforms
         if (isWindows) {
             String name = fileName;
-            while (name.length() < 256) {
+            while (name.length() < MAX_LENGTH) {
                 testLongPath (20, name, false);
                 testLongPath (20, name, true);
-                name += "A";
+                name = getNextName(name);
             }
         }
     }
 
+    private static String getNextName(String fName) {
+        return (fName.length() < MAX_LENGTH/2) ? fName + fName
+                                               : fName + "A";
+    }
+
     static void testLongPath(int max, String fn,
                              boolean tryAbsolute) throws Exception {
         String[] created = new String[max];
         String pathString = ".";
         for (int i = 0; i < max -1; i++) {
-            pathString = pathString + pathComponent;
+            pathString = pathString + pathComponent + (counter++);
             created[max - 1 -i] = pathString;
+        }
 
-        }
         File dirFile = new File(pathString);
         File f = new File(pathString + sep + fn);
 
@@ -88,9 +98,10 @@
             System.err.println("Warning: Test directory structure exists already!");
             return;
         }
-        Files.createDirectories(dirFile.toPath());
 
         try {
+            Files.createDirectories(dirFile.toPath());
+
             if (tryAbsolute)
                 dirFile = new File(dirFile.getCanonicalPath());
             if (!dirFile.isDirectory())
@@ -99,6 +110,7 @@
             if (!f.createNewFile()) {
                 throw new RuntimeException ("File.createNewFile() failed");
             }
+
             if (!f.exists())
                 throw new RuntimeException ("File.exists() failed");
             if (!f.isFile())
@@ -107,11 +119,14 @@
                 throw new RuntimeException ("File.canRead() failed");
             if (!f.canWrite())
                 throw new RuntimeException ("File.canWrite() failed");
+
             if (!f.delete())
                 throw new RuntimeException ("File.delete() failed");
+
             FileOutputStream fos = new FileOutputStream(f);
             fos.write(1);
             fos.close();
+
             if (f.length() != 1)
                 throw new RuntimeException ("File.length() failed");
             long time = System.currentTimeMillis();
@@ -148,30 +163,26 @@
                     throw new RuntimeException ("File.renameTo() failed for lenth="
                                                 + abPath.length());
                 }
-                return;
+            } else {
+                if (!nf.canRead())
+                    throw new RuntimeException ("Renamed file is not readable");
+                if (!nf.canWrite())
+                    throw new RuntimeException ("Renamed file is not writable");
+                if (nf.length() != 1)
+                    throw new RuntimeException ("Renamed file's size is not correct");
+                if (!nf.renameTo(f)) {
+                    created[0] = nf.getPath();
+                }
+                /* add a script to test these two if we got a regression later
+                if (!f.setReadOnly())
+                    throw new RuntimeException ("File.setReadOnly() failed");
+                f.deleteOnExit();
+                */
             }
-            if (!nf.canRead())
-                throw new RuntimeException ("Renamed file is not readable");
-            if (!nf.canWrite())
-                throw new RuntimeException ("Renamed file is not writable");
-            if (nf.length() != 1)
-                throw new RuntimeException ("Renamed file's size is not correct");
-            nf.renameTo(f);
-            /* add a script to test these two if we got a regression later
-            if (!f.setReadOnly())
-                throw new RuntimeException ("File.setReadOnly() failed");
-            f.deleteOnExit();
-            */
         } finally {
             // Clean up
             for (int i = 0; i < max; i++) {
-                pathString = created[i];
-                // Only works with completex canonical paths
-                File df = new File(pathString);
-                pathString = df.getCanonicalPath();
-                df = new File(pathString);
-                if (!df.delete())
-                    System.out.printf("Delete failed->%s\n", pathString);
+                Files.deleteIfExists((new File(created[i])).toPath());
             }
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/Class/ArrayMethods.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 4987375
+ * @summary make sure clone() isn't reflected and that Cloneable and
+ *          Serializable are found
+ */
+
+import java.lang.reflect.*;
+import java.util.Arrays;
+
+public class ArrayMethods {
+    public int failed = 0;
+
+    public static void main(String[] args) throws Exception {
+        ArrayMethods m = new ArrayMethods();
+
+        m.testGetMethod();
+        m.testGetMethods();
+        m.testGetDeclaredMethod();
+        m.testGetDeclaredMethods();
+        m.testGetInterfaces();
+
+        if (m.failed != 0)
+            throw new RuntimeException("Test failed, check log for details");
+    }
+
+    public void testGetMethod() {
+        try {
+            Method m = new String[0].getClass().getMethod("clone", (Class<?>[])null);
+
+            failed++;
+            System.out.println("getMethod(\"clone\", null) Should not find clone()");
+        } catch (NoSuchMethodException e) {
+            ; //all good
+        }
+    }
+
+    public void testGetMethods() {
+        Method[] m = new Integer[0][0][0].getClass().getMethods();
+        for (Method mm : m)
+            if(mm.getName().contentEquals("clone")) {
+                failed++;
+                System.out.println("getMethods() Should not find clone()");
+            }
+    }
+
+    public void testGetDeclaredMethod() {
+        try {
+            Method m = new Object[0][0].getClass().getDeclaredMethod("clone", (Class<?>[])null);
+
+            failed++;
+            System.out.println("getDeclaredMethod(\"clone\", null) Should not find clone()");
+
+        } catch (NoSuchMethodException e) {
+            ; //all good
+        }
+    }
+
+    public void testGetDeclaredMethods() {
+        Method[] m = new Throwable[0][0][0][0].getClass().getDeclaredMethods();
+        if (m.length != 0) {
+            failed++;
+            System.out.println("getDeclaredMethods().length should be 0");
+        }
+    }
+
+    public void testGetInterfaces() {
+        Class<?>[] is = new Integer[0].getClass().getInterfaces();
+        boolean thisFailed = false;
+
+        if (is.length != 2)
+            thisFailed = true;
+
+        if (!is[0].getCanonicalName().equals("java.lang.Cloneable"))
+            thisFailed = true;
+
+        if (!is[1].getCanonicalName().equals("java.io.Serializable"))
+            thisFailed = true;
+
+        if (thisFailed) {
+            failed++;
+            System.out.println(Arrays.asList(is));
+            System.out.println("Should contain exactly Cloneable, Serializable in that order.");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/Class/getField/ArrayLength.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 5047859
+ * @summary verify that for an array type class instance, getField("length")
+ *          throws an exception, and getFields() does not contain a Field for
+ *          'length'
+ */
+
+import java.lang.reflect.Field;
+
+public class ArrayLength {
+    public static void main(String [] args) {
+        int failed = 0;
+
+        try {
+            new String[0].getClass().getField("length");
+            failed++;
+            System.out.println("getField(\"length\") should throw NoSuchFieldException");
+        } catch (NoSuchFieldException e) {
+        }
+        try {
+            new String[0].getClass().getDeclaredField("length");
+            failed++;
+            System.out.println("getDeclaredField(\"length\") should throw NoSuchFieldException");
+        } catch (NoSuchFieldException e) {
+        }
+
+        if (new String[0].getClass().getFields().length != 0) {
+            failed++;
+            System.out.println("getFields() for an array type should return a zero length array");
+        }
+
+        if (new String[0].getClass().getDeclaredFields().length != 0) {
+            failed++;
+            System.out.println("getDeclaredFields() for an array type should return a zero length array");
+        }
+
+        if (failed != 0)
+            throw new RuntimeException("Test failed see log for details");
+    }
+}
--- a/jdk/test/java/lang/Math/RoundTests.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/lang/Math/RoundTests.java	Wed Jul 05 19:11:53 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 6430675
+ * @bug 6430675 8010430
  * @summary Check for correct implementation of {Math, StrictMath}.round
  */
 public class RoundTests {
@@ -32,6 +32,8 @@
 
         failures += testNearFloatHalfCases();
         failures += testNearDoubleHalfCases();
+        failures += testUnityULPCases();
+        failures += testSpecialCases();
 
         if (failures > 0) {
             System.err.println("Testing {Math, StrictMath}.round incurred "
@@ -95,4 +97,69 @@
 
         return failures;
     }
+
+    private static int testUnityULPCases() {
+        int failures = 0;
+        for (float sign : new float[]{-1, 1}) {
+            for (float v1 : new float[]{1 << 23, 1 << 24}) {
+                for (int k = -5; k <= 5; k++) {
+                    float value = (v1 + k) * sign;
+                    float actual = Math.round(value);
+                    failures += Tests.test("Math.round", value, actual, value);
+                }
+            }
+        }
+
+        if (failures != 0) {
+            System.out.println();
+        }
+
+        for (double sign : new double[]{-1, 1}) {
+            for (double v1 : new double[]{1L << 52, 1L << 53}) {
+                for (int k = -5; k <= 5; k++) {
+                    double value = (v1 + k) * sign;
+                    double actual = Math.round(value);
+                    failures += Tests.test("Math.round", value, actual, value);
+                }
+            }
+        }
+
+        return failures;
+    }
+
+    private static int testSpecialCases() {
+        int failures = 0;
+
+        failures += Tests.test("Math.round", Float.NaN, Math.round(Float.NaN), 0.0F);
+        failures += Tests.test("Math.round", Float.POSITIVE_INFINITY,
+                Math.round(Float.POSITIVE_INFINITY), Integer.MAX_VALUE);
+        failures += Tests.test("Math.round", Float.NEGATIVE_INFINITY,
+                Math.round(Float.NEGATIVE_INFINITY), Integer.MIN_VALUE);
+        failures += Tests.test("Math.round", -(float)Integer.MIN_VALUE,
+                Math.round(-(float)Integer.MIN_VALUE), Integer.MAX_VALUE);
+        failures += Tests.test("Math.round", (float) Integer.MIN_VALUE,
+                Math.round((float) Integer.MIN_VALUE), Integer.MIN_VALUE);
+        failures += Tests.test("Math.round", 0F, Math.round(0F), 0.0F);
+        failures += Tests.test("Math.round", Float.MIN_VALUE,
+                Math.round(Float.MIN_VALUE), 0.0F);
+        failures += Tests.test("Math.round", -Float.MIN_VALUE,
+                Math.round(-Float.MIN_VALUE), 0.0F);
+
+        failures += Tests.test("Math.round", Double.NaN, Math.round(Double.NaN), 0.0);
+        failures += Tests.test("Math.round", Double.POSITIVE_INFINITY,
+                Math.round(Double.POSITIVE_INFINITY), Long.MAX_VALUE);
+        failures += Tests.test("Math.round", Double.NEGATIVE_INFINITY,
+                Math.round(Double.NEGATIVE_INFINITY), Long.MIN_VALUE);
+        failures += Tests.test("Math.round", -(double)Long.MIN_VALUE,
+                Math.round(-(double)Long.MIN_VALUE), Long.MAX_VALUE);
+        failures += Tests.test("Math.round", (double) Long.MIN_VALUE,
+                Math.round((double) Long.MIN_VALUE), Long.MIN_VALUE);
+        failures += Tests.test("Math.round", 0, Math.round(0), 0.0);
+        failures += Tests.test("Math.round", Double.MIN_VALUE,
+                Math.round(Double.MIN_VALUE), 0.0);
+        failures += Tests.test("Math.round", -Double.MIN_VALUE,
+                Math.round(-Double.MIN_VALUE), 0.0);
+
+        return failures;
+    }
 }
--- a/jdk/test/java/lang/invoke/7087570/Test7087570.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/lang/invoke/7087570/Test7087570.java	Wed Jul 05 19:11:53 2017 +0200
@@ -35,20 +35,9 @@
 
 import static java.lang.invoke.MethodHandles.*;
 import static java.lang.invoke.MethodType.*;
+import static java.lang.invoke.MethodHandleInfo.*;
 
 public class Test7087570 {
-    // XXX may remove the following constant declarations when MethodHandleInfo is made public
-    private static final int
-            REF_getField                = 1,
-            REF_getStatic               = 2,
-            REF_putField                = 3,
-            REF_putStatic               = 4,
-            REF_invokeVirtual           = 5,
-            REF_invokeStatic            = 6,
-            REF_invokeSpecial           = 7,
-            REF_newInvokeSpecial        = 8,
-            REF_invokeInterface         = 9,
-            REF_LIMIT                  = 10;
 
     private static final TestMethodData[] TESTS = new TestMethodData[] {
         // field accessors
@@ -87,17 +76,17 @@
     }
 
     private static void doTest(MethodHandle mh, TestMethodData testMethod) {
-        Object mhi = newMethodHandleInfo(mh);
+        MethodHandleInfo mhi = LOOKUP.revealDirect(mh);
 
         System.out.printf("%s.%s: %s, nominal refKind: %s, actual refKind: %s\n",
                           testMethod.clazz.getName(), testMethod.name, testMethod.methodType,
-                          REF_KIND_NAMES[testMethod.referenceKind],
-                          REF_KIND_NAMES[getReferenceKind(mhi)]);
-        assertEquals(testMethod.name,           getName(mhi));
-        assertEquals(testMethod.methodType,     getMethodType(mhi));
-        assertEquals(testMethod.declaringClass, getDeclaringClass(mhi));
+                          referenceKindToString(testMethod.referenceKind),
+                          referenceKindToString(mhi.getReferenceKind()));
+        assertEquals(testMethod.name,           mhi.getName());
+        assertEquals(testMethod.methodType,     mhi.getMethodType());
+        assertEquals(testMethod.declaringClass, mhi.getDeclaringClass());
         assertEquals(testMethod.referenceKind == REF_invokeSpecial, isInvokeSpecial(mh));
-        assertRefKindEquals(testMethod.referenceKind,  getReferenceKind(mhi));
+        assertRefKindEquals(testMethod.referenceKind,  mhi.getReferenceKind());
     }
 
     private static void testWithLookup() throws Throwable {
@@ -122,50 +111,8 @@
         return methodType(void.class, clazz);
     }
 
-    private static final String[] REF_KIND_NAMES = {
-        "MH::invokeBasic",
-        "REF_getField", "REF_getStatic", "REF_putField", "REF_putStatic",
-        "REF_invokeVirtual", "REF_invokeStatic", "REF_invokeSpecial",
-        "REF_newInvokeSpecial", "REF_invokeInterface"
-    };
-
     private static final Lookup LOOKUP = lookup();
 
-    // XXX may remove the following reflective logic when MethodHandleInfo is made public
-    private static final MethodHandle MH_IS_INVOKESPECIAL;
-    private static final MethodHandle MHI_CONSTRUCTOR;
-    private static final MethodHandle MHI_GET_NAME;
-    private static final MethodHandle MHI_GET_METHOD_TYPE;
-    private static final MethodHandle MHI_GET_DECLARING_CLASS;
-    private static final MethodHandle MHI_GET_REFERENCE_KIND;
-
-    static {
-        try {
-            // This is white box testing.  Use reflection to grab private implementation bits.
-            String magicName = "IMPL_LOOKUP";
-            Field magicLookup = MethodHandles.Lookup.class.getDeclaredField(magicName);
-            // This unit test will fail if a security manager is installed.
-            magicLookup.setAccessible(true);
-            // Forbidden fruit...
-            Lookup directInvokeLookup = (Lookup) magicLookup.get(null);
-            Class<?> mhiClass = Class.forName("java.lang.invoke.MethodHandleInfo", false, MethodHandle.class.getClassLoader());
-            MH_IS_INVOKESPECIAL = directInvokeLookup
-                    .findVirtual(MethodHandle.class, "isInvokeSpecial", methodType(boolean.class));
-            MHI_CONSTRUCTOR = directInvokeLookup
-                    .findConstructor(mhiClass, methodType(void.class, MethodHandle.class));
-            MHI_GET_NAME = directInvokeLookup
-                    .findVirtual(mhiClass, "getName", methodType(String.class));
-            MHI_GET_METHOD_TYPE = directInvokeLookup
-                    .findVirtual(mhiClass, "getMethodType", methodType(MethodType.class));
-            MHI_GET_DECLARING_CLASS = directInvokeLookup
-                    .findVirtual(mhiClass, "getDeclaringClass", methodType(Class.class));
-            MHI_GET_REFERENCE_KIND = directInvokeLookup
-                    .findVirtual(mhiClass, "getReferenceKind", methodType(int.class));
-        } catch (ReflectiveOperationException ex) {
-            throw new Error(ex);
-        }
-    }
-
     private static class TestMethodData {
         final Class<?> clazz;
         final String name;
@@ -208,7 +155,9 @@
             return LOOKUP.findStatic(testMethod.clazz, testMethod.name, testMethod.methodType);
         case REF_invokeSpecial:
             Class<?> thisClass = LOOKUP.lookupClass();
-            return LOOKUP.findSpecial(testMethod.clazz, testMethod.name, testMethod.methodType, thisClass);
+            MethodHandle smh = LOOKUP.findSpecial(testMethod.clazz, testMethod.name, testMethod.methodType, thisClass);
+            noteInvokeSpecial(smh);
+            return smh;
         case REF_newInvokeSpecial:
             return LOOKUP.findConstructor(testMethod.clazz, testMethod.methodType);
         default:
@@ -238,7 +187,9 @@
         case REF_invokeSpecial: {
                 Method m = testMethod.clazz.getDeclaredMethod(testMethod.name, testMethod.methodType.parameterArray());
                 Class<?> thisClass = LOOKUP.lookupClass();
-                return LOOKUP.unreflectSpecial(m, thisClass);
+                MethodHandle smh = LOOKUP.unreflectSpecial(m, thisClass);
+                noteInvokeSpecial(smh);
+                return smh;
             }
         case REF_newInvokeSpecial: {
                 Constructor c = testMethod.clazz.getDeclaredConstructor(testMethod.methodType.parameterArray());
@@ -249,59 +200,20 @@
         }
     }
 
-    private static Object newMethodHandleInfo(MethodHandle mh) {
-        try {
-            return MHI_CONSTRUCTOR.invoke(mh);
-        } catch (Throwable ex) {
-            throw new Error(ex);
-        }
-    }
-
-    private static boolean isInvokeSpecial(MethodHandle mh) {
-        try {
-            return (boolean) MH_IS_INVOKESPECIAL.invokeExact(mh);
-        } catch (Throwable ex) {
-            throw new Error(ex);
-        }
-    }
-
-    private static String getName(Object mhi) {
-        try {
-            return (String) MHI_GET_NAME.invoke(mhi);
-        } catch (Throwable ex) {
-            throw new Error(ex);
-        }
+    private static List<MethodHandle> specialMethodHandles = new ArrayList<>();
+    private static void noteInvokeSpecial(MethodHandle mh) {
+        specialMethodHandles.add(mh);
+        assert(isInvokeSpecial(mh));
     }
-
-    private static MethodType getMethodType(Object mhi) {
-        try {
-            return (MethodType) MHI_GET_METHOD_TYPE.invoke(mhi);
-        } catch (Throwable ex) {
-            throw new Error(ex);
-        }
-    }
-
-    private static Class<?> getDeclaringClass(Object mhi) {
-        try {
-            return (Class<?>) MHI_GET_DECLARING_CLASS.invoke(mhi);
-        } catch (Throwable ex) {
-            throw new Error(ex);
-        }
-    }
-
-    private static int getReferenceKind(Object mhi) {
-        try {
-            return (int) MHI_GET_REFERENCE_KIND.invoke(mhi);
-        } catch (Throwable ex) {
-            throw new Error(ex);
-        }
+    private static boolean isInvokeSpecial(MethodHandle mh) {
+        return specialMethodHandles.contains(mh);
     }
 
     private static void assertRefKindEquals(int expect, int observed) {
         if (expect == observed) return;
 
-        String msg = "expected " + REF_KIND_NAMES[(int) expect] +
-                     " but observed " + REF_KIND_NAMES[(int) observed];
+        String msg = "expected " + referenceKindToString(expect) +
+                     " but observed " + referenceKindToString(observed);
         System.out.println("FAILED: " + msg);
         throw new AssertionError(msg);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/RevealDirectTest.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,753 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary verify Lookup.revealDirect on a variety of input handles
+ * @compile -XDignore.symbol.file RevealDirectTest.java
+ * @run junit/othervm -ea -esa test.java.lang.invoke.RevealDirectTest
+ *
+ * @test
+ * @summary verify Lookup.revealDirect on a variety of input handles, with security manager
+ * @run main/othervm/policy=jtreg.security.policy/secure=java.lang.SecurityManager -ea -esa test.java.lang.invoke.RevealDirectTest
+ */
+
+/* To run manually:
+ * $ $JAVA8X_HOME/bin/javac -cp $JUNIT4_JAR -d ../../../.. -XDignore.symbol.file RevealDirectTest.java
+ * $ $JAVA8X_HOME/bin/java  -cp $JUNIT4_JAR:../../../.. -ea -esa org.junit.runner.JUnitCore test.java.lang.invoke.RevealDirectTest
+ * $ $JAVA8X_HOME/bin/java  -cp $JUNIT4_JAR:../../../.. -ea -esa    -Djava.security.manager test.java.lang.invoke.RevealDirectTest
+ */
+
+package test.java.lang.invoke;
+
+import java.lang.reflect.*;
+import java.lang.invoke.*;
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodType.*;
+import static java.lang.invoke.MethodHandleInfo.*;
+import java.util.*;
+import static org.junit.Assert.*;
+import org.junit.*;
+
+public class RevealDirectTest {
+    public static void main(String... av) throws Throwable {
+        // Run the @Test methods explicitly, in case we don't want to use the JUnitCore driver.
+        // This appears to be necessary when running with a security manager.
+        Throwable fail = null;
+        for (Method test : RevealDirectTest.class.getDeclaredMethods()) {
+            if (!test.isAnnotationPresent(Test.class))  continue;
+            try {
+                test.invoke(new RevealDirectTest());
+            } catch (Throwable ex) {
+                if (ex instanceof InvocationTargetException)
+                    ex = ex.getCause();
+                if (fail == null)  fail = ex;
+                System.out.println("Testcase: "+test.getName()
+                                   +"("+test.getDeclaringClass().getName()
+                                   +"):\tCaused an ERROR");
+                System.out.println(ex);
+                ex.printStackTrace(System.out);
+            }
+        }
+        if (fail != null)  throw fail;
+    }
+
+    public interface SimpleSuperInterface {
+        public abstract int getInt();
+        public static void printAll(String... args) {
+            System.out.println(Arrays.toString(args));
+        }
+        public int NICE_CONSTANT = 42;
+    }
+    public interface SimpleInterface extends SimpleSuperInterface {
+        default float getFloat() { return getInt(); }
+        public static void printAll(String[] args) {
+            System.out.println(Arrays.toString(args));
+        }
+    }
+    public static class Simple implements SimpleInterface, Cloneable {
+        public int intField;
+        public final int finalField;
+        private static String stringField;
+        public int getInt() { return NICE_CONSTANT; }
+        private static Number getNum() { return 804; }
+        public Simple clone() {
+            try {
+                return (Simple) super.clone();
+            } catch (CloneNotSupportedException ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+        Simple() { finalField = -NICE_CONSTANT; }
+        private static Lookup localLookup() { return lookup(); }
+        private static List<Member> members() { return getMembers(lookup().lookupClass()); };
+    }
+
+    static boolean VERBOSE = false;
+
+    @Test public void testSimple() throws Throwable {
+        if (VERBOSE)  System.out.println("@Test testSimple");
+        testOnMembers("testSimple", Simple.members(), Simple.localLookup());
+    }
+    @Test public void testPublicLookup() throws Throwable {
+        if (VERBOSE)  System.out.println("@Test testPublicLookup");
+        List<Member> mems = publicOnly(Simple.members());
+        Lookup pubLookup = publicLookup(), privLookup = Simple.localLookup();
+        testOnMembers("testPublicLookup/1", mems, pubLookup);
+        // reveal using publicLookup:
+        testOnMembers("testPublicLookup/2", mems, privLookup, pubLookup);
+        // lookup using publicLookup, but reveal using private:
+        testOnMembers("testPublicLookup/3", mems, pubLookup, privLookup);
+    }
+    @Test public void testPublicLookupNegative() throws Throwable {
+        if (VERBOSE)  System.out.println("@Test testPublicLookupNegative");
+        List<Member> mems = nonPublicOnly(Simple.members());
+        Lookup pubLookup = publicLookup(), privLookup = Simple.localLookup();
+        testOnMembersNoLookup("testPublicLookupNegative/1", mems, pubLookup);
+        testOnMembersNoReveal("testPublicLookupNegative/2", mems, privLookup, pubLookup);
+        testOnMembersNoReflect("testPublicLookupNegative/3", mems, privLookup, pubLookup);
+    }
+    @Test public void testJavaLangClass() throws Throwable {
+        if (VERBOSE)  System.out.println("@Test testJavaLangClass");
+        List<Member> mems = callerSensitive(false, publicOnly(getMembers(Class.class)));
+        mems = limit(20, mems);
+        testOnMembers("testJavaLangClass", mems, Simple.localLookup());
+    }
+    @Test public void testCallerSensitive() throws Throwable {
+        if (VERBOSE)  System.out.println("@Test testCallerSensitive");
+        List<Member> mems = union(getMembers(MethodHandles.class, "lookup"),
+                                  getMembers(Method.class, "invoke"),
+                                  getMembers(Field.class, "get", "set", "getLong"),
+                                  getMembers(Class.class));
+        mems = callerSensitive(true, publicOnly(mems));
+        mems = limit(10, mems);
+        testOnMembers("testCallerSensitive", mems, Simple.localLookup());
+    }
+    @Test public void testCallerSensitiveNegative() throws Throwable {
+        if (VERBOSE)  System.out.println("@Test testCallerSensitiveNegative");
+        List<Member> mems = union(getMembers(MethodHandles.class, "lookup"),
+                                  getMembers(Class.class, "forName"),
+                                  getMembers(Method.class, "invoke"));
+        mems = callerSensitive(true, publicOnly(mems));
+        // CS methods cannot be looked up with publicLookup
+        testOnMembersNoLookup("testCallerSensitiveNegative", mems, publicLookup());
+    }
+    @Test public void testMethodHandleNatives() throws Throwable {
+        if (VERBOSE)  System.out.println("@Test testMethodHandleNatives");
+        List<Member> mems = getMembers(MethodHandle.class, "invoke", "invokeExact");
+        testOnMembers("testMethodHandleNatives", mems, Simple.localLookup());
+    }
+    @Test public void testMethodHandleInvokes() throws Throwable {
+        if (VERBOSE)  System.out.println("@Test testMethodHandleInvokes");
+        List<MethodType> types = new ArrayList<>();
+        Class<?>[] someParamTypes = { void.class, int.class, Object.class, Object[].class };
+        for (Class<?> rt : someParamTypes) {
+            for (Class<?> p0 : someParamTypes) {
+                if (p0 == void.class) { types.add(methodType(rt)); continue; }
+                for (Class<?> p1 : someParamTypes) {
+                    if (p1 == void.class) { types.add(methodType(rt, p0)); continue; }
+                    for (Class<?> p2 : someParamTypes) {
+                        if (p2 == void.class) { types.add(methodType(rt, p0, p1)); continue; }
+                        types.add(methodType(rt, p0, p1, p2));
+                    }
+                }
+            }
+        }
+        List<Member> mems = union(getPolyMembers(MethodHandle.class, "invoke", types),
+                                  getPolyMembers(MethodHandle.class, "invokeExact", types));
+        testOnMembers("testMethodHandleInvokes/1", mems, Simple.localLookup());
+        testOnMembers("testMethodHandleInvokes/2", mems, publicLookup());
+    }
+
+    static List<Member> getPolyMembers(Class<?> cls, String name, List<MethodType> types) {
+        assert(cls == MethodHandle.class);
+        ArrayList<Member> mems = new ArrayList<>();
+        for (MethodType type : types) {
+            mems.add(new SignaturePolymorphicMethod(name, type));
+        }
+        return mems;
+    }
+    static List<Member> getMembers(Class<?> cls) {
+        return getMembers(cls, (String[]) null);
+    }
+    static List<Member> getMembers(Class<?> cls, String... onlyNames) {
+        List<String> names = (onlyNames == null || onlyNames.length == 0 ? null : Arrays.asList(onlyNames));
+        ArrayList<Member> res = new ArrayList<>();
+        for (Class<?> sup : getSupers(cls)) {
+            res.addAll(getDeclaredMembers(sup, "getDeclaredFields"));
+            res.addAll(getDeclaredMembers(sup, "getDeclaredMethods"));
+            res.addAll(getDeclaredMembers(sup, "getDeclaredConstructors"));
+        }
+        res = new ArrayList<>(new LinkedHashSet<>(res));
+        for (int i = 0; i < res.size(); i++) {
+            Member mem = res.get(i);
+            if (!canBeReached(mem, cls) ||
+                res.indexOf(mem) != i ||
+                mem.isSynthetic() ||
+                (names != null && !names.contains(mem.getName()))
+                ) {
+                res.remove(i--);
+            }
+        }
+        return res;
+    }
+    static List<Class<?>> getSupers(Class<?> cls) {
+        ArrayList<Class<?>> res = new ArrayList<>();
+        ArrayList<Class<?>> intfs = new ArrayList<>();
+        for (Class<?> sup = cls; sup != null; sup = sup.getSuperclass()) {
+            res.add(sup);
+            for (Class<?> intf : cls.getInterfaces()) {
+                if (!intfs.contains(intf))
+                    intfs.add(intf);
+            }
+        }
+        for (int i = 0; i < intfs.size(); i++) {
+            for (Class<?> intf : intfs.get(i).getInterfaces()) {
+                if (!intfs.contains(intf))
+                    intfs.add(intf);
+            }
+        }
+        res.addAll(intfs);
+        //System.out.println("getSupers => "+res);
+        return res;
+    }
+    static boolean hasSM() {
+        return (System.getSecurityManager() != null);
+    }
+    static List<Member> getDeclaredMembers(Class<?> cls, String accessor) {
+        Member[] mems = {};
+        Method getter = getMethod(Class.class, accessor);
+        if (hasSM()) {
+            try {
+                mems = (Member[]) invokeMethod(getter, cls);
+            } catch (SecurityException ex) {
+                //if (VERBOSE)  ex.printStackTrace();
+                accessor = accessor.replace("Declared", "");
+                getter = getMethod(Class.class, accessor);
+                if (VERBOSE)  System.out.println("replaced accessor: "+getter);
+            }
+        }
+        if (mems.length == 0) {
+            try {
+                mems = (Member[]) invokeMethod(getter, cls);
+            } catch (SecurityException ex) {
+                ex.printStackTrace();
+            }
+        }
+        if (VERBOSE)  System.out.println(accessor+" "+cls.getName()+" => "+mems.length+" members");
+        return Arrays.asList(mems);
+    }
+    static Method getMethod(Class<?> cls, String name) {
+        try {
+            return cls.getMethod(name);
+        } catch (ReflectiveOperationException ex) {
+            throw new AssertionError(ex);
+        }
+    }
+    static Object invokeMethod(Method m, Object recv, Object... args) {
+        try {
+            return m.invoke(recv, args);
+        } catch (InvocationTargetException ex) {
+            Throwable ex2 = ex.getCause();
+            if (ex2 instanceof RuntimeException)  throw (RuntimeException) ex2;
+            if (ex2 instanceof Error)  throw (Error) ex2;
+            throw new AssertionError(ex);
+        } catch (ReflectiveOperationException ex) {
+            throw new AssertionError(ex);
+        }
+    }
+
+    static List<Member> limit(int len, List<Member> mems) {
+        if (mems.size() <= len)  return mems;
+        return mems.subList(0, len);
+    }
+    @SafeVarargs
+    static List<Member> union(List<Member> mems, List<Member>... mem2s) {
+        for (List<Member> mem2 : mem2s) {
+            for (Member m : mem2) {
+                if (!mems.contains(m))
+                    mems.add(m);
+            }
+        }
+        return mems;
+    }
+    static List<Member> callerSensitive(boolean cond, List<Member> members) {
+        for (Iterator<Member> i = members.iterator(); i.hasNext(); ) {
+            Member mem = i.next();
+            if (isCallerSensitive(mem) != cond)
+                i.remove();
+        }
+        if (members.isEmpty())  throw new AssertionError("trivial result");
+        return members;
+    }
+    static boolean isCallerSensitive(Member mem) {
+        if (!(mem instanceof AnnotatedElement))  return false;
+        AnnotatedElement ae = (AnnotatedElement) mem;
+        if (CS_CLASS != null)
+            return ae.isAnnotationPresent(sun.reflect.CallerSensitive.class);
+        for (java.lang.annotation.Annotation a : ae.getDeclaredAnnotations()) {
+            if (a.toString().contains(".CallerSensitive"))
+                return true;
+        }
+        return false;
+    }
+    static final Class<?> CS_CLASS;
+    static {
+        Class<?> c = null;
+        try {
+            c = sun.reflect.CallerSensitive.class;
+        } catch (SecurityException | LinkageError ex) {
+        }
+        CS_CLASS = c;
+    }
+    static List<Member> publicOnly(List<Member> members) {
+        return removeMods(members, Modifier.PUBLIC, 0);
+    }
+    static List<Member> nonPublicOnly(List<Member> members) {
+        return removeMods(members, Modifier.PUBLIC, -1);
+    }
+    static List<Member> removeMods(List<Member> members, int mask, int bits) {
+        int publicMods = (mask & Modifier.PUBLIC);
+        members = new ArrayList<>(members);
+        for (Iterator<Member> i = members.iterator(); i.hasNext(); ) {
+            Member mem = i.next();
+            int mods = mem.getModifiers();
+            if ((publicMods & mods) != 0 &&
+                (publicMods & mem.getDeclaringClass().getModifiers()) == 0)
+                mods -= publicMods;
+            if ((mods & mask) == (bits & mask))
+                i.remove();
+        }
+        return members;
+    }
+
+    void testOnMembers(String tname, List<Member> mems, Lookup lookup, Lookup... lookups) throws Throwable {
+        if (VERBOSE)  System.out.println("testOnMembers "+mems);
+        Lookup revLookup = (lookups.length > 0) ? lookups[0] : null;
+        if (revLookup == null)  revLookup = lookup;
+        Lookup refLookup = (lookups.length > 1) ? lookups[1] : null;
+        if (refLookup == null)  refLookup = lookup;
+        assert(lookups.length <= 2);
+        testOnMembersImpl(tname, mems, lookup, revLookup, refLookup, NO_FAIL);
+    }
+    void testOnMembersNoLookup(String tname, List<Member> mems, Lookup lookup) throws Throwable {
+        if (VERBOSE)  System.out.println("testOnMembersNoLookup "+mems);
+        testOnMembersImpl(tname, mems, lookup, null, null, FAIL_LOOKUP);
+    }
+    void testOnMembersNoReveal(String tname, List<Member> mems,
+                               Lookup lookup, Lookup negLookup) throws Throwable {
+        if (VERBOSE)  System.out.println("testOnMembersNoReveal "+mems);
+        testOnMembersImpl(tname, mems, lookup, negLookup, null, FAIL_REVEAL);
+    }
+    void testOnMembersNoReflect(String tname, List<Member> mems,
+                                Lookup lookup, Lookup negLookup) throws Throwable {
+        if (VERBOSE)  System.out.println("testOnMembersNoReflect "+mems);
+        testOnMembersImpl(tname, mems, lookup, lookup, negLookup, FAIL_REFLECT);
+    }
+    void testOnMembersImpl(String tname, List<Member> mems,
+                           Lookup lookup,
+                           Lookup revLookup,
+                           Lookup refLookup,
+                           int failureMode) throws Throwable {
+        Throwable fail = null;
+        int failCount = 0;
+        failureModeCounts = new int[FAIL_MODE_COUNT];
+        long tm0 = System.currentTimeMillis();
+        for (Member mem : mems) {
+            try {
+                testWithMember(mem, lookup, revLookup, refLookup, failureMode);
+            } catch (Throwable ex) {
+                if (fail == null)  fail = ex;
+                if (++failCount > 10) { System.out.println("*** FAIL: too many failures"); break; }
+                System.out.println("*** FAIL: "+mem+" => "+ex);
+                if (VERBOSE)  ex.printStackTrace(System.out);
+            }
+        }
+        long tm1 = System.currentTimeMillis();
+        System.out.printf("@Test %s executed %s tests in %d ms",
+                          tname, testKinds(failureModeCounts), (tm1-tm0)).println();
+        if (fail != null)  throw fail;
+    }
+    static String testKinds(int[] modes) {
+        int pos = modes[0], neg = -pos;
+        for (int n : modes)  neg += n;
+        if (neg == 0)  return pos + " positive";
+        String negs = "";
+        for (int n : modes)  negs += "/"+n;
+        negs = negs.replaceFirst("/"+pos+"/", "");
+        negs += " negative";
+        if (pos == 0)  return negs;
+        return pos + " positive, " + negs;
+    }
+    static class SignaturePolymorphicMethod implements Member {  // non-reflected instance of MH.invoke*
+        final String name;
+        final MethodType type;
+        SignaturePolymorphicMethod(String name, MethodType type) {
+            this.name = name;
+            this.type = type;
+        }
+        public String toString() {
+            String typeStr = type.toString();
+            if (isVarArgs())  typeStr = typeStr.replaceFirst("\\[\\])$", "...)");
+            return (Modifier.toString(getModifiers())
+                    +typeStr.substring(0, typeStr.indexOf('('))+" "
+                    +getDeclaringClass().getTypeName()+"."
+                    +getName()+typeStr.substring(typeStr.indexOf('(')));
+        }
+        public boolean equals(Object x) {
+            return (x instanceof SignaturePolymorphicMethod && equals((SignaturePolymorphicMethod)x));
+        }
+        public boolean equals(SignaturePolymorphicMethod that) {
+            return this.name.equals(that.name) && this.type.equals(that.type);
+        }
+        public int hashCode() {
+            return name.hashCode() * 31 + type.hashCode();
+        }
+        public Class<?> getDeclaringClass() { return MethodHandle.class; }
+        public String getName() { return name; }
+        public MethodType getMethodType() { return type; }
+        public int getModifiers() { return Modifier.PUBLIC | Modifier.FINAL | Modifier.NATIVE | SYNTHETIC; }
+        public boolean isVarArgs() { return Modifier.isTransient(getModifiers()); }
+        public boolean isSynthetic() { return true; }
+        public Class<?> getReturnType() { return type.returnType(); }
+        public Class<?>[] getParameterTypes() { return type.parameterArray(); }
+        static final int SYNTHETIC = 0x00001000;
+    }
+    static class UnreflectResult {  // a tuple
+        final MethodHandle mh;
+        final Throwable ex;
+        final byte kind;
+        final Member mem;
+        final int var;
+        UnreflectResult(MethodHandle mh, byte kind, Member mem, int var) {
+            this.mh = mh;
+            this.ex = null;
+            this.kind = kind;
+            this.mem = mem;
+            this.var = var;
+        }
+        UnreflectResult(Throwable ex, byte kind, Member mem, int var) {
+            this.mh = null;
+            this.ex = ex;
+            this.kind = kind;
+            this.mem = mem;
+            this.var = var;
+        }
+        public String toString() {
+            return toInfoString()+"/v"+var;
+        }
+        public String toInfoString() {
+            return String.format("%s %s.%s:%s", MethodHandleInfo.referenceKindToString(kind),
+                                 mem.getDeclaringClass().getName(), name(mem), type(mem, kind));
+        }
+        static String name(Member mem) {
+            if (mem instanceof Constructor)  return "<init>";
+            return mem.getName();
+        }
+        static MethodType type(Member mem, byte kind) {
+            if (mem instanceof Field) {
+                Class<?> type = ((Field)mem).getType();
+                if (kind == REF_putStatic || kind == REF_putField)
+                    return methodType(void.class, type);
+                return methodType(type);
+            } else if (mem instanceof SignaturePolymorphicMethod) {
+                return ((SignaturePolymorphicMethod)mem).getMethodType();
+            }
+            Class<?>[] params = ((Executable)mem).getParameterTypes();
+            if (mem instanceof Constructor)
+                return methodType(void.class, params);
+            Class<?> type = ((Method)mem).getReturnType();
+            return methodType(type, params);
+        }
+    }
+    static UnreflectResult unreflectMember(Lookup lookup, Member mem, int variation) {
+        byte[] refKind = {0};
+        try {
+            return unreflectMemberOrThrow(lookup, mem, variation, refKind);
+        } catch (ReflectiveOperationException|SecurityException ex) {
+            return new UnreflectResult(ex, refKind[0], mem, variation);
+        }
+    }
+    static UnreflectResult unreflectMemberOrThrow(Lookup lookup, Member mem, int variation,
+                                                  byte[] refKind) throws ReflectiveOperationException {
+        Class<?> cls = lookup.lookupClass();
+        Class<?> defc = mem.getDeclaringClass();
+        String   name = mem.getName();
+        int      mods = mem.getModifiers();
+        boolean isStatic = Modifier.isStatic(mods);
+        MethodHandle mh = null;
+        byte kind = 0;
+        if (mem instanceof Method) {
+            Method m = (Method) mem;
+            MethodType type = methodType(m.getReturnType(), m.getParameterTypes());
+            boolean canBeSpecial = (!isStatic &&
+                                    (lookup.lookupModes() & Modifier.PRIVATE) != 0 &&
+                                    defc.isAssignableFrom(cls) &&
+                                    (!defc.isInterface() || Arrays.asList(cls.getInterfaces()).contains(defc)));
+            if (variation >= 2)
+                kind = REF_invokeSpecial;
+            else if (isStatic)
+                kind = REF_invokeStatic;
+            else if (defc.isInterface())
+                kind = REF_invokeInterface;
+            else
+                kind = REF_invokeVirtual;
+            refKind[0] = kind;
+            switch (variation) {
+            case 0:
+                mh = lookup.unreflect(m);
+                break;
+            case 1:
+                if (defc == MethodHandle.class &&
+                    !isStatic &&
+                    m.isVarArgs() &&
+                    Modifier.isFinal(mods) &&
+                    Modifier.isNative(mods)) {
+                    break;
+                }
+                if (isStatic)
+                    mh = lookup.findStatic(defc, name, type);
+                else
+                    mh = lookup.findVirtual(defc, name, type);
+                break;
+            case 2:
+                if (!canBeSpecial)
+                    break;
+                mh = lookup.unreflectSpecial(m, lookup.lookupClass());
+                break;
+            case 3:
+                if (!canBeSpecial)
+                    break;
+                mh = lookup.findSpecial(defc, name, type, lookup.lookupClass());
+                break;
+            }
+        } else if (mem instanceof SignaturePolymorphicMethod) {
+            SignaturePolymorphicMethod m = (SignaturePolymorphicMethod) mem;
+            MethodType type = methodType(m.getReturnType(), m.getParameterTypes());
+            kind = REF_invokeVirtual;
+            refKind[0] = kind;
+            switch (variation) {
+            case 0:
+                mh = lookup.findVirtual(defc, name, type);
+                break;
+            }
+        } else if (mem instanceof Constructor) {
+            name = "<init>";  // not used
+            Constructor<?> m = (Constructor<?>) mem;
+            MethodType type = methodType(void.class, m.getParameterTypes());
+            kind = REF_newInvokeSpecial;
+            refKind[0] = kind;
+            switch (variation) {
+            case 0:
+                mh = lookup.unreflectConstructor(m);
+                break;
+            case 1:
+                mh = lookup.findConstructor(defc, type);
+                break;
+            }
+        } else if (mem instanceof Field) {
+            Field m = (Field) mem;
+            Class<?> type = m.getType();
+            boolean canHaveSetter = !Modifier.isFinal(mods);
+            if (variation >= 2)
+                kind = (byte)(isStatic ? REF_putStatic : REF_putField);
+            else
+                kind = (byte)(isStatic ? REF_getStatic : REF_getField);
+            refKind[0] = kind;
+            switch (variation) {
+            case 0:
+                mh = lookup.unreflectGetter(m);
+                break;
+            case 1:
+                if (isStatic)
+                    mh = lookup.findStaticGetter(defc, name, type);
+                else
+                    mh = lookup.findGetter(defc, name, type);
+                break;
+            case 3:
+                if (!canHaveSetter)
+                    break;
+                mh = lookup.unreflectSetter(m);
+                break;
+            case 2:
+                if (!canHaveSetter)
+                    break;
+                if (isStatic)
+                    mh = lookup.findStaticSetter(defc, name, type);
+                else
+                    mh = lookup.findSetter(defc, name, type);
+                break;
+            }
+        } else {
+            throw new IllegalArgumentException(String.valueOf(mem));
+        }
+        if (mh == null)
+            // ran out of valid variations; return null to caller
+            return null;
+        return new UnreflectResult(mh, kind, mem, variation);
+    }
+    static boolean canBeReached(Member mem, Class<?> cls) {
+        Class<?> defc = mem.getDeclaringClass();
+        String   name = mem.getName();
+        int      mods = mem.getModifiers();
+        if (mem instanceof Constructor) {
+            name = "<init>";  // according to 292 spec.
+        }
+        if (defc == cls)
+            return true;
+        if (name.startsWith("<"))
+            return false;  // only my own constructors
+        if (Modifier.isPrivate(mods))
+            return false;  // only my own constructors
+        if (defc.getPackage() == cls.getPackage())
+            return true;   // package access or greater OK
+        if (Modifier.isPublic(mods))
+            return true;   // publics always OK
+        if (Modifier.isProtected(mods) && defc.isAssignableFrom(cls))
+            return true;   // protected OK
+        return false;
+    }
+    static boolean consistent(UnreflectResult res, MethodHandleInfo info) {
+        assert(res.mh != null);
+        assertEquals(res.kind, info.getReferenceKind());
+        assertEquals(res.mem.getModifiers(), info.getModifiers());
+        assertEquals(res.mem.getDeclaringClass(), info.getDeclaringClass());
+        String expectName = res.mem.getName();
+        if (res.kind == REF_newInvokeSpecial)
+            expectName = "<init>";
+        assertEquals(expectName, info.getName());
+        MethodType expectType = res.mh.type();
+        if ((res.kind & 1) == (REF_getField & 1))
+            expectType = expectType.dropParameterTypes(0, 1);
+        if (res.kind == REF_newInvokeSpecial)
+            expectType = expectType.changeReturnType(void.class);
+        assertEquals(expectType, info.getMethodType());
+        assertEquals(res.mh.isVarargsCollector(), isVarArgs(info));
+        assertEquals(res.toInfoString(), info.toString());
+        assertEquals(res.toInfoString(), MethodHandleInfo.toString(info.getReferenceKind(), info.getDeclaringClass(), info.getName(), info.getMethodType()));
+        return true;
+    }
+    static boolean isVarArgs(MethodHandleInfo info) {
+        return info.isVarArgs();
+    }
+    static boolean consistent(Member mem, Member mem2) {
+        assertEquals(mem, mem2);
+        return true;
+    }
+    static boolean consistent(MethodHandleInfo info, MethodHandleInfo info2) {
+        assertEquals(info.getReferenceKind(), info2.getReferenceKind());
+        assertEquals(info.getModifiers(), info2.getModifiers());
+        assertEquals(info.getDeclaringClass(), info2.getDeclaringClass());
+        assertEquals(info.getName(), info2.getName());
+        assertEquals(info.getMethodType(), info2.getMethodType());
+        assertEquals(isVarArgs(info), isVarArgs(info));
+        return true;
+    }
+    static boolean consistent(MethodHandle mh, MethodHandle mh2) {
+        assertEquals(mh.type(), mh2.type());
+        assertEquals(mh.isVarargsCollector(), mh2.isVarargsCollector());
+        return true;
+    }
+    int[] failureModeCounts;
+    static final int NO_FAIL=0, FAIL_LOOKUP=1, FAIL_REVEAL=2, FAIL_REFLECT=3, FAIL_MODE_COUNT=4;
+    void testWithMember(Member mem,
+                        Lookup lookup,      // initial lookup of member => MH
+                        Lookup revLookup,   // reveal MH => info
+                        Lookup refLookup,   // reflect info => member
+                        int failureMode) throws Throwable {
+        boolean expectEx1 = (failureMode == FAIL_LOOKUP);   // testOnMembersNoLookup
+        boolean expectEx2 = (failureMode == FAIL_REVEAL);   // testOnMembersNoReveal
+        boolean expectEx3 = (failureMode == FAIL_REFLECT);  // testOnMembersNoReflect
+        for (int variation = 0; ; variation++) {
+            UnreflectResult res = unreflectMember(lookup, mem, variation);
+            failureModeCounts[failureMode] += 1;
+            if (variation == 0)  assert(res != null);
+            if (res == null)  break;
+            if (VERBOSE && variation == 0)
+                System.out.println("from "+mem.getDeclaringClass().getSimpleName());
+            MethodHandle mh = res.mh;
+            Throwable   ex1 = res.ex;
+            if (VERBOSE)  System.out.println("  "+variation+": "+res+"  << "+(mh != null ? mh : ex1));
+            if (expectEx1 && ex1 != null)
+                continue;  // this is OK; we expected that lookup to fail
+            if (expectEx1)
+                throw new AssertionError("unexpected lookup for negative test");
+            if (ex1 != null && !expectEx1) {
+                if (failureMode != NO_FAIL)
+                    throw new AssertionError("unexpected lookup failure for negative test", ex1);
+                throw ex1;
+            }
+            MethodHandleInfo info;
+            try {
+                info = revLookup.revealDirect(mh);
+                if (expectEx2)  throw new AssertionError("unexpected revelation for negative test");
+            } catch (Throwable ex2) {
+                if (VERBOSE)  System.out.println("  "+variation+": "+res+" => "+mh.getClass().getName()+" => (EX2)"+ex2);
+                if (expectEx2)
+                    continue;  // this is OK; we expected the reflect to fail
+                if (failureMode != NO_FAIL)
+                    throw new AssertionError("unexpected revelation failure for negative test", ex2);
+                throw ex2;
+            }
+            assert(consistent(res, info));
+            Member mem2;
+            try {
+                mem2 = info.reflectAs(Member.class, refLookup);
+                if (expectEx3)  throw new AssertionError("unexpected reflection for negative test");
+                assert(!(mem instanceof SignaturePolymorphicMethod));
+            } catch (IllegalArgumentException ex3) {
+                if (VERBOSE)  System.out.println("  "+variation+": "+info+" => (EX3)"+ex3);
+                if (expectEx3)
+                    continue;  // this is OK; we expected the reflect to fail
+                if (mem instanceof SignaturePolymorphicMethod)
+                    continue;  // this is OK; we cannot reflect MH.invokeExact(a,b,c)
+                if (failureMode != NO_FAIL)
+                    throw new AssertionError("unexpected reflection failure for negative test", ex3);
+                throw ex3;
+            }
+            assert(consistent(mem, mem2));
+            UnreflectResult res2 = unreflectMember(lookup, mem2, variation);
+            MethodHandle mh2 = res2.mh;
+            assert(consistent(mh, mh2));
+            MethodHandleInfo info2 = lookup.revealDirect(mh2);
+            assert(consistent(info, info2));
+            assert(consistent(res, info2));
+            Member mem3;
+            if (hasSM())
+                mem3 = info2.reflectAs(Member.class, lookup);
+            else
+                mem3 = MethodHandles.reflectAs(Member.class, mh2);
+            assert(consistent(mem2, mem3));
+            if (hasSM()) {
+                try {
+                    MethodHandles.reflectAs(Member.class, mh2);
+                    throw new AssertionError("failed to throw on "+mem3);
+                } catch (SecurityException ex3) {
+                    // OK...
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/invoke/jtreg.security.policy	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,9 @@
+/*
+ * security policy used by the test process
+ * must allow file reads so that jtreg itself can run
+ */
+
+grant {
+  // standard test activation permissions
+  permission java.io.FilePermission "*", "read";
+};
--- a/jdk/test/java/lang/management/ThreadMXBean/LockedMonitors.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/lang/management/ThreadMXBean/LockedMonitors.java	Wed Jul 05 19:11:53 2017 +0200
@@ -37,7 +37,7 @@
  * @build Barrier
  * @build LockingThread
  * @build ThreadDump
- * @run main LockedMonitors
+ * @run main/othervm LockedMonitors
  */
 
 import java.lang.management.*;
--- a/jdk/test/java/lang/management/ThreadMXBean/LockedSynchronizers.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/lang/management/ThreadMXBean/LockedSynchronizers.java	Wed Jul 05 19:11:53 2017 +0200
@@ -33,7 +33,7 @@
  * @build Barrier
  * @build SynchronizerLockingThread
  * @build ThreadDump
- * @run main LockedSynchronizers
+ * @run main/othervm LockedSynchronizers
  */
 
 import java.lang.management.*;
--- a/jdk/test/java/lang/management/ThreadMXBean/Locks.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/lang/management/ThreadMXBean/Locks.java	Wed Jul 05 19:11:53 2017 +0200
@@ -193,16 +193,18 @@
         public CheckerThread() {
             super("CheckerThread");
         }
+
+        private void waitForState(Thread.State state) {
+            thrsync.waitForSignal();
+            while (waiter.getState() != state) {
+               goSleep(10);
+            }
+        }
+
         public void run() {
             synchronized (ready) {
                 // wait until WaitingThread about to wait for objC
-                thrsync.waitForSignal();
-
-                int retryCount = 0;
-                while (waiter.getState() != Thread.State.WAITING
-                       && retryCount++ < 500) {
-                   goSleep(100);
-                }
+                waitForState(Thread.State.WAITING);
                 checkBlockedObject(waiter, objC, null, Thread.State.WAITING);
 
                 synchronized (objC) {
@@ -211,16 +213,13 @@
 
                 // wait for waiter thread to about to enter
                 // synchronized object ready.
-                thrsync.waitForSignal();
-                // give chance for waiter thread to get blocked on
-                // object ready.
-                goSleep(50);
+                waitForState(Thread.State.BLOCKED);
                 checkBlockedObject(waiter, ready, this, Thread.State.BLOCKED);
             }
 
             // wait for signal from waiting thread that it is about
             // wait for objC.
-            thrsync.waitForSignal();
+            waitForState(Thread.State.WAITING);
             synchronized(objC) {
                 checkBlockedObject(waiter, objC, Thread.currentThread(), Thread.State.WAITING);
                 objC.notify();
--- a/jdk/test/java/lang/management/ThreadMXBean/MyOwnSynchronizer.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/lang/management/ThreadMXBean/MyOwnSynchronizer.java	Wed Jul 05 19:11:53 2017 +0200
@@ -30,7 +30,7 @@
  *
  * @build Barrier
  * @build ThreadDump
- * @run main MyOwnSynchronizer
+ * @run main/othervm MyOwnSynchronizer
  */
 
 import java.lang.management.*;
--- a/jdk/test/java/lang/management/ThreadMXBean/SharedSynchronizer.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/lang/management/ThreadMXBean/SharedSynchronizer.java	Wed Jul 05 19:11:53 2017 +0200
@@ -28,7 +28,7 @@
  *          in shared mode which has no owner when a thread is parked.
  * @author  Mandy Chung
  *
- * @run main SharedSynchronizer
+ * @run main/othervm SharedSynchronizer
  */
 
 
--- a/jdk/test/java/lang/management/ThreadMXBean/SynchronizationStatistics.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/lang/management/ThreadMXBean/SynchronizationStatistics.java	Wed Jul 05 19:11:53 2017 +0200
@@ -30,7 +30,7 @@
  *
  * @ignore  6309226
  * @build Semaphore
- * @run main SynchronizationStatistics
+ * @run main/othervm SynchronizationStatistics
  */
 
 import java.lang.management.*;
--- a/jdk/test/java/lang/management/ThreadMXBean/ThreadExecutionSynchronizer.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/lang/management/ThreadMXBean/ThreadExecutionSynchronizer.java	Wed Jul 05 19:11:53 2017 +0200
@@ -23,7 +23,7 @@
 
 /*
  *
- * @summary Thiseclass is used to synchronize execution off two threads.
+ * @summary This class is used to synchronize execution of two threads.
  * @author  Swamy Venkataramanappa
  */
 
@@ -31,8 +31,8 @@
 
 public class ThreadExecutionSynchronizer {
 
-    private boolean  waiting;
-    private Semaphore semaphore;
+    private volatile boolean waiting;
+    private final Semaphore semaphore;
 
     public ThreadExecutionSynchronizer() {
         semaphore = new Semaphore(1);
--- a/jdk/test/java/lang/reflect/Generics/Probe.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/lang/reflect/Generics/Probe.java	Wed Jul 05 19:11:53 2017 +0200
@@ -50,9 +50,9 @@
           "java.util.HashMap$EntryIterator",
           "java.util.HashMap$KeyIterator",
           "java.util.HashMap$ValueIterator",
-          "java.util.LinkedHashMap$EntryIterator",
-          "java.util.LinkedHashMap$KeyIterator",
-          "java.util.LinkedHashMap$ValueIterator"})
+          "java.util.LinkedHashMap$LinkedEntryIterator",
+          "java.util.LinkedHashMap$LinkedKeyIterator",
+          "java.util.LinkedHashMap$LinkedValueIterator"})
 public class Probe {
     public static void main (String... args) throws Throwable {
         Classes classesAnnotation = (Probe.class).getAnnotation(Classes.class);
--- a/jdk/test/java/net/CookieHandler/LocalHostCookie.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/net/CookieHandler/LocalHostCookie.java	Wed Jul 05 19:11:53 2017 +0200
@@ -72,7 +72,9 @@
                 }
             }
         } finally {
-            s.stopServer();
+            if (s != null) {
+                s.stopServer();
+            }
         }
     }
 
@@ -96,7 +98,9 @@
         }
 
         public void stopServer() {
-            server.stop(0);
+            if (server != null) {
+                server.stop(0);
+            }
         }
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/IDN/UseSTD3ASCIIRules.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8023881
+ * @summary IDN.USE_STD3_ASCII_RULES option is too strict to use Unicode
+ *          in IDN.toASCII
+ */
+
+import java.net.*;
+
+public class UseSTD3ASCIIRules {
+
+    public static void main(String[] args) throws Exception {
+        // Per Section 4.1, RFC 3490, if the UseSTD3ASCIIRules flag is set,
+        // then perform these checks:
+        //
+        // (a) Verify the absence of non-LDH ASCII code points; that is, the
+        //     absence of 0..2C, 2E..2F, 3A..40, 5B..60, and 7B..7F.
+        //
+        // (b) Verify the absence of leading and trailing hyphen-minus; that
+        //     is, the absence of U+002D at the beginning and end of the
+        //     sequence.
+        String[] illegalNames = {
+                "www.example.com-",
+                "-www.example.com",
+                "-www.example.com-",
+                "www.ex\u002Cmple.com",
+                "www.ex\u007Bmple.com",
+                "www.ex\u007Fmple.com"
+            };
+
+        String[] legalNames = {
+                "www.ex-ample.com",
+                "www.ex\u002Dmple.com",         // www.ex-mple.com
+                "www.ex\u007Ample.com",         // www.exzmple.com
+                "www.ex\u3042mple.com",         // www.xn--exmple-j43e.com
+                "www.\u3042\u3044\u3046.com",   // www.xn--l8jeg.com
+                "www.\u793A\u4F8B.com"          // www.xn--fsq092h.com
+            };
+
+        for (String name : illegalNames) {
+            try {
+                System.out.println("Convering illegal IDN: " + name);
+                IDN.toASCII(name, IDN.USE_STD3_ASCII_RULES);
+                throw new Exception(
+                    "Expected to get IllegalArgumentException for " + name);
+            } catch (IllegalArgumentException iae) {
+                // That's the right behavior.
+            }
+        }
+
+        for (String name : legalNames) {
+            System.out.println("Convering legal IDN: " + name);
+            System.out.println("\tThe ACE form is: " +
+                        IDN.toASCII(name, IDN.USE_STD3_ASCII_RULES));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/MulticastSocket/SetGetNetworkInterfaceTest.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+/*
+ * @test
+ * @bug 6458027
+ * @summary Disabling IPv6 on a specific network interface causes problems.
+ *
+ */
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.MulticastSocket;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.Arrays;
+import java.util.Enumeration;
+
+
+public class SetGetNetworkInterfaceTest  {
+
+    public static void main(String[] args) throws Exception {
+
+        boolean passed = true;
+        try {
+            MulticastSocket ms = new MulticastSocket();
+            Enumeration<NetworkInterface> networkInterfaces = NetworkInterface
+                    .getNetworkInterfaces();
+            while (networkInterfaces.hasMoreElements()) {
+                NetworkInterface netIf = networkInterfaces.nextElement();
+                if (isNetworkInterfaceTestable(netIf)) {
+                    printNetIfDetails(netIf);
+                    ms.setNetworkInterface(netIf);
+                    NetworkInterface msNetIf = ms.getNetworkInterface();
+                    if (netIf.equals(msNetIf)) {
+                        System.out.println(" OK");
+                    } else {
+                        System.out.println("FAILED!!!");
+                        printNetIfDetails(msNetIf);
+                        passed = false;
+                    }
+                    System.out.println("------------------");
+                }
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+            passed = false;
+        }
+        if (!passed) {
+            throw new RuntimeException("Test Fail");
+        }
+        System.out.println("Test passed ");
+    }
+
+    private static boolean isNetworkInterfaceTestable(NetworkInterface netIf) throws Exception {
+        System.out.println("checking netif == " + netIf.getName());
+        return  (netIf.isUp() && netIf.supportsMulticast() && isIpAddrAvailable(netIf));
+    }
+
+    private static boolean isIpAddrAvailable (NetworkInterface netIf) {
+        boolean ipAddrAvailable = false;
+        byte[] nullIpAddr = {'0', '0', '0', '0'};
+        byte[] testIpAddr = null;
+
+        Enumeration<InetAddress> ipAddresses = netIf.getInetAddresses();
+        while (ipAddresses.hasMoreElements()) {
+            InetAddress testAddr = ipAddresses.nextElement();
+            testIpAddr = testAddr.getAddress();
+            if ((testIpAddr != null) && (!Arrays.equals(testIpAddr, nullIpAddr))) {
+                ipAddrAvailable = true;
+                break;
+            } else {
+                System.out.println("ignore netif " + netIf.getName());
+            }
+        }
+        return ipAddrAvailable;
+    }
+
+    private static void printNetIfDetails(NetworkInterface ni)
+            throws SocketException {
+        System.out.println("Name " + ni.getName() + " index " + ni.getIndex());
+        Enumeration<InetAddress> en = ni.getInetAddresses();
+        while (en.hasMoreElements()) {
+            System.out.println(" InetAdress: " + en.nextElement());
+        }
+        System.out.println("HardwareAddress: " + createMacAddrString(ni));
+        System.out.println("loopback: " + ni.isLoopback() + "; pointToPoint: "
+                + ni.isPointToPoint() + "; virtual: " + ni.isVirtual()
+                + "; MTU: " + ni.getMTU());
+    }
+
+    private static String createMacAddrString(NetworkInterface netIf)
+            throws SocketException {
+        byte[] macAddr = netIf.getHardwareAddress();
+        StringBuilder sb = new StringBuilder();
+        if (macAddr != null) {
+            for (int i = 0; i < macAddr.length; i++) {
+                sb.append(String.format("%02X%s", macAddr[i],
+                        (i < macAddr.length - 1) ? "-" : ""));
+            }
+        }
+        return sb.toString();
+    }
+}
--- a/jdk/test/java/net/NetworkInterface/Equals.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/net/NetworkInterface/Equals.java	Wed Jul 05 19:11:53 2017 +0200
@@ -25,41 +25,83 @@
  * @bug 7003398
  * @run main/othervm Equals
  */
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.net.InetAddress;
 import java.net.NetworkInterface;
-import java.net.InetAddress;
+import java.net.SocketException;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashMap;
 
 public class Equals {
 
     public static void main(String args[]) throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        PrintStream bufferedOut = new PrintStream(baos);
 
-        Enumeration nifs1 = NetworkInterface.getNetworkInterfaces();
+        Enumeration<NetworkInterface> nifs1 = NetworkInterface.getNetworkInterfaces();
         HashMap<String,Integer> hashes = new HashMap<>();
         HashMap<String,NetworkInterface> nicMap = new HashMap<>();
 
         while (nifs1.hasMoreElements()) {
-            NetworkInterface ni = (NetworkInterface)nifs1.nextElement();
+            NetworkInterface ni = nifs1.nextElement();
             hashes.put(ni.getName(),ni.hashCode());
             nicMap.put(ni.getName(),ni);
+            displayInterfaceInformation(ni, bufferedOut);
+            bufferedOut.flush();
         }
 
         System.setSecurityManager(new SecurityManager());
 
-        Enumeration nifs2 = NetworkInterface.getNetworkInterfaces();
+        Enumeration<NetworkInterface> nifs2 = NetworkInterface.getNetworkInterfaces();
         while (nifs2.hasMoreElements()) {
-            NetworkInterface ni = (NetworkInterface)nifs2.nextElement();
+            NetworkInterface ni = nifs2.nextElement();
             NetworkInterface niOrig = nicMap.get(ni.getName());
 
-            int h = hashes.get(ni.getName());
-            if (h != ni.hashCode()) {
-                throw new RuntimeException ("Hashcodes different for " +
+            int h = ni.hashCode();
+            if (h != hashes.get(ni.getName())) {
+                System.out.printf("%nSystem information:%n");
+                System.out.printf("%s", baos.toString("UTF8"));
+                System.out.printf("%nni.hashCode() returned %d, expected %d, for:%n",
+                                  h, hashes.get(ni.getName()));
+                displayInterfaceInformation(ni, System.out);
+                throw new RuntimeException("Hashcodes different for " +
                         ni.getName());
             }
             if (!ni.equals(niOrig)) {
-                throw new RuntimeException ("equality different for " +
+                System.out.printf("%nSystem information:%n");
+                System.out.printf("%s", baos.toString("UTF8"));
+                System.out.printf("%nExpected the following interfaces to be the same:%n");
+                displayInterfaceInformation(niOrig, System.out);
+                displayInterfaceInformation(ni, System.out);
+                throw new RuntimeException("equality different for " +
                         ni.getName());
             }
         }
     }
+
+    static void displayInterfaceInformation(NetworkInterface netint,
+                                            PrintStream out) throws SocketException {
+        out.printf("Display name: %s%n", netint.getDisplayName());
+        out.printf("Name: %s%n", netint.getName());
+        Enumeration<InetAddress> inetAddresses = netint.getInetAddresses();
+
+        for (InetAddress inetAddress : Collections.list(inetAddresses))
+            out.printf("InetAddress: %s%n", inetAddress);
+
+        out.printf("Up? %s%n", netint.isUp());
+        out.printf("Loopback? %s%n", netint.isLoopback());
+        out.printf("PointToPoint? %s%n", netint.isPointToPoint());
+        out.printf("Supports multicast? %s%n", netint.supportsMulticast());
+        out.printf("Virtual? %s%n", netint.isVirtual());
+        out.printf("Hardware address: %s%n",
+                    Arrays.toString(netint.getHardwareAddress()));
+        out.printf("MTU: %s%n", netint.getMTU());
+        out.printf("Index: %s%n", netint.getIndex());
+        out.printf("%n");
+     }
 }
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/NetworkInterface/UniqueMacAddressesTest.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.List;
+
+
+/*
+ * @test
+ * @bug 8021372
+ * @summary Tests that the MAC addresses returned by NetworkInterface.getNetworkInterfaces are unique for each adapter.
+ *
+ */
+public class UniqueMacAddressesTest {
+
+    public static void main(String[] args) throws Exception {
+        new UniqueMacAddressesTest().execute();
+        System.out.println("UniqueMacAddressesTest: OK");
+    }
+
+    public UniqueMacAddressesTest() {
+        System.out.println("UniqueMacAddressesTest: start ");
+    }
+
+    public void execute() throws Exception {
+        Enumeration<NetworkInterface> networkInterfaces;
+        boolean areMacAddressesUnique = false;
+        List<NetworkInterface> networkInterfaceList = new ArrayList<NetworkInterface>();
+            networkInterfaces = NetworkInterface.getNetworkInterfaces();
+
+        // build a list of NetworkInterface objects to test MAC address
+        // uniqueness
+        createNetworkInterfaceList(networkInterfaces, networkInterfaceList);
+        areMacAddressesUnique = checkMacAddressesAreUnique(networkInterfaceList);
+        if (!areMacAddressesUnique) {
+            throw new RuntimeException("mac address uniqueness test failed");
+        }
+    }
+
+    private boolean checkMacAddressesAreUnique (
+            List<NetworkInterface> networkInterfaces) throws Exception {
+        boolean uniqueMacAddresses = true;
+        for (NetworkInterface networkInterface : networkInterfaces) {
+            for (NetworkInterface comparisonNetIf : networkInterfaces) {
+                System.out.println("Comparing netif "
+                        + networkInterface.getName() + " and netif "
+                        + comparisonNetIf.getName());
+                if (testMacAddressesEqual(networkInterface, comparisonNetIf)) {
+                    uniqueMacAddresses = false;
+                    break;
+                }
+            }
+            if (uniqueMacAddresses != true)
+                break;
+        }
+        return uniqueMacAddresses;
+    }
+
+    private boolean testMacAddressesEqual(NetworkInterface netIf1,
+            NetworkInterface netIf2) throws Exception {
+
+        byte[] rawMacAddress1 = null;
+        byte[] rawMacAddress2 = null;
+        boolean macAddressesEqual = false;
+        if (!netIf1.getName().equals(netIf2.getName())) {
+            System.out.println("compare hardware addresses "
+                +  createMacAddressString(netIf1) + " and " + createMacAddressString(netIf2));
+            rawMacAddress1 = netIf1.getHardwareAddress();
+            rawMacAddress2 = netIf2.getHardwareAddress();
+            macAddressesEqual = Arrays.equals(rawMacAddress1, rawMacAddress2);
+        } else {
+            // same interface
+            macAddressesEqual = false;
+        }
+        return macAddressesEqual;
+    }
+
+    private String createMacAddressString (NetworkInterface netIf) throws Exception {
+        byte[] macAddr = netIf.getHardwareAddress();
+        StringBuilder sb =  new StringBuilder();
+        if (macAddr != null) {
+            for (int i = 0; i < macAddr.length; i++) {
+                sb.append(String.format("%02X%s", macAddr[i],
+                        (i < macAddr.length - 1) ? "-" : ""));
+            }
+        }
+        return sb.toString();
+    }
+
+    private void createNetworkInterfaceList(Enumeration<NetworkInterface> nis,
+            List<NetworkInterface> networkInterfaceList) throws Exception {
+        byte[] macAddr = null;
+        NetworkInterface netIf = null;
+        while (nis.hasMoreElements()) {
+            netIf = (NetworkInterface) nis.nextElement();
+            if (netIf.isUp()) {
+                macAddr = netIf.getHardwareAddress();
+                if (macAddr != null) {
+                    System.out.println("Adding NetworkInterface "
+                            + netIf.getName() + " with mac address "
+                            + createMacAddressString(netIf));
+                    networkInterfaceList.add(netIf);
+                }
+            }
+        }
+    }
+}
--- a/jdk/test/java/nio/file/Files/StreamTest.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/nio/file/Files/StreamTest.java	Wed Jul 05 19:11:53 2017 +0200
@@ -43,14 +43,13 @@
 import java.nio.file.Paths;
 import java.nio.file.attribute.BasicFileAttributes;
 import java.util.Arrays;
-import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.function.BiPredicate;
-import java.util.stream.CloseableStream;
+import java.util.stream.Stream;
 import java.util.stream.Collectors;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
@@ -138,14 +137,14 @@
     }
 
     public void testBasic() {
-        try (CloseableStream<Path> s = Files.list(testFolder)) {
-            Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
+        try (Stream<Path> s = Files.list(testFolder)) {
+            Object[] actual = s.sorted().toArray();
             assertEquals(actual, level1);
         } catch (IOException ioe) {
             fail("Unexpected IOException");
         }
 
-        try (CloseableStream<Path> s = Files.list(testFolder.resolve("empty"))) {
+        try (Stream<Path> s = Files.list(testFolder.resolve("empty"))) {
             int count = s.mapToInt(p -> 1).reduce(0, Integer::sum);
             assertEquals(count, 0, "Expect empty stream.");
         } catch (IOException ioe) {
@@ -154,8 +153,8 @@
     }
 
     public void testWalk() {
-        try (CloseableStream<Path> s = Files.walk(testFolder)) {
-            Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
+        try (Stream<Path> s = Files.walk(testFolder)) {
+            Object[] actual = s.sorted().toArray();
             assertEquals(actual, all);
         } catch (IOException ioe) {
             fail("Unexpected IOException");
@@ -163,9 +162,9 @@
     }
 
     public void testWalkOneLevel() {
-        try (CloseableStream<Path> s = Files.walk(testFolder, 1)) {
+        try (Stream<Path> s = Files.walk(testFolder, 1)) {
             Object[] actual = s.filter(path -> ! path.equals(testFolder))
-                               .sorted(Comparator.naturalOrder())
+                               .sorted()
                                .toArray();
             assertEquals(actual, level1);
         } catch (IOException ioe) {
@@ -176,8 +175,8 @@
     public void testWalkFollowLink() {
         // If link is not supported, the directory structure won't have link.
         // We still want to test the behavior with FOLLOW_LINKS option.
-        try (CloseableStream<Path> s = Files.walk(testFolder, FileVisitOption.FOLLOW_LINKS)) {
-            Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
+        try (Stream<Path> s = Files.walk(testFolder, FileVisitOption.FOLLOW_LINKS)) {
+            Object[] actual = s.sorted().toArray();
             assertEquals(actual, all_folowLinks);
         } catch (IOException ioe) {
             fail("Unexpected IOException");
@@ -185,7 +184,7 @@
     }
 
     private void validateFileSystemLoopException(Path start, Path... causes) {
-        try (CloseableStream<Path> s = Files.walk(start, FileVisitOption.FOLLOW_LINKS)) {
+        try (Stream<Path> s = Files.walk(start, FileVisitOption.FOLLOW_LINKS)) {
             try {
                 int count = s.mapToInt(p -> 1).reduce(0, Integer::sum);
                 fail("Should got FileSystemLoopException, but got " + count + "elements.");
@@ -282,28 +281,28 @@
     public void testFind() throws IOException {
         PathBiPredicate pred = new PathBiPredicate((path, attrs) -> true);
 
-        try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
+        try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
             Set<Path> result = s.collect(Collectors.toCollection(TreeSet::new));
             assertEquals(pred.visited(), all);
             assertEquals(result.toArray(new Path[0]), pred.visited());
         }
 
         pred = new PathBiPredicate((path, attrs) -> attrs.isSymbolicLink());
-        try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
+        try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
             s.forEach(path -> assertTrue(Files.isSymbolicLink(path)));
             assertEquals(pred.visited(), all);
         }
 
         pred = new PathBiPredicate((path, attrs) ->
             path.getFileName().toString().startsWith("e"));
-        try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
+        try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
             s.forEach(path -> assertEquals(path.getFileName().toString(), "empty"));
             assertEquals(pred.visited(), all);
         }
 
         pred = new PathBiPredicate((path, attrs) ->
             path.getFileName().toString().startsWith("l") && attrs.isRegularFile());
-        try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
+        try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE, pred)) {
             s.forEach(path -> fail("Expect empty stream"));
             assertEquals(pred.visited(), all);
         }
@@ -317,14 +316,14 @@
         try {
             // zero lines
             assertTrue(Files.size(tmpfile) == 0, "File should be empty");
-            try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
+            try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {
                 assertEquals(s.mapToInt(l -> 1).reduce(0, Integer::sum), 0, "No line expected");
             }
 
             // one line
             byte[] hi = { (byte)'h', (byte)'i' };
             Files.write(tmpfile, hi);
-            try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
+            try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {
                 List<String> lines = s.collect(Collectors.toList());
                 assertTrue(lines.size() == 1, "One line expected");
                 assertTrue(lines.get(0).equals("hi"), "'Hi' expected");
@@ -334,7 +333,7 @@
             List<String> expected = Arrays.asList("hi", "there");
             Files.write(tmpfile, expected, US_ASCII);
             assertTrue(Files.size(tmpfile) > 0, "File is empty");
-            try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
+            try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {
                 List<String> lines = s.collect(Collectors.toList());
                 assertTrue(lines.equals(expected), "Unexpected lines");
             }
@@ -342,7 +341,7 @@
             // MalformedInputException
             byte[] bad = { (byte)0xff, (byte)0xff };
             Files.write(tmpfile, bad);
-            try (CloseableStream<String> s = Files.lines(tmpfile, US_ASCII)) {
+            try (Stream<String> s = Files.lines(tmpfile, US_ASCII)) {
                 try {
                     List<String> lines = s.collect(Collectors.toList());
                     throw new RuntimeException("UncheckedIOException expected");
@@ -378,7 +377,7 @@
             fsp.setFaultyMode(false);
             Path fakeRoot = fs.getRoot();
             try {
-                try (CloseableStream<Path> s = Files.list(fakeRoot)) {
+                try (Stream<Path> s = Files.list(fakeRoot)) {
                     s.forEach(path -> assertEquals(path.getFileName().toString(), "DirectoryIteratorException"));
                 }
             } catch (UncheckedIOException uioe) {
@@ -398,7 +397,7 @@
             }
 
             try {
-                try (CloseableStream<Path> s = Files.list(fakeRoot)) {
+                try (Stream<Path> s = Files.list(fakeRoot)) {
                     s.forEach(path -> fail("should not get here"));
                 }
             } catch (UncheckedIOException uioe) {
@@ -427,12 +426,12 @@
         try {
             fsp.setFaultyMode(false);
             Path fakeRoot = fs.getRoot();
-            try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
+            try (Stream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
                 // only one file
                 s.forEach(path -> assertEquals(path.getFileName().toString(), "IOException"));
             }
 
-            try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
+            try (Stream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
                 String[] result = s.map(path -> path.getFileName().toString())
                                    .toArray(String[]::new);
                 // ordered as depth-first
@@ -440,13 +439,13 @@
             }
 
             fsp.setFaultyMode(true);
-            try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
+            try (Stream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
                 s.forEach(path -> fail("should have caused exception"));
             } catch (UncheckedIOException uioe) {
                 assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);
             }
 
-            try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
+            try (Stream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
                 String[] result = s.map(path -> path.getFileName().toString())
                                    .toArray(String[]::new);
                 fail("should not reach here due to IOException");
@@ -454,7 +453,7 @@
                 assertTrue(uioe.getCause() instanceof FaultyFileSystem.FaultyException);
             }
 
-            try (CloseableStream<Path> s = Files.walk(
+            try (Stream<Path> s = Files.walk(
                 fakeRoot.resolve("empty").resolve("IOException")))
             {
                 String[] result = s.map(path -> path.getFileName().toString())
@@ -502,20 +501,20 @@
             fsp.setFaultyMode(false);
             Path fakeRoot = fs.getRoot();
             // validate setting
-            try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("empty"))) {
+            try (Stream<Path> s = Files.list(fakeRoot.resolve("empty"))) {
                 String[] result = s.map(path -> path.getFileName().toString())
                                    .toArray(String[]::new);
                 assertEqualsNoOrder(result, new String[] { "SecurityException", "sample" });
             }
 
-            try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {
+            try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {
                 String[] result = s.map(path -> path.getFileName().toString())
                                    .toArray(String[]::new);
                 assertEqualsNoOrder(result, new String[] { "dir2", "SecurityException", "fileInSE", "file" });
             }
 
             if (supportsLinks) {
-                try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir"))) {
+                try (Stream<Path> s = Files.list(fakeRoot.resolve("dir"))) {
                     String[] result = s.map(path -> path.getFileName().toString())
                                        .toArray(String[]::new);
                     assertEqualsNoOrder(result, new String[] { "d1", "f1", "lnDir2", "SecurityException", "lnDirSE", "lnFileSE" });
@@ -525,13 +524,13 @@
             // execute test
             fsp.setFaultyMode(true);
             // ignore file cause SecurityException
-            try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
+            try (Stream<Path> s = Files.walk(fakeRoot.resolve("empty"))) {
                 String[] result = s.map(path -> path.getFileName().toString())
                                    .toArray(String[]::new);
                 assertEqualsNoOrder(result, new String[] { "empty", "sample" });
             }
             // skip folder cause SecurityException
-            try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {
+            try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir2"))) {
                 String[] result = s.map(path -> path.getFileName().toString())
                                    .toArray(String[]::new);
                 assertEqualsNoOrder(result, new String[] { "dir2", "file" });
@@ -539,14 +538,14 @@
 
             if (supportsLinks) {
                 // not following links
-                try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("dir"))) {
+                try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir"))) {
                     String[] result = s.map(path -> path.getFileName().toString())
                                        .toArray(String[]::new);
                     assertEqualsNoOrder(result, new String[] { "dir", "d1", "f1", "lnDir2", "lnDirSE", "lnFileSE" });
                 }
 
                 // following links
-                try (CloseableStream<Path> s = Files.walk(fakeRoot.resolve("dir"), FileVisitOption.FOLLOW_LINKS)) {
+                try (Stream<Path> s = Files.walk(fakeRoot.resolve("dir"), FileVisitOption.FOLLOW_LINKS)) {
                     String[] result = s.map(path -> path.getFileName().toString())
                                        .toArray(String[]::new);
                     // ?? Should fileInSE show up?
@@ -556,19 +555,19 @@
             }
 
             // list instead of walk
-            try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("empty"))) {
+            try (Stream<Path> s = Files.list(fakeRoot.resolve("empty"))) {
                 String[] result = s.map(path -> path.getFileName().toString())
                                    .toArray(String[]::new);
                 assertEqualsNoOrder(result, new String[] { "sample" });
             }
-            try (CloseableStream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
+            try (Stream<Path> s = Files.list(fakeRoot.resolve("dir2"))) {
                 String[] result = s.map(path -> path.getFileName().toString())
                                    .toArray(String[]::new);
                 assertEqualsNoOrder(result, new String[] { "file" });
             }
 
             // root cause SecurityException should be reported
-            try (CloseableStream<Path> s = Files.walk(
+            try (Stream<Path> s = Files.walk(
                 fakeRoot.resolve("dir2").resolve("SecurityException")))
             {
                 String[] result = s.map(path -> path.getFileName().toString())
@@ -579,7 +578,7 @@
             }
 
             // Walk a file cause SecurityException, we should get SE
-            try (CloseableStream<Path> s = Files.walk(
+            try (Stream<Path> s = Files.walk(
                 fakeRoot.resolve("dir").resolve("SecurityException")))
             {
                 String[] result = s.map(path -> path.getFileName().toString())
@@ -590,7 +589,7 @@
             }
 
             // List a file cause SecurityException, we should get SE as cannot read attribute
-            try (CloseableStream<Path> s = Files.list(
+            try (Stream<Path> s = Files.list(
                 fakeRoot.resolve("dir2").resolve("SecurityException")))
             {
                 String[] result = s.map(path -> path.getFileName().toString())
@@ -600,7 +599,7 @@
                 assertTrue(se.getCause() instanceof FaultyFileSystem.FaultyException);
             }
 
-            try (CloseableStream<Path> s = Files.list(
+            try (Stream<Path> s = Files.list(
                 fakeRoot.resolve("dir").resolve("SecurityException")))
             {
                 String[] result = s.map(path -> path.getFileName().toString())
@@ -627,7 +626,7 @@
     }
 
     public void testConstructException() {
-        try (CloseableStream<String> s = Files.lines(testFolder.resolve("notExist"), Charset.forName("UTF-8"))) {
+        try (Stream<String> s = Files.lines(testFolder.resolve("notExist"), Charset.forName("UTF-8"))) {
             s.forEach(l -> fail("File is not even exist!"));
         } catch (IOException ioe) {
             assertTrue(ioe instanceof NoSuchFileException);
@@ -635,24 +634,26 @@
     }
 
     public void testClosedStream() throws IOException {
-        try (CloseableStream<Path> s = Files.list(testFolder)) {
+        try (Stream<Path> s = Files.list(testFolder)) {
             s.close();
-            Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
-            assertTrue(actual.length <= level1.length);
-        }
-
-        try (CloseableStream<Path> s = Files.walk(testFolder)) {
-            s.close();
-            Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
+            Object[] actual = s.sorted().toArray();
             fail("Operate on closed stream should throw IllegalStateException");
         } catch (IllegalStateException ex) {
             // expected
         }
 
-        try (CloseableStream<Path> s = Files.find(testFolder, Integer.MAX_VALUE,
+        try (Stream<Path> s = Files.walk(testFolder)) {
+            s.close();
+            Object[] actual = s.sorted().toArray();
+            fail("Operate on closed stream should throw IllegalStateException");
+        } catch (IllegalStateException ex) {
+            // expected
+        }
+
+        try (Stream<Path> s = Files.find(testFolder, Integer.MAX_VALUE,
                     (p, attr) -> true)) {
             s.close();
-            Object[] actual = s.sorted(Comparator.naturalOrder()).toArray();
+            Object[] actual = s.sorted().toArray();
             fail("Operate on closed stream should throw IllegalStateException");
         } catch (IllegalStateException ex) {
             // expected
--- a/jdk/test/java/nio/file/WatchService/SensitivityModifier.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/nio/file/WatchService/SensitivityModifier.java	Wed Jul 05 19:11:53 2017 +0200
@@ -100,7 +100,7 @@
                     }
                     key.reset();
                     key = watcher.poll(1, TimeUnit.SECONDS);
-                } while (key != null && !eventReceived);
+                } while (key != null);
 
                 // we should have received at least one ENTRY_MODIFY event
                 if (eventReceived) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/security/cert/PKIXRevocationChecker/OcspUnauthorized.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8023362
+ * @summary Make sure Ocsp UNAUTHORIZED response is treated as failure when
+ *          SOFT_FAIL option is set
+ */
+
+import java.io.ByteArrayInputStream;
+import java.security.cert.*;
+import java.security.cert.PKIXRevocationChecker.Option;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.EnumSet;
+
+public class OcspUnauthorized {
+
+    private final static String OCSP_RESPONSE = "MAMKAQY=";
+
+    private final static String EE_CERT =
+        "MIICADCCAWmgAwIBAgIEOvxUmjANBgkqhkiG9w0BAQQFADAqMQswCQYDVQQGEwJ1czE" +
+        "MMAoGA1UEChMDc3VuMQ0wCwYDVQQLEwRsYWJzMB4XDTAxMDUxNDIwNDQyMVoXDTI4MD" +
+        "kyOTIwNDQyMVowOTELMAkGA1UEBhMCdXMxDDAKBgNVBAoTA3N1bjENMAsGA1UECxMEb" +
+        "GFiczENMAsGA1UECxMEaXNyZzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4MmP" +
+        "GDriFJ+OhDlTuLpHzPy0nawDKyIYUJPZmU9M/pCAUbZewAOyAXGPYVU1og2ZiO9tWBi" +
+        "ZBeJGoFHEkkhfeqSVb2PsRckiXvPZ3AiSVmdX0uD/a963abmhRMYB1gDO2+jBe3F/DU" +
+        "pHwpyThchy8tYUMh7Gr7+m/8FwZbdbSpMCAwEAAaMkMCIwDwYDVR0PAQH/BAUDAwekA" +
+        "DAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBAUAA4GBAME3fmXvES0FVDXSD1iC" +
+        "TJLf86kUy3H+uMG7h5pOQmcfF1o9PVWlNByVf4r2b4GRgftPQ3Ao0SAvq1aSkW7YpkN" +
+        "pcartYqNk2E5brPajOC0v+Pkxf/g/pkRTT6Zp+9erGQF4Ta62q0iwOyc3FovSbh0Ph2" +
+        "WidZRP4qUG5I6JmGkI";
+
+    private final static String TRUST_ANCHOR =
+        "MIICIzCCAYygAwIBAgIEOvxT7DANBgkqhkiG9w0BAQQFADAbMQswCQYDVQQGEwJ1czE" +
+        "MMAoGA1UEChMDc3VuMB4XDTAxMDUxNDIxMDQyOVoXDTI4MDkyOTIxMDQyOVowKjELMA" +
+        "kGA1UEBhMCdXMxDDAKBgNVBAoTA3N1bjENMAsGA1UECxMEbGFiczCBnzANBgkqhkiG9" +
+        "w0BAQEFAAOBjQAwgYkCgYEA0/16V87rhznCM0y7IqyGcfQBentG+PglA+1hiqCuQY/A" +
+        "jFiDKr5N+LpcfU28P41E4M+DSDrMIEe4JchRcXeJY6aIVhpOveVV9mgtBaEKlsScrIJ" +
+        "zmVqM07PG9JENg2FibECnB5TNUSfVbFKfvtAqaZ7Pc971oZVoIePBWnfKV9kCAwEAAa" +
+        "NlMGMwPwYDVR0eAQH/BDUwM6AxMC+kKjELMAkGA1UEBhMCdXMxDDAKBgNVBAoTA3N1b" +
+        "jENMAsGA1UECxMEbGFic4ABAzAPBgNVHQ8BAf8EBQMDB6QAMA8GA1UdEwEB/wQFMAMB" +
+        "Af8wDQYJKoZIhvcNAQEEBQADgYEAfJ5HWd7K5PmX0+Vbsux4SYhoaejDwwgS43BRNa+" +
+        "AmFq9LIZ+ZcjBMVte8Y3sJF+nz9+1qBaUhNhbaECCqsgmWSwvI+0kUzJXL89k9AdQ8m" +
+        "AYf6CB6+kaZQBgrdSdqSGz3tCVa2MIK8wmb0ROM40oJ7vt3qSwgFi3UTltxkFfwQ0=";
+
+    private static CertificateFactory cf;
+    private static Base64.Decoder base64Decoder = Base64.getDecoder();
+
+    public static void main(String[] args) throws Exception {
+        cf = CertificateFactory.getInstance("X.509");
+        X509Certificate taCert = getX509Cert(TRUST_ANCHOR);
+        X509Certificate eeCert = getX509Cert(EE_CERT);
+        CertPath cp = cf.generateCertPath(Collections.singletonList(eeCert));
+
+        CertPathValidator cpv = CertPathValidator.getInstance("PKIX");
+        PKIXRevocationChecker prc =
+            (PKIXRevocationChecker)cpv.getRevocationChecker();
+        prc.setOptions(EnumSet.of(Option.SOFT_FAIL, Option.NO_FALLBACK));
+        byte[] response = base64Decoder.decode(OCSP_RESPONSE);
+
+        prc.setOcspResponses(Collections.singletonMap(eeCert, response));
+
+        TrustAnchor ta = new TrustAnchor(taCert, null);
+        PKIXParameters params = new PKIXParameters(Collections.singleton(ta));
+
+        params.addCertPathChecker(prc);
+
+        try {
+            cpv.validate(cp, params);
+            throw new Exception("FAILED: expected CertPathValidatorException");
+        } catch (CertPathValidatorException cpve) {
+            cpve.printStackTrace();
+        }
+    }
+
+    private static X509Certificate getX509Cert(String enc) throws Exception {
+        byte[] bytes = base64Decoder.decode(enc);
+        ByteArrayInputStream is = new ByteArrayInputStream(bytes);
+        return (X509Certificate)cf.generateCertificate(is);
+    }
+}
--- a/jdk/test/java/time/tck/java/time/TCKLocalTime.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/time/tck/java/time/TCKLocalTime.java	Wed Jul 05 19:11:53 2017 +0200
@@ -283,17 +283,6 @@
     }
 
     //-----------------------------------------------------------------------
-    // now()
-    //-----------------------------------------------------------------------
-    @Test
-    public void now() {
-        LocalTime expected = LocalTime.now(Clock.systemDefaultZone());
-        LocalTime test = LocalTime.now();
-        long diff = Math.abs(test.toNanoOfDay() - expected.toNanoOfDay());
-        assertTrue(diff < 100000000);  // less than 0.1 secs
-    }
-
-    //-----------------------------------------------------------------------
     // now(ZoneId)
     //-----------------------------------------------------------------------
     @Test(expectedExceptions=NullPointerException.class)
--- a/jdk/test/java/time/tck/java/time/chrono/TCKChronologySerialization.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/time/tck/java/time/chrono/TCKChronologySerialization.java	Wed Jul 05 19:11:53 2017 +0200
@@ -97,7 +97,9 @@
         ObjectOutputStream out = new ObjectOutputStream(baos);
         out.writeObject(chrono);
         out.close();
-        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+
+        byte[] bytes = baos.toByteArray();
+        ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
 
         ObjectInputStream in = new ObjectInputStream(bais);
         @SuppressWarnings("unchecked")
--- a/jdk/test/java/time/tck/java/time/format/TCKDateTimeTextPrinting.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/time/tck/java/time/format/TCKDateTimeTextPrinting.java	Wed Jul 05 19:11:53 2017 +0200
@@ -157,23 +157,6 @@
 
     //-----------------------------------------------------------------------
     @Test
-    public void test_print_appendText2arg_french_long() throws Exception {
-        DateTimeFormatter f = builder.appendText(MONTH_OF_YEAR, TextStyle.FULL).toFormatter(Locale.FRENCH);
-        LocalDateTime dt = LocalDateTime.of(2010, 1, 1, 0, 0);
-        String text = f.format(dt);
-        assertEquals(text, "janvier");
-    }
-
-    @Test
-    public void test_print_appendText2arg_french_short() throws Exception {
-        DateTimeFormatter f = builder.appendText(MONTH_OF_YEAR, TextStyle.SHORT).toFormatter(Locale.FRENCH);
-        LocalDateTime dt = LocalDateTime.of(2010, 1, 1, 0, 0);
-        String text = f.format(dt);
-        assertEquals(text, "janv.");
-    }
-
-    //-----------------------------------------------------------------------
-    @Test
     public void test_appendTextMap() throws Exception {
         Map<Long, String> map = new HashMap<Long, String>();
         map.put(1L, "JNY");
--- a/jdk/test/java/time/test/java/time/TestLocalTime.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/time/test/java/time/TestLocalTime.java	Wed Jul 05 19:11:53 2017 +0200
@@ -61,7 +61,9 @@
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
 
+import java.time.Clock;
 import java.time.LocalTime;
 
 import org.testng.annotations.Test;
@@ -71,6 +73,9 @@
  */
 @Test
 public class TestLocalTime extends AbstractTest {
+    static final long NANOS_PER_SECOND = 1_000_000_000L;
+    static final long NANOS_PER_MINUTE = 60 * NANOS_PER_SECOND;
+    static final long NANOS_PER_DAY = 24 * 60 * NANOS_PER_MINUTE;
 
     //-----------------------------------------------------------------------
     @Test
@@ -176,4 +181,31 @@
         }
     }
 
+    //-----------------------------------------------------------------------
+    // now()
+    //-----------------------------------------------------------------------
+    @Test
+    @SuppressWarnings("unused")
+    public void now() {
+        // Warmup the TimeZone data so the following test does not include
+        // one-time initialization
+        LocalTime.now(Clock.systemDefaultZone());
+
+        long diff = Integer.MAX_VALUE;
+        for (int i = 0; i < 2; i++) {
+            LocalTime expected = LocalTime.now(Clock.systemDefaultZone());
+            LocalTime test = LocalTime.now();
+            diff = test.toNanoOfDay() - expected.toNanoOfDay();
+            // Normalize for wrap-around midnight
+            diff = Math.floorMod(NANOS_PER_DAY + diff, NANOS_PER_DAY);
+            if (diff < 100000000) {
+                break;
+            }
+            // A second iteration may be needed if the clock changed
+            // due to a DST change between the two calls to now.
+        }
+        assertTrue(diff < 100000000,   // less than 0.1 sec
+                "LocalTime.now  vs LocalTime.now(Clock.systemDefaultZone()) not close");
+    }
+
 }
--- a/jdk/test/java/util/Arrays/SetAllTest.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/util/Arrays/SetAllTest.java	Wed Jul 05 19:11:53 2017 +0200
@@ -167,13 +167,13 @@
     public void testStringSetNulls() {
         String[] ar = new String[2];
         try {
-            Arrays.setAll(null, i -> "X");
+            Arrays.setAll(null, (IntFunction<String>) i -> "X");
             fail("Arrays.setAll(null, foo) should throw NPE");
         } catch (NullPointerException npe) {
             // expected
         }
         try {
-            Arrays.parallelSetAll(null, i -> "X");
+            Arrays.parallelSetAll(null, (IntFunction<String>) i -> "X");
             fail("Arrays.parallelSetAll(null, foo) should throw NPE");
         } catch (NullPointerException npe) {
             // expected
--- a/jdk/test/java/util/Collection/CollectionDefaults.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/util/Collection/CollectionDefaults.java	Wed Jul 05 19:11:53 2017 +0200
@@ -21,15 +21,19 @@
  * questions.
  */
 
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
 
+import java.util.SortedSet;
+
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 
@@ -38,43 +42,68 @@
 
 import java.util.TreeMap;
 import java.util.TreeSet;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentSkipListMap;
 import java.util.function.Predicate;
+import java.util.function.Supplier;
 
 /**
  * @test
+ * @summary Unit tests for extension methods on Collection
  * @library testlibrary
- * @build CollectionAsserts CollectionSupplier
+ * @build CollectionAsserts CollectionSupplier ExtendsAbstractSet ExtendsAbstractCollection
  * @run testng CollectionDefaults
- * @summary Unit tests for extension methods on Collection
  */
 public class CollectionDefaults {
 
     public static final Predicate<Integer> pEven = x -> 0 == x % 2;
     public static final Predicate<Integer> pOdd = x -> 1 == x % 2;
 
-    private static final String[] SET_CLASSES = {
-        "java.util.HashSet",
-        "java.util.LinkedHashSet",
-        "java.util.TreeSet"
+    @SuppressWarnings("unchecked")
+    private static final Supplier<?>[] TEST_CLASSES = {
+        // Collection
+        ExtendsAbstractCollection<Integer>::new,
+
+        // Lists
+        java.util.ArrayList<Integer>::new,
+        java.util.LinkedList<Integer>::new,
+        java.util.Vector<Integer>::new,
+        java.util.concurrent.CopyOnWriteArrayList<Integer>::new,
+        ExtendsAbstractList<Integer>::new,
+
+        // Sets
+        java.util.HashSet<Integer>::new,
+        java.util.LinkedHashSet<Integer>::new,
+        java.util.TreeSet<Integer>::new,
+        java.util.concurrent.ConcurrentSkipListSet<Integer>::new,
+        java.util.concurrent.CopyOnWriteArraySet<Integer>::new,
+        ExtendsAbstractSet<Integer>::new
     };
 
     private static final int SIZE = 100;
 
     @DataProvider(name="setProvider", parallel=true)
-    public static Object[][] setCases() {
+    public static Iterator<Object[]> setCases() {
         final List<Object[]> cases = new LinkedList<>();
         cases.add(new Object[] { new HashSet<>() });
         cases.add(new Object[] { new LinkedHashSet<>() });
         cases.add(new Object[] { new TreeSet<>() });
+        cases.add(new Object[] { new java.util.concurrent.ConcurrentSkipListSet<>() });
+        cases.add(new Object[] { new java.util.concurrent.CopyOnWriteArraySet<>() });
+
+        cases.add(new Object[] { new ExtendsAbstractSet<>() });
 
         cases.add(new Object[] { Collections.newSetFromMap(new HashMap<>()) });
         cases.add(new Object[] { Collections.newSetFromMap(new LinkedHashMap()) });
         cases.add(new Object[] { Collections.newSetFromMap(new TreeMap<>()) });
+        cases.add(new Object[] { Collections.newSetFromMap(new ConcurrentHashMap<>()) });
+        cases.add(new Object[] { Collections.newSetFromMap(new ConcurrentSkipListMap<>()) });
 
-        cases.add(new Object[] { new HashSet(){{add(42);}} });
-        cases.add(new Object[] { new LinkedHashSet(){{add(42);}} });
-        cases.add(new Object[] { new TreeSet(){{add(42);}} });
-        return cases.toArray(new Object[0][cases.size()]);
+        cases.add(new Object[] { new HashSet<Integer>(){{add(42);}} });
+        cases.add(new Object[] { new ExtendsAbstractSet<Integer>(){{add(42);}} });
+        cases.add(new Object[] { new LinkedHashSet<Integer>(){{add(42);}} });
+        cases.add(new Object[] { new TreeSet<Integer>(){{add(42);}} });
+        return cases.iterator();
     }
 
     @Test(dataProvider = "setProvider")
@@ -82,57 +111,66 @@
         try {
             set.forEach(null);
             fail("expected NPE not thrown");
-        } catch (NullPointerException npe) {}
+        } catch (NullPointerException expected) {
+                ; // expected
+            }
         try {
             set.removeIf(null);
             fail("expected NPE not thrown");
-        } catch (NullPointerException npe) {}
+        } catch (NullPointerException expected) {
+               ; // expected
+        }
     }
 
     @Test
     public void testForEach() throws Exception {
-        final CollectionSupplier supplier = new CollectionSupplier(SET_CLASSES, SIZE);
-        for (final CollectionSupplier.TestCase test : supplier.get()) {
-            final Set<Integer> original = ((Set<Integer>) test.original);
-            final Set<Integer> set = ((Set<Integer>) test.collection);
+        final CollectionSupplier<Collection<Integer>> supplier = new CollectionSupplier((Supplier<Collection<Integer>>[]) TEST_CLASSES, SIZE);
+
+        for (final CollectionSupplier.TestCase<Collection<Integer>> test : supplier.get()) {
+            final Collection<Integer> original = test.expected;
+            final Collection<Integer> set = test.collection;
 
             try {
                 set.forEach(null);
                 fail("expected NPE not thrown");
-            } catch (NullPointerException npe) {}
-            if (test.className.equals("java.util.HashSet")) {
-                CollectionAsserts.assertContentsUnordered(set, original);
+            } catch (NullPointerException expected) {
+                ; // expected
+            }
+            if (set instanceof Set && !((set instanceof SortedSet) || (set instanceof LinkedHashSet))) {
+                CollectionAsserts.assertContentsUnordered(set, original, test.toString());
             } else {
-                CollectionAsserts.assertContents(set, original);
+                CollectionAsserts.assertContents(set, original, test.toString());
             }
 
             final List<Integer> actual = new LinkedList<>();
             set.forEach(actual::add);
-            if (test.className.equals("java.util.HashSet")) {
-                CollectionAsserts.assertContentsUnordered(actual, set);
-                CollectionAsserts.assertContentsUnordered(actual, original);
+            if (set instanceof Set && !((set instanceof SortedSet) || (set instanceof LinkedHashSet))) {
+                CollectionAsserts.assertContentsUnordered(actual, set, test.toString());
+                CollectionAsserts.assertContentsUnordered(actual, original, test.toString());
             } else {
-                CollectionAsserts.assertContents(actual, set);
-                CollectionAsserts.assertContents(actual, original);
+                CollectionAsserts.assertContents(actual, set, test.toString());
+                CollectionAsserts.assertContents(actual, original, test.toString());
             }
         }
     }
 
     @Test
     public void testRemoveIf() throws Exception {
-        final CollectionSupplier supplier = new CollectionSupplier(SET_CLASSES, SIZE);
-        for (final CollectionSupplier.TestCase test : supplier.get()) {
-            final Set<Integer> original = ((Set<Integer>) test.original);
-            final Set<Integer> set = ((Set<Integer>) test.collection);
+        final CollectionSupplier<Collection<Integer>> supplier = new CollectionSupplier((Supplier<Collection<Integer>>[]) TEST_CLASSES, SIZE);
+        for (final CollectionSupplier.TestCase<Collection<Integer>> test : supplier.get()) {
+            final Collection<Integer> original = test.expected;
+            final Collection<Integer> set = test.collection;
 
             try {
                 set.removeIf(null);
                 fail("expected NPE not thrown");
-            } catch (NullPointerException npe) {}
-            if (test.className.equals("java.util.HashSet")) {
-                CollectionAsserts.assertContentsUnordered(set, original);
+            } catch (NullPointerException expected) {
+                ; // expected
+            }
+            if (set instanceof Set && !((set instanceof SortedSet) || (set instanceof LinkedHashSet))) {
+                CollectionAsserts.assertContentsUnordered(set, original, test.toString());
             } else {
-                CollectionAsserts.assertContents(set, original);
+                CollectionAsserts.assertContents(set, original, test.toString());
             }
 
             set.removeIf(pEven);
--- a/jdk/test/java/util/Collection/ListDefaults.java	Tue Sep 17 08:08:07 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,536 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.LinkedList;
-import java.util.Stack;
-import java.util.TreeMap;
-import java.util.TreeSet;
-import java.util.Vector;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.testng.annotations.DataProvider;
-import org.testng.annotations.Test;
-
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertFalse;
-import static org.testng.Assert.assertTrue;
-import static org.testng.Assert.fail;
-
-import java.lang.reflect.Constructor;
-import java.util.ConcurrentModificationException;
-import java.util.function.Predicate;
-
-/**
- * @test
- * @bug 8023367
- * @library testlibrary
- * @build CollectionAsserts CollectionSupplier
- * @run testng ListDefaults
- * @summary Unit tests for extension methods on List
- */
-public class ListDefaults {
-
-    private static final String[] LIST_CLASSES = {
-        "java.util.ArrayList",
-        "java.util.LinkedList",
-        "java.util.Vector",
-        "java.util.concurrent.CopyOnWriteArrayList"
-    };
-
-    private static final String[] LIST_CME_CLASSES = {
-        "java.util.ArrayList",
-        "java.util.Vector"
-    };
-
-    private static final Predicate<Integer> pEven = x -> 0 == x % 2;
-    private static final Predicate<Integer> pOdd = x -> 1 == x % 2;
-
-    private static final Comparator<Integer> BIT_COUNT_COMPARATOR =
-            (x, y) -> Integer.bitCount(x) - Integer.bitCount(y);
-
-    private static final Comparator<AtomicInteger> ATOMIC_INTEGER_COMPARATOR =
-            (x, y) -> x.intValue() - y.intValue();
-
-    private static final int SIZE = 100;
-    private static final int SUBLIST_FROM = 20;
-    private static final int SUBLIST_TO = SIZE - 5;
-    private static final int SUBLIST_SIZE = SUBLIST_TO - SUBLIST_FROM;
-
-    private static interface Callback {
-        void call(List<Integer> list);
-    }
-
-    // call the callback for each recursive subList
-    private void trimmedSubList(final List<Integer> list, final Callback callback) {
-        int size = list.size();
-        if (size > 1) {
-            // trim 1 element from both ends
-            final List<Integer> subList = list.subList(1, size - 1);
-            callback.call(subList);
-            trimmedSubList(subList, callback);
-        }
-    }
-
-    @DataProvider(name="listProvider", parallel=true)
-    public static Object[][] listCases() {
-        final List<Object[]> cases = new LinkedList<>();
-        cases.add(new Object[] { Collections.emptyList() });
-        cases.add(new Object[] { new ArrayList<>() });
-        cases.add(new Object[] { new LinkedList<>() });
-        cases.add(new Object[] { new Vector<>() });
-        cases.add(new Object[] { new Stack<>() });
-        cases.add(new Object[] { new CopyOnWriteArrayList<>() });
-
-        cases.add(new Object[] { new ArrayList(){{add(42);}} });
-        cases.add(new Object[] { new LinkedList(){{add(42);}} });
-        cases.add(new Object[] { new Vector(){{add(42);}} });
-        cases.add(new Object[] { new Stack(){{add(42);}} });
-        cases.add(new Object[] { new CopyOnWriteArrayList(){{add(42);}} });
-        return cases.toArray(new Object[0][cases.size()]);
-    }
-
-    @Test(dataProvider = "listProvider")
-    public void testProvidedWithNull(final List<Integer> list) throws Exception {
-        try {
-            list.forEach(null);
-            fail("expected NPE not thrown");
-        } catch (NullPointerException npe) {}
-        try {
-            list.replaceAll(null);
-            fail("expected NPE not thrown");
-        } catch (NullPointerException npe) {}
-        try {
-            list.removeIf(null);
-            fail("expected NPE not thrown");
-        } catch (NullPointerException npe) {}
-        try {
-            list.sort(null);
-        } catch (Throwable t) {
-            fail("Exception not expected: " + t);
-        }
-    }
-
-    @Test
-    public void testForEach() throws Exception {
-        final CollectionSupplier supplier = new CollectionSupplier(LIST_CLASSES, SIZE);
-        for (final CollectionSupplier.TestCase test : supplier.get()) {
-            final List<Integer> original = ((List<Integer>) test.original);
-            final List<Integer> list = ((List<Integer>) test.collection);
-        }
-        for (final CollectionSupplier.TestCase test : supplier.get()) {
-            final List<Integer> original = ((List<Integer>) test.original);
-            final List<Integer> list = ((List<Integer>) test.collection);
-
-            try {
-                list.forEach(null);
-                fail("expected NPE not thrown");
-            } catch (NullPointerException npe) {}
-            CollectionAsserts.assertContents(list, original);
-
-            final List<Integer> actual = new LinkedList<>();
-            list.forEach(actual::add);
-            CollectionAsserts.assertContents(actual, list);
-            CollectionAsserts.assertContents(actual, original);
-
-            if (original.size() > SUBLIST_SIZE) {
-                final List<Integer> subList = original.subList(SUBLIST_FROM, SUBLIST_TO);
-                final List<Integer> actualSubList = new LinkedList<>();
-                subList.forEach(actualSubList::add);
-                assertEquals(actualSubList.size(), SUBLIST_SIZE);
-                for (int i = 0; i < SUBLIST_SIZE; i++) {
-                    assertEquals(actualSubList.get(i), original.get(i + SUBLIST_FROM));
-                }
-            }
-
-            trimmedSubList(list, new Callback() {
-                @Override
-                public void call(final List<Integer> list) {
-                    final List<Integer> actual = new LinkedList<>();
-                    list.forEach(actual::add);
-                    CollectionAsserts.assertContents(actual, list);
-                }
-            });
-        }
-    }
-
-    @Test
-    public void testRemoveIf() throws Exception {
-        final CollectionSupplier supplier = new CollectionSupplier(LIST_CLASSES, SIZE);
-
-        for (final CollectionSupplier.TestCase test : supplier.get()) {
-            final List<Integer> original = ((List<Integer>) test.original);
-            final List<Integer> list = ((List<Integer>) test.collection);
-
-            try {
-                list.removeIf(null);
-                fail("expected NPE not thrown");
-            } catch (NullPointerException npe) {}
-            CollectionAsserts.assertContents(list, original);
-
-            final AtomicInteger offset = new AtomicInteger(1);
-            while (list.size() > 0) {
-                removeFirst(original, list, offset);
-            }
-        }
-
-        for (final CollectionSupplier.TestCase test : supplier.get()) {
-            final List<Integer> original = ((List<Integer>) test.original);
-            final List<Integer> list = ((List<Integer>) test.collection);
-            list.removeIf(pOdd);
-            for (int i : list) {
-                assertTrue((i % 2) == 0);
-            }
-            for (int i : original) {
-                if (i % 2 == 0) {
-                    assertTrue(list.contains(i));
-                }
-            }
-            list.removeIf(pEven);
-            assertTrue(list.isEmpty());
-        }
-
-        for (final CollectionSupplier.TestCase test : supplier.get()) {
-            final List<Integer> original = ((List<Integer>) test.original);
-            final List<Integer> list = ((List<Integer>) test.collection);
-            final List<Integer> listCopy = new ArrayList<>(list);
-            if (original.size() > SUBLIST_SIZE) {
-                final List<Integer> subList = list.subList(SUBLIST_FROM, SUBLIST_TO);
-                final List<Integer> subListCopy = new ArrayList<>(subList);
-                listCopy.removeAll(subList);
-                subList.removeIf(pOdd);
-                for (int i : subList) {
-                    assertTrue((i % 2) == 0);
-                }
-                for (int i : subListCopy) {
-                    if (i % 2 == 0) {
-                        assertTrue(subList.contains(i));
-                    } else {
-                        assertFalse(subList.contains(i));
-                    }
-                }
-                subList.removeIf(pEven);
-                assertTrue(subList.isEmpty());
-                // elements outside the view should remain
-                CollectionAsserts.assertContents(list, listCopy);
-            }
-        }
-
-        for (final CollectionSupplier.TestCase test : supplier.get()) {
-            final List<Integer> list = ((List<Integer>) test.collection);
-            trimmedSubList(list, new Callback() {
-                @Override
-                public void call(final List<Integer> list) {
-                    final List<Integer> copy = new ArrayList<>(list);
-                    list.removeIf(pOdd);
-                    for (int i : list) {
-                        assertTrue((i % 2) == 0);
-                    }
-                    for (int i : copy) {
-                        if (i % 2 == 0) {
-                            assertTrue(list.contains(i));
-                        } else {
-                            assertFalse(list.contains(i));
-                        }
-                    }
-                }
-            });
-        }
-    }
-
-    // remove the first element
-    private void removeFirst(final List<Integer> original, final List<Integer> list, final AtomicInteger offset) {
-        final AtomicBoolean first = new AtomicBoolean(true);
-        list.removeIf(x -> first.getAndSet(false));
-        CollectionAsserts.assertContents(original.subList(offset.getAndIncrement(), original.size()), list);
-    }
-
-    @Test
-    public void testReplaceAll() throws Exception {
-        final int scale = 3;
-        final CollectionSupplier supplier = new CollectionSupplier(LIST_CLASSES, SIZE);
-        for (final CollectionSupplier.TestCase test : supplier.get()) {
-            final List<Integer> original = ((List<Integer>) test.original);
-            final List<Integer> list = ((List<Integer>) test.collection);
-
-            try {
-                list.replaceAll(null);
-                fail("expected NPE not thrown");
-            } catch (NullPointerException npe) {}
-            CollectionAsserts.assertContents(list, original);
-
-            list.replaceAll(x -> scale * x);
-            for (int i=0; i < original.size(); i++) {
-                assertTrue(list.get(i) == (scale * original.get(i)), "mismatch at index " + i);
-            }
-
-            if (original.size() > SUBLIST_SIZE) {
-                final List<Integer> subList = list.subList(SUBLIST_FROM, SUBLIST_TO);
-                subList.replaceAll(x -> x + 1);
-                // verify elements in view [from, to) were replaced
-                for (int i = 0; i < SUBLIST_SIZE; i++) {
-                    assertTrue(subList.get(i) == ((scale * original.get(i + SUBLIST_FROM)) + 1),
-                            "mismatch at sublist index " + i);
-                }
-                // verify that elements [0, from) remain unmodified
-                for (int i = 0; i < SUBLIST_FROM; i++) {
-                    assertTrue(list.get(i) == (scale * original.get(i)),
-                            "mismatch at original index " + i);
-                }
-                // verify that elements [to, size) remain unmodified
-                for (int i = SUBLIST_TO; i < list.size(); i++) {
-                    assertTrue(list.get(i) == (scale * original.get(i)),
-                            "mismatch at original index " + i);
-                }
-            }
-        }
-
-        for (final CollectionSupplier.TestCase test : supplier.get()) {
-            final List<Integer> list = ((List<Integer>) test.collection);
-            trimmedSubList(list, new Callback() {
-                @Override
-                public void call(final List<Integer> list) {
-                    final List<Integer> copy = new ArrayList<>(list);
-                    final int offset = 5;
-                    list.replaceAll(x -> offset + x);
-                    for (int i=0; i < copy.size(); i++) {
-                        assertTrue(list.get(i) == (offset + copy.get(i)), "mismatch at index " + i);
-                    }
-                }
-            });
-        }
-    }
-
-    @Test
-    public void testSort() throws Exception {
-        final CollectionSupplier supplier = new CollectionSupplier(LIST_CLASSES, SIZE);
-        for (final CollectionSupplier.TestCase test : supplier.get()) {
-            final List<Integer> original = ((List<Integer>) test.original);
-            final List<Integer> list = ((List<Integer>) test.collection);
-            CollectionSupplier.shuffle(list);
-            list.sort(Integer::compare);
-            CollectionAsserts.assertSorted(list, Integer::compare);
-            if (test.name.startsWith("reverse")) {
-                Collections.reverse(list);
-            }
-            CollectionAsserts.assertContents(list, original);
-
-            CollectionSupplier.shuffle(list);
-            list.sort(null);
-            CollectionAsserts.assertSorted(list, Comparator.<Integer>naturalOrder());
-            if (test.name.startsWith("reverse")) {
-                Collections.reverse(list);
-            }
-            CollectionAsserts.assertContents(list, original);
-
-            CollectionSupplier.shuffle(list);
-            list.sort(Comparator.<Integer>naturalOrder());
-            CollectionAsserts.assertSorted(list, Comparator.<Integer>naturalOrder());
-            if (test.name.startsWith("reverse")) {
-                Collections.reverse(list);
-            }
-            CollectionAsserts.assertContents(list, original);
-
-            CollectionSupplier.shuffle(list);
-            list.sort(Comparator.<Integer>reverseOrder());
-            CollectionAsserts.assertSorted(list, Comparator.<Integer>reverseOrder());
-            if (!test.name.startsWith("reverse")) {
-                Collections.reverse(list);
-            }
-            CollectionAsserts.assertContents(list, original);
-
-            CollectionSupplier.shuffle(list);
-            list.sort(BIT_COUNT_COMPARATOR);
-            CollectionAsserts.assertSorted(list, BIT_COUNT_COMPARATOR);
-            // check sort by verifying that bitCount increases and never drops
-            int minBitCount = 0;
-            int bitCount = 0;
-            for (final Integer i : list) {
-                bitCount = Integer.bitCount(i);
-                assertTrue(bitCount >= minBitCount);
-                minBitCount = bitCount;
-            }
-
-            @SuppressWarnings("unchecked")
-            final Class<? extends List<AtomicInteger>> type =
-                    (Class<? extends List<AtomicInteger>>) Class.forName(test.className);
-            final Constructor<? extends List<AtomicInteger>> defaultConstructor = type.getConstructor();
-            final List<AtomicInteger> incomparables = (List<AtomicInteger>) defaultConstructor.newInstance();
-
-            for (int i=0; i < test.original.size(); i++) {
-                incomparables.add(new AtomicInteger(i));
-            }
-            CollectionSupplier.shuffle(incomparables);
-            incomparables.sort(ATOMIC_INTEGER_COMPARATOR);
-            for (int i=0; i < test.original.size(); i++) {
-                assertEquals(i, incomparables.get(i).intValue());
-            }
-
-            if (original.size() > SUBLIST_SIZE) {
-                final List<Integer> copy = new ArrayList<>(list);
-                final List<Integer> subList = list.subList(SUBLIST_FROM, SUBLIST_TO);
-                CollectionSupplier.shuffle(subList);
-                subList.sort(Comparator.<Integer>naturalOrder());
-                CollectionAsserts.assertSorted(subList, Comparator.<Integer>naturalOrder());
-                // verify that elements [0, from) remain unmodified
-                for (int i = 0; i < SUBLIST_FROM; i++) {
-                    assertTrue(list.get(i) == copy.get(i),
-                            "mismatch at index " + i);
-                }
-                // verify that elements [to, size) remain unmodified
-                for (int i = SUBLIST_TO; i < list.size(); i++) {
-                    assertTrue(list.get(i) == copy.get(i),
-                            "mismatch at index " + i);
-                }
-            }
-        }
-
-        for (final CollectionSupplier.TestCase test : supplier.get()) {
-            final List<Integer> list = ((List<Integer>) test.collection);
-            trimmedSubList(list, new Callback() {
-                @Override
-                public void call(final List<Integer> list) {
-                    final List<Integer> copy = new ArrayList<>(list);
-                    CollectionSupplier.shuffle(list);
-                    list.sort(Comparator.<Integer>naturalOrder());
-                    CollectionAsserts.assertSorted(list, Comparator.<Integer>naturalOrder());
-                }
-            });
-        }
-    }
-
-    @Test
-    public void testForEachThrowsCME() throws Exception {
-        final CollectionSupplier supplier = new CollectionSupplier(LIST_CME_CLASSES, SIZE);
-        for (final CollectionSupplier.TestCase test : supplier.get()) {
-            final List<Integer> list = ((List<Integer>) test.collection);
-            if (list.size() <= 1) {
-                continue;
-            }
-            boolean gotException = false;
-            try {
-                // bad predicate that modifies its list, should throw CME
-                list.forEach((x) -> {list.add(x);});
-            } catch (ConcurrentModificationException cme) {
-                gotException = true;
-            }
-            if (!gotException) {
-                fail("expected CME was not thrown from " + test);
-            }
-        }
-    }
-
-    @Test
-    public void testRemoveIfThrowsCME() throws Exception {
-        final CollectionSupplier supplier = new CollectionSupplier(LIST_CME_CLASSES, SIZE);
-        for (final CollectionSupplier.TestCase test : supplier.get()) {
-            final List<Integer> list = ((List<Integer>) test.collection);
-            if (list.size() <= 1) {
-                continue;
-            }
-            boolean gotException = false;
-            try {
-                // bad predicate that modifies its list, should throw CME
-                list.removeIf((x) -> {return list.add(x);});
-            } catch (ConcurrentModificationException cme) {
-                gotException = true;
-            }
-            if (!gotException) {
-                fail("expected CME was not thrown from " + test);
-            }
-        }
-    }
-
-    @Test
-    public void testReplaceAllThrowsCME() throws Exception {
-        final CollectionSupplier supplier = new CollectionSupplier(LIST_CME_CLASSES, SIZE);
-        for (final CollectionSupplier.TestCase test : supplier.get()) {
-            final List<Integer> list = ((List<Integer>) test.collection);
-            if (list.size() <= 1) {
-                continue;
-            }
-            boolean gotException = false;
-            try {
-                // bad predicate that modifies its list, should throw CME
-                list.replaceAll(x -> {int n = 3 * x; list.add(n); return n;});
-            } catch (ConcurrentModificationException cme) {
-                gotException = true;
-            }
-            if (!gotException) {
-                fail("expected CME was not thrown from " + test);
-            }
-        }
-    }
-
-    @Test
-    public void testSortThrowsCME() throws Exception {
-        final CollectionSupplier supplier = new CollectionSupplier(LIST_CME_CLASSES, SIZE);
-        for (final CollectionSupplier.TestCase test : supplier.get()) {
-            final List<Integer> list = ((List<Integer>) test.collection);
-            if (list.size() <= 1) {
-                continue;
-            }
-            boolean gotException = false;
-            try {
-                // bad predicate that modifies its list, should throw CME
-                list.sort((x, y) -> {list.add(x); return x - y;});
-            } catch (ConcurrentModificationException cme) {
-                gotException = true;
-            }
-            if (!gotException) {
-                fail("expected CME was not thrown from " + test);
-            }
-        }
-    }
-
-    private static final List<Integer> SLICED_EXPECTED = Arrays.asList(0, 1, 2, 3, 5, 6, 7, 8, 9);
-    private static final List<Integer> SLICED_EXPECTED2 = Arrays.asList(0, 1, 2, 5, 6, 7, 8, 9);
-
-    @DataProvider(name="shortIntListProvider", parallel=true)
-    public static Object[][] intListCases() {
-        final Integer[] DATA = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
-        final List<Object[]> cases = new LinkedList<>();
-        cases.add(new Object[] { new ArrayList<>(Arrays.asList(DATA)) });
-        cases.add(new Object[] { new LinkedList<>(Arrays.asList(DATA)) });
-        cases.add(new Object[] { new Vector<>(Arrays.asList(DATA)) });
-        cases.add(new Object[] { new CopyOnWriteArrayList<>(Arrays.asList(DATA)) });
-        return cases.toArray(new Object[0][cases.size()]);
-    }
-
-    @Test(dataProvider = "shortIntListProvider")
-    public void testRemoveIfFromSlice(final List<Integer> list) throws Exception {
-        final List<Integer> sublist = list.subList(3, 6);
-        assertTrue(sublist.removeIf(x -> x == 4));
-        CollectionAsserts.assertContents(list, SLICED_EXPECTED);
-
-        final List<Integer> sublist2 = list.subList(2, 5);
-        assertTrue(sublist2.removeIf(x -> x == 3));
-        CollectionAsserts.assertContents(list, SLICED_EXPECTED2);
-    }
-}
--- a/jdk/test/java/util/Collection/MOAT.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/util/Collection/MOAT.java	Wed Jul 05 19:11:53 2017 +0200
@@ -400,8 +400,6 @@
     // If add(null) succeeds, contains(null) & remove(null) should succeed
     //----------------------------------------------------------------
     private static void testNullElement(Collection<Integer> c) {
-        // !!!! 5018849: (coll) TreeSet.contains(null) does not agree with Javadoc
-        if (c instanceof TreeSet) return;
 
         try {
             check(c.add(null));
--- a/jdk/test/java/util/Collection/testlibrary/CollectionAsserts.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/util/Collection/testlibrary/CollectionAsserts.java	Wed Jul 05 19:11:53 2017 +0200
@@ -41,6 +41,10 @@
  */
 public class CollectionAsserts {
 
+    private CollectionAsserts() {
+        // no instances
+    }
+
     public static void assertCountSum(Iterable<? super Integer> it, int count, int sum) {
         assertCountSum(it.iterator(), count, sum);
     }
@@ -117,10 +121,18 @@
     }
 
     public static<T> void assertContents(Iterable<T> actual, Iterable<T> expected) {
-        assertContents(actual.iterator(), expected.iterator());
+        assertContents(actual, expected, null);
+    }
+
+    public static<T> void assertContents(Iterable<T> actual, Iterable<T> expected, String msg) {
+        assertContents(actual.iterator(), expected.iterator(), msg);
     }
 
     public static<T> void assertContents(Iterator<T> actual, Iterator<T> expected) {
+        assertContents(actual, expected, null);
+    }
+
+    public static<T> void assertContents(Iterator<T> actual, Iterator<T> expected, String msg) {
         List<T> history = new ArrayList<>();
 
         while (expected.hasNext()) {
@@ -128,20 +140,23 @@
                 List<T> expectedData = new ArrayList<>(history);
                 while (expected.hasNext())
                     expectedData.add(expected.next());
-                fail(String.format("Premature end of data; expected=%s, found=%s", expectedData, history));
+                fail(String.format("%s Premature end of data; expected=%s, found=%s",
+                    (msg == null ? "" : msg), expectedData, history));
             }
             T a = actual.next();
             T e = expected.next();
             history.add(a);
 
             if (!Objects.equals(a, e))
-                fail(String.format("Data mismatch; preceding=%s, nextExpected=%s, nextFound=%s", history, e, a));
+                fail(String.format("%s Data mismatch; preceding=%s, nextExpected=%s, nextFound=%s",
+                    (msg == null ? "" : msg), history, e, a));
         }
         if (actual.hasNext()) {
             List<T> rest = new ArrayList<>();
             while (actual.hasNext())
                 rest.add(actual.next());
-            fail(String.format("Unexpected data %s after %s", rest, history));
+            fail(String.format("%s Unexpected data %s after %s",
+                (msg == null ? "" : msg), rest, history));
         }
     }
 
@@ -151,30 +166,21 @@
         assertContents(actual, Arrays.asList(expected).iterator());
     }
 
-    public static <T> boolean equalsContentsUnordered(Iterable<T> a, Iterable<T> b) {
-        Set<T> sa = new HashSet<>();
-        for (T t : a) {
-            sa.add(t);
-        }
+    public static<T extends Comparable<? super T>> void assertContentsUnordered(Iterable<T> actual, Iterable<T> expected) {
+        assertContentsUnordered(actual, expected, null);
+    }
 
-        Set<T> sb = new HashSet<>();
-        for (T t : b) {
-            sb.add(t);
+    public static<T extends Comparable<? super T>> void assertContentsUnordered(Iterable<T> actual, Iterable<T> expected, String msg) {
+        List<T> allExpected = new ArrayList<>();
+        for (T t : expected) {
+            allExpected.add(t);
         }
 
-        return Objects.equals(sa, sb);
-    }
+        for (T t : actual) {
+            assertTrue(allExpected.remove(t), msg + " element '" + String.valueOf(t) + "' not found");
+        }
 
-    public static<T extends Comparable<? super T>> void assertContentsUnordered(Iterable<T> actual, Iterable<T> expected) {
-        ArrayList<T> one = new ArrayList<>();
-        for (T t : actual)
-            one.add(t);
-        ArrayList<T> two = new ArrayList<>();
-        for (T t : expected)
-            two.add(t);
-        Collections.sort(one);
-        Collections.sort(two);
-        assertContents(one, two);
+        assertTrue(allExpected.isEmpty(), msg + "expected contained additional elements");
     }
 
     static <T> void assertSplitContents(Iterable<Iterable<T>> splits, Iterable<T> list) {
--- a/jdk/test/java/util/Collection/testlibrary/CollectionSupplier.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/util/Collection/testlibrary/CollectionSupplier.java	Wed Jul 05 19:11:53 2017 +0200
@@ -29,13 +29,11 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Random;
-import java.util.Set;
 
 import org.testng.TestException;
 
 import static org.testng.Assert.assertTrue;
 
-import java.lang.reflect.Constructor;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.function.Supplier;
@@ -44,15 +42,15 @@
  * @library
  * @summary A Supplier of test cases for Collection tests
  */
-public final class CollectionSupplier implements Supplier<Iterable<CollectionSupplier.TestCase>> {
+public final class CollectionSupplier<C extends Collection<Integer>> implements Supplier<Iterable<CollectionSupplier.TestCase<C>>> {
 
-    private final String[] classNames;
+    private final Supplier<C>[] classes;
     private final int size;
 
     /**
      * A Collection test case.
      */
-    public static final class TestCase {
+    public static final class TestCase<C extends Collection<Integer>> {
 
         /**
          * The name of the test case.
@@ -60,57 +58,45 @@
         public final String name;
 
         /**
-         * Class name of the instantiated Collection.
-         */
-        public final String className;
-
-        /**
          * Unmodifiable reference collection, useful for comparisons.
          */
-        public final Collection<Integer> original;
+        public final List<Integer> expected;
 
         /**
          * A modifiable test collection.
          */
-        public final Collection<Integer> collection;
+        public final C collection;
 
         /**
          * Create a Collection test case.
+         *
          * @param name name of the test case
-         * @param className class name of the instantiated collection
-         * @param original reference collection
+         * @param expected reference collection
          * @param collection the modifiable test collection
          */
-        public TestCase(String name, String className,
-                Collection<Integer> original, Collection<Integer> collection) {
+        public TestCase(String name, C collection) {
             this.name = name;
-            this.className = className;
-            this.original =
-                    List.class.isAssignableFrom(original.getClass()) ?
-                    Collections.unmodifiableList((List<Integer>) original) :
-                    Set.class.isAssignableFrom(original.getClass()) ?
-                    Collections.unmodifiableSet((Set<Integer>) original) :
-                    Collections.unmodifiableCollection(original);
+            this.expected = Collections.unmodifiableList(
+                Arrays.asList(collection.toArray(new Integer[0])));
             this.collection = collection;
         }
 
         @Override
         public String toString() {
-            return name + " " + className +
-                    "\n original: " + original +
-                    "\n   target: " + collection;
+            return name + " " + collection.getClass().toString();
         }
     }
 
     /**
      * Shuffle a list using a PRNG with known seed for repeatability
+     *
      * @param list the list to be shuffled
      */
     public static <E> void shuffle(final List<E> list) {
         // PRNG with known seed for repeatable tests
         final Random prng = new Random(13);
         final int size = list.size();
-        for (int i=0; i < size; i++) {
+        for (int i = 0; i < size; i++) {
             // random index in interval [i, size)
             final int j = i + prng.nextInt(size - i);
             // swap elements at indices i & j
@@ -127,178 +113,133 @@
      * @param classNames class names that implement {@code Collection}
      * @param size the desired size of each collection
      */
-    public CollectionSupplier(String[] classNames, int size) {
-        this.classNames = Arrays.copyOf(classNames, classNames.length);
+    public CollectionSupplier(Supplier<C>[] classes, int size) {
+        this.classes = Arrays.copyOf(classes, classes.length);
         this.size = size;
     }
 
     @Override
-    public Iterable<TestCase> get() {
-        try {
-            return getThrows();
-        } catch (Exception e) {
-            throw new TestException(e);
-        }
-    }
+    public Iterable<TestCase<C>> get() {
+        final Collection<TestCase<C>> cases = new LinkedList<>();
+        for (final Supplier<C> type : classes) {
+            try {
+                final Collection<Integer> empty = type.get();
+                cases.add(new TestCase("empty", empty));
 
-    private Iterable<TestCase> getThrows() throws Exception {
-        final Collection<TestCase> collections = new LinkedList<>();
-        for (final String className : classNames) {
-            @SuppressWarnings("unchecked")
-            final Class<? extends Collection<Integer>> type =
-                    (Class<? extends Collection<Integer>>) Class.forName(className);
-            final Constructor<? extends Collection<Integer>>
-                    defaultConstructor = type.getConstructor();
-            final Constructor<? extends Collection<Integer>>
-                    copyConstructor = type.getConstructor(Collection.class);
+                final Collection<Integer> single = type.get();
+                single.add(42);
+                cases.add(new TestCase("single", single));
 
-            final Collection<Integer> empty = defaultConstructor.newInstance();
-            collections.add(new TestCase("empty",
-                    className,
-                    copyConstructor.newInstance(empty),
-                    empty));
+                final Collection<Integer> regular = type.get();
+                for (int i = 0; i < size; i++) {
+                    regular.add(i);
+                }
+                cases.add(new TestCase("regular", regular));
 
-            final Collection<Integer> single = defaultConstructor.newInstance();
-            single.add(42);
-            collections.add(new TestCase("single",
-                    className,
-                    copyConstructor.newInstance(single),
-                    single));
-
-            final Collection<Integer> regular = defaultConstructor.newInstance();
-            for (int i=0; i < size; i++) {
-                regular.add(i);
-            }
-            collections.add(new TestCase("regular",
-                    className,
-                    copyConstructor.newInstance(regular),
-                    regular));
+                final Collection<Integer> reverse = type.get();
+                for (int i = size; i >= 0; i--) {
+                    reverse.add(i);
+                }
+                cases.add(new TestCase("reverse", reverse));
 
-            final Collection<Integer> reverse = defaultConstructor.newInstance();
-            for (int i=size; i >= 0; i--) {
-                reverse.add(i);
-            }
-            collections.add(new TestCase("reverse",
-                    className,
-                    copyConstructor.newInstance(reverse),
-                    reverse));
+                final Collection<Integer> odds = type.get();
+                for (int i = 0; i < size; i++) {
+                    odds.add((i * 2) + 1);
+                }
+                cases.add(new TestCase("odds", odds));
 
-            final Collection<Integer> odds = defaultConstructor.newInstance();
-            for (int i=0; i < size; i++) {
-                odds.add((i * 2) + 1);
-            }
-            collections.add(new TestCase("odds",
-                    className,
-                    copyConstructor.newInstance(odds),
-                    odds));
+                final Collection<Integer> evens = type.get();
+                for (int i = 0; i < size; i++) {
+                    evens.add(i * 2);
+                }
+                cases.add(new TestCase("evens", evens));
 
-            final Collection<Integer> evens = defaultConstructor.newInstance();
-            for (int i=0; i < size; i++) {
-                evens.add(i * 2);
-            }
-            collections.add(new TestCase("evens",
-                    className,
-                    copyConstructor.newInstance(evens),
-                    evens));
-
-            final Collection<Integer> fibonacci = defaultConstructor.newInstance();
-            int prev2 = 0;
-            int prev1 = 1;
-            for (int i=0; i < size; i++) {
-                final int n = prev1 + prev2;
-                if (n < 0) { // stop on overflow
-                    break;
+                final Collection<Integer> fibonacci = type.get();
+                int prev2 = 0;
+                int prev1 = 1;
+                for (int i = 0; i < size; i++) {
+                    final int n = prev1 + prev2;
+                    if (n < 0) { // stop on overflow
+                        break;
+                    }
+                    fibonacci.add(n);
+                    prev2 = prev1;
+                    prev1 = n;
                 }
-                fibonacci.add(n);
-                prev2 = prev1;
-                prev1 = n;
-            }
-            collections.add(new TestCase("fibonacci",
-                    className,
-                    copyConstructor.newInstance(fibonacci),
-                    fibonacci));
+                cases.add(new TestCase("fibonacci", fibonacci));
 
             // variants where the size of the backing storage != reported size
-            // created by removing half of the elements
+                // created by removing half of the elements
+                final Collection<Integer> emptyWithSlack = type.get();
+                emptyWithSlack.add(42);
+                assertTrue(emptyWithSlack.remove(42));
+                cases.add(new TestCase("emptyWithSlack", emptyWithSlack));
 
-            final Collection<Integer> emptyWithSlack = defaultConstructor.newInstance();
-            emptyWithSlack.add(42);
-            assertTrue(emptyWithSlack.remove(42));
-            collections.add(new TestCase("emptyWithSlack",
-                    className,
-                    copyConstructor.newInstance(emptyWithSlack),
-                    emptyWithSlack));
-
-            final Collection<Integer> singleWithSlack = defaultConstructor.newInstance();
-            singleWithSlack.add(42);
-            singleWithSlack.add(43);
-            assertTrue(singleWithSlack.remove(43));
-            collections.add(new TestCase("singleWithSlack",
-                    className,
-                    copyConstructor.newInstance(singleWithSlack),
-                    singleWithSlack));
+                final Collection<Integer> singleWithSlack = type.get();
+                singleWithSlack.add(42);
+                singleWithSlack.add(43);
+                assertTrue(singleWithSlack.remove(43));
+                cases.add(new TestCase("singleWithSlack", singleWithSlack));
 
-            final Collection<Integer> regularWithSlack = defaultConstructor.newInstance();
-            for (int i=0; i < (2 * size); i++) {
-                regularWithSlack.add(i);
-            }
-            assertTrue(regularWithSlack.removeIf((x) -> {return x >= size;}));
-            collections.add(new TestCase("regularWithSlack",
-                    className,
-                    copyConstructor.newInstance(regularWithSlack),
-                    regularWithSlack));
+                final Collection<Integer> regularWithSlack = type.get();
+                for (int i = 0; i < (2 * size); i++) {
+                    regularWithSlack.add(i);
+                }
+                assertTrue(regularWithSlack.removeIf((x) -> {
+                    return x >= size;
+                }));
+                cases.add(new TestCase("regularWithSlack", regularWithSlack));
 
-            final Collection<Integer> reverseWithSlack = defaultConstructor.newInstance();
-            for (int i=2 * size; i >= 0; i--) {
-                reverseWithSlack.add(i);
-            }
-            assertTrue(reverseWithSlack.removeIf((x) -> {return x < size;}));
-            collections.add(new TestCase("reverseWithSlack",
-                    className,
-                    copyConstructor.newInstance(reverseWithSlack),
-                    reverseWithSlack));
+                final Collection<Integer> reverseWithSlack = type.get();
+                for (int i = 2 * size; i >= 0; i--) {
+                    reverseWithSlack.add(i);
+                }
+                assertTrue(reverseWithSlack.removeIf((x) -> {
+                    return x < size;
+                }));
+                cases.add(new TestCase("reverseWithSlack", reverseWithSlack));
 
-            final Collection<Integer> oddsWithSlack = defaultConstructor.newInstance();
-            for (int i = 0; i < 2 * size; i++) {
-                oddsWithSlack.add((i * 2) + 1);
-            }
-            assertTrue(oddsWithSlack.removeIf((x) -> {return x >= size;}));
-            collections.add(new TestCase("oddsWithSlack",
-                    className,
-                    copyConstructor.newInstance(oddsWithSlack),
-                    oddsWithSlack));
+                final Collection<Integer> oddsWithSlack = type.get();
+                for (int i = 0; i < 2 * size; i++) {
+                    oddsWithSlack.add((i * 2) + 1);
+                }
+                assertTrue(oddsWithSlack.removeIf((x) -> {
+                    return x >= size;
+                }));
+                cases.add(new TestCase("oddsWithSlack", oddsWithSlack));
+
+                final Collection<Integer> evensWithSlack = type.get();
+                for (int i = 0; i < 2 * size; i++) {
+                    evensWithSlack.add(i * 2);
+                }
+                assertTrue(evensWithSlack.removeIf((x) -> {
+                    return x >= size;
+                }));
+                cases.add(new TestCase("evensWithSlack", evensWithSlack));
 
-            final Collection<Integer> evensWithSlack = defaultConstructor.newInstance();
-            for (int i = 0; i < 2 * size; i++) {
-                evensWithSlack.add(i * 2);
+                final Collection<Integer> fibonacciWithSlack = type.get();
+                prev2 = 0;
+                prev1 = 1;
+                for (int i = 0; i < size; i++) {
+                    final int n = prev1 + prev2;
+                    if (n < 0) { // stop on overflow
+                        break;
+                    }
+                    fibonacciWithSlack.add(n);
+                    prev2 = prev1;
+                    prev1 = n;
+                }
+                assertTrue(fibonacciWithSlack.removeIf((x) -> {
+                    return x < 20;
+                }));
+                cases.add(new TestCase("fibonacciWithSlack",
+                    fibonacciWithSlack));
+            } catch (Exception failed) {
+                throw new TestException(failed);
             }
-            assertTrue(evensWithSlack.removeIf((x) -> {return x >= size;}));
-            collections.add(new TestCase("evensWithSlack",
-                    className,
-                    copyConstructor.newInstance(evensWithSlack),
-                    evensWithSlack));
-
-            final Collection<Integer> fibonacciWithSlack = defaultConstructor.newInstance();
-            prev2 = 0;
-            prev1 = 1;
-            for (int i=0; i < size; i++) {
-                final int n = prev1 + prev2;
-                if (n < 0) { // stop on overflow
-                    break;
-                }
-                fibonacciWithSlack.add(n);
-                prev2 = prev1;
-                prev1 = n;
-            }
-            assertTrue(fibonacciWithSlack.removeIf((x) -> {return x < 20;}));
-            collections.add(new TestCase("fibonacciWithSlack",
-                    className,
-                    copyConstructor.newInstance(fibonacciWithSlack),
-                    fibonacciWithSlack));
-
         }
 
-        return collections;
+        return cases;
     }
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Collection/testlibrary/ExtendsAbstractCollection.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.util.AbstractCollection;
+import java.util.HashSet;
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.function.Supplier;
+
+/**
+ * @library
+ *
+ * A simple mutable collection implementation that provides only default
+ * implementations of all methods. ie. none of the Collection interface default
+ * methods have overridden implementations.
+ *
+ * @param <E> type of collection elements
+ */
+public class ExtendsAbstractCollection<E> extends AbstractCollection<E> {
+
+    protected final Collection<E> coll;
+
+    public ExtendsAbstractCollection() {
+        this(ArrayList<E>::new);
+    }
+
+    public ExtendsAbstractCollection(Collection<E> source) {
+        this();
+        coll.addAll(source);
+    }
+
+    protected ExtendsAbstractCollection(Supplier<Collection<E>> backer) {
+        this.coll = backer.get();
+    }
+
+    public boolean add(E element) {
+        return coll.add(element);
+    }
+
+    public boolean remove(Object element) {
+        return coll.remove(element);
+    }
+
+    public Iterator<E> iterator() {
+        return new Iterator<E>() {
+            Iterator<E> source = coll.iterator();
+
+            public boolean hasNext() {
+                return source.hasNext();
+            }
+
+            public E next() {
+                return source.next();
+            }
+
+            public void remove() {
+                source.remove();
+            }
+        };
+    }
+
+    public int size() {
+        return coll.size();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Collection/testlibrary/ExtendsAbstractList.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.util.ArrayList;
+import java.util.AbstractList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.function.Supplier;
+
+/**
+ * @library
+ *
+ * A simple mutable list implementation that provides only default
+ * implementations of all methods. ie. none of the List interface default
+ * methods have overridden implementations.
+ *
+ * @param <E> type of list elements
+ */
+public class ExtendsAbstractList<E> extends AbstractList<E> {
+
+    protected final List<E> list;
+
+    public ExtendsAbstractList() {
+        this(ArrayList<E>::new);
+    }
+
+    protected ExtendsAbstractList(Supplier<List<E>> supplier) {
+        this.list = supplier.get();
+    }
+
+    public ExtendsAbstractList(Collection<E> source) {
+        this();
+        addAll(source);
+    }
+
+    public boolean add(E element) {
+        return list.add(element);
+    }
+
+    public E get(int index) {
+        return list.get(index);
+    }
+
+    public boolean remove(Object element) {
+        return list.remove(element);
+    }
+
+    public E set(int index, E element) {
+        return list.set(index, element);
+    }
+
+    public void add(int index, E element) {
+        list.add(index, element);
+    }
+
+    public E remove(int index) {
+        return list.remove(index);
+    }
+
+    public Iterator<E> iterator() {
+        return new Iterator<E>() {
+            Iterator<E> source = list.iterator();
+
+            public boolean hasNext() {
+                return source.hasNext();
+            }
+
+            public E next() {
+                return source.next();
+            }
+
+            public void remove() {
+                source.remove();
+            }
+        };
+    }
+
+    public int size() {
+        return list.size();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Collection/testlibrary/ExtendsAbstractSet.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.util.HashSet;
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.function.Supplier;
+
+/**
+ * @library
+ *
+ * A simple mutable set implementation that provides only default
+ * implementations of all methods. ie. none of the Set interface default methods
+ * have overridden implementations.
+ *
+ * @param <E> type of set members
+ */
+public class ExtendsAbstractSet<E> extends AbstractSet<E> {
+
+    protected final Set<E> set;
+
+    public ExtendsAbstractSet() {
+        this(HashSet<E>::new);
+    }
+
+    public ExtendsAbstractSet(Collection<E> source) {
+        this();
+        addAll(source);
+    }
+
+    protected ExtendsAbstractSet(Supplier<Set<E>> backer) {
+        this.set = backer.get();
+    }
+
+    public boolean add(E element) {
+        return set.add(element);
+    }
+
+    public boolean remove(Object element) {
+        return set.remove(element);
+    }
+
+    public Iterator<E> iterator() {
+        return new Iterator<E>() {
+            Iterator<E> source = set.iterator();
+
+            public boolean hasNext() {
+                return source.hasNext();
+            }
+
+            public E next() {
+                return source.next();
+            }
+
+            public void remove() {
+                source.remove();
+            }
+        };
+    }
+
+    public int size() {
+        return set.size();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Collections/SingletonIterator.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @run testng SingletonIterator
+ */
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.fail;
+
+@Test(groups = "unit")
+public class SingletonIterator {
+    public void testForEachRemaining() {
+        Iterator<String> it = Collections.singleton("TheOne").iterator();
+        AtomicInteger cnt = new AtomicInteger(0);
+
+        it.forEachRemaining(s -> {
+            assertEquals("TheOne", s);
+            cnt.incrementAndGet();
+        });
+
+        assertEquals(cnt.get(), 1);
+        assertFalse(it.hasNext());
+
+        try {
+            String str = it.next();
+            fail("Should throw NoSuchElementException at end");
+        } catch (NoSuchElementException ex) {
+            // ignore;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/List/ListDefaults.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,535 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Stack;
+import java.util.Vector;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.lang.reflect.Constructor;
+import java.util.ConcurrentModificationException;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+/**
+ * @test
+ * @summary Unit tests for extension methods on List
+ * @bug 8023367
+ * @library ../Collection/testlibrary
+ * @build CollectionAsserts CollectionSupplier ExtendsAbstractList
+ * @run testng ListDefaults
+ */
+public class ListDefaults {
+
+    private static final Supplier<?>[] LIST_CLASSES = {
+        java.util.ArrayList::new,
+        java.util.LinkedList::new,
+        java.util.Vector::new,
+        java.util.concurrent.CopyOnWriteArrayList::new,
+        ExtendsAbstractList::new
+     };
+
+    private static final Supplier<?>[] LIST_CME_CLASSES = {
+        java.util.ArrayList::new,
+        java.util.Vector::new
+     };
+
+    private static final Predicate<Integer> pEven = x -> 0 == x % 2;
+    private static final Predicate<Integer> pOdd = x -> 1 == x % 2;
+
+    private static final Comparator<Integer> BIT_COUNT_COMPARATOR =
+            (x, y) -> Integer.bitCount(x) - Integer.bitCount(y);
+
+    private static final Comparator<AtomicInteger> ATOMIC_INTEGER_COMPARATOR =
+            (x, y) -> x.intValue() - y.intValue();
+
+    private static final int SIZE = 100;
+    private static final int SUBLIST_FROM = 20;
+    private static final int SUBLIST_TO = SIZE - 5;
+    private static final int SUBLIST_SIZE = SUBLIST_TO - SUBLIST_FROM;
+
+    private static interface Callback {
+        void call(List<Integer> list);
+    }
+
+    // call the callback for each recursive subList
+    private void trimmedSubList(final List<Integer> list, final Callback callback) {
+        int size = list.size();
+        if (size > 1) {
+            // trim 1 element from both ends
+            final List<Integer> subList = list.subList(1, size - 1);
+            callback.call(subList);
+            trimmedSubList(subList, callback);
+        }
+    }
+
+    @DataProvider(name="listProvider", parallel=true)
+    public static Object[][] listCases() {
+        final List<Object[]> cases = new LinkedList<>();
+        cases.add(new Object[] { Collections.emptyList() });
+        cases.add(new Object[] { new ArrayList<>() });
+        cases.add(new Object[] { new LinkedList<>() });
+        cases.add(new Object[] { new Vector<>() });
+        cases.add(new Object[] { new Stack<>() });
+        cases.add(new Object[] { new CopyOnWriteArrayList<>() });
+
+        cases.add(new Object[] { new ArrayList(){{add(42);}} });
+        cases.add(new Object[] { new LinkedList(){{add(42);}} });
+        cases.add(new Object[] { new Vector(){{add(42);}} });
+        cases.add(new Object[] { new Stack(){{add(42);}} });
+        cases.add(new Object[] { new CopyOnWriteArrayList(){{add(42);}} });
+        return cases.toArray(new Object[0][cases.size()]);
+    }
+
+    @Test(dataProvider = "listProvider")
+    public void testProvidedWithNull(final List<Integer> list) throws Exception {
+        try {
+            list.forEach(null);
+            fail("expected NPE not thrown");
+        } catch (NullPointerException npe) {}
+        try {
+            list.replaceAll(null);
+            fail("expected NPE not thrown");
+        } catch (NullPointerException npe) {}
+        try {
+            list.removeIf(null);
+            fail("expected NPE not thrown");
+        } catch (NullPointerException npe) {}
+        try {
+            list.sort(null);
+        } catch (Throwable t) {
+            fail("Exception not expected: " + t);
+        }
+    }
+
+    @Test
+    public void testForEach() throws Exception {
+        final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CLASSES, SIZE);
+        for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
+            final List<Integer> original = ((List<Integer>) test.expected);
+            final List<Integer> list = ((List<Integer>) test.collection);
+
+            try {
+                list.forEach(null);
+                fail("expected NPE not thrown");
+            } catch (NullPointerException npe) {}
+            CollectionAsserts.assertContents(list, original);
+
+            final List<Integer> actual = new LinkedList<>();
+            list.forEach(actual::add);
+            CollectionAsserts.assertContents(actual, list);
+            CollectionAsserts.assertContents(actual, original);
+
+            if (original.size() > SUBLIST_SIZE) {
+                final List<Integer> subList = original.subList(SUBLIST_FROM, SUBLIST_TO);
+                final List<Integer> actualSubList = new LinkedList<>();
+                subList.forEach(actualSubList::add);
+                assertEquals(actualSubList.size(), SUBLIST_SIZE);
+                for (int i = 0; i < SUBLIST_SIZE; i++) {
+                    assertEquals(actualSubList.get(i), original.get(i + SUBLIST_FROM));
+                }
+            }
+
+            trimmedSubList(list, new Callback() {
+                @Override
+                public void call(final List<Integer> list) {
+                    final List<Integer> actual = new LinkedList<>();
+                    list.forEach(actual::add);
+                    CollectionAsserts.assertContents(actual, list);
+                }
+            });
+        }
+    }
+
+    @Test
+    public void testRemoveIf() throws Exception {
+        final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CLASSES, SIZE);
+        for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
+            final List<Integer> original = ((List<Integer>) test.expected);
+            final List<Integer> list = ((List<Integer>) test.collection);
+
+            try {
+                list.removeIf(null);
+                fail("expected NPE not thrown");
+            } catch (NullPointerException npe) {}
+            CollectionAsserts.assertContents(list, original);
+
+            final AtomicInteger offset = new AtomicInteger(1);
+            while (list.size() > 0) {
+                removeFirst(original, list, offset);
+            }
+        }
+
+        for (final CollectionSupplier.TestCase test : supplier.get()) {
+            final List<Integer> original = ((List<Integer>) test.expected);
+            final List<Integer> list = ((List<Integer>) test.collection);
+            list.removeIf(pOdd);
+            for (int i : list) {
+                assertTrue((i % 2) == 0);
+            }
+            for (int i : original) {
+                if (i % 2 == 0) {
+                    assertTrue(list.contains(i));
+                }
+            }
+            list.removeIf(pEven);
+            assertTrue(list.isEmpty());
+        }
+
+        for (final CollectionSupplier.TestCase test : supplier.get()) {
+            final List<Integer> original = ((List<Integer>) test.expected);
+            final List<Integer> list = ((List<Integer>) test.collection);
+            final List<Integer> listCopy = new ArrayList<>(list);
+            if (original.size() > SUBLIST_SIZE) {
+                final List<Integer> subList = list.subList(SUBLIST_FROM, SUBLIST_TO);
+                final List<Integer> subListCopy = new ArrayList<>(subList);
+                listCopy.removeAll(subList);
+                subList.removeIf(pOdd);
+                for (int i : subList) {
+                    assertTrue((i % 2) == 0);
+                }
+                for (int i : subListCopy) {
+                    if (i % 2 == 0) {
+                        assertTrue(subList.contains(i));
+                    } else {
+                        assertFalse(subList.contains(i));
+                    }
+                }
+                subList.removeIf(pEven);
+                assertTrue(subList.isEmpty());
+                // elements outside the view should remain
+                CollectionAsserts.assertContents(list, listCopy);
+            }
+        }
+
+        for (final CollectionSupplier.TestCase test : supplier.get()) {
+            final List<Integer> list = ((List<Integer>) test.collection);
+            trimmedSubList(list, new Callback() {
+                @Override
+                public void call(final List<Integer> list) {
+                    final List<Integer> copy = new ArrayList<>(list);
+                    list.removeIf(pOdd);
+                    for (int i : list) {
+                        assertTrue((i % 2) == 0);
+                    }
+                    for (int i : copy) {
+                        if (i % 2 == 0) {
+                            assertTrue(list.contains(i));
+                        } else {
+                            assertFalse(list.contains(i));
+                        }
+                    }
+                }
+            });
+        }
+    }
+
+    // remove the first element
+    private void removeFirst(final List<Integer> original, final List<Integer> list, final AtomicInteger offset) {
+        final AtomicBoolean first = new AtomicBoolean(true);
+        list.removeIf(x -> first.getAndSet(false));
+        CollectionAsserts.assertContents(original.subList(offset.getAndIncrement(), original.size()), list);
+    }
+
+    @Test
+    public void testReplaceAll() throws Exception {
+        final int scale = 3;
+        final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CLASSES, SIZE);
+        for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
+            final List<Integer> original = ((List<Integer>) test.expected);
+            final List<Integer> list = ((List<Integer>) test.collection);
+
+            try {
+                list.replaceAll(null);
+                fail("expected NPE not thrown");
+            } catch (NullPointerException npe) {}
+            CollectionAsserts.assertContents(list, original);
+
+            list.replaceAll(x -> scale * x);
+            for (int i=0; i < original.size(); i++) {
+                assertTrue(list.get(i) == (scale * original.get(i)), "mismatch at index " + i);
+            }
+
+            if (original.size() > SUBLIST_SIZE) {
+                final List<Integer> subList = list.subList(SUBLIST_FROM, SUBLIST_TO);
+                subList.replaceAll(x -> x + 1);
+                // verify elements in view [from, to) were replaced
+                for (int i = 0; i < SUBLIST_SIZE; i++) {
+                    assertTrue(subList.get(i) == ((scale * original.get(i + SUBLIST_FROM)) + 1),
+                            "mismatch at sublist index " + i);
+                }
+                // verify that elements [0, from) remain unmodified
+                for (int i = 0; i < SUBLIST_FROM; i++) {
+                    assertTrue(list.get(i) == (scale * original.get(i)),
+                            "mismatch at original index " + i);
+                }
+                // verify that elements [to, size) remain unmodified
+                for (int i = SUBLIST_TO; i < list.size(); i++) {
+                    assertTrue(list.get(i) == (scale * original.get(i)),
+                            "mismatch at original index " + i);
+                }
+            }
+        }
+
+        for (final CollectionSupplier.TestCase test : supplier.get()) {
+            final List<Integer> list = ((List<Integer>) test.collection);
+            trimmedSubList(list, new Callback() {
+                @Override
+                public void call(final List<Integer> list) {
+                    final List<Integer> copy = new ArrayList<>(list);
+                    final int offset = 5;
+                    list.replaceAll(x -> offset + x);
+                    for (int i=0; i < copy.size(); i++) {
+                        assertTrue(list.get(i) == (offset + copy.get(i)), "mismatch at index " + i);
+                    }
+                }
+            });
+        }
+    }
+
+    @Test
+    public void testSort() throws Exception {
+        final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CLASSES, SIZE);
+        for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
+            final List<Integer> original = ((List<Integer>) test.expected);
+            final List<Integer> list = ((List<Integer>) test.collection);
+            CollectionSupplier.shuffle(list);
+            list.sort(Integer::compare);
+            CollectionAsserts.assertSorted(list, Integer::compare);
+            if (test.name.startsWith("reverse")) {
+                Collections.reverse(list);
+            }
+            CollectionAsserts.assertContents(list, original);
+
+            CollectionSupplier.shuffle(list);
+            list.sort(null);
+            CollectionAsserts.assertSorted(list, Comparator.<Integer>naturalOrder());
+            if (test.name.startsWith("reverse")) {
+                Collections.reverse(list);
+            }
+            CollectionAsserts.assertContents(list, original);
+
+            CollectionSupplier.shuffle(list);
+            list.sort(Comparator.<Integer>naturalOrder());
+            CollectionAsserts.assertSorted(list, Comparator.<Integer>naturalOrder());
+            if (test.name.startsWith("reverse")) {
+                Collections.reverse(list);
+            }
+            CollectionAsserts.assertContents(list, original);
+
+            CollectionSupplier.shuffle(list);
+            list.sort(Comparator.<Integer>reverseOrder());
+            CollectionAsserts.assertSorted(list, Comparator.<Integer>reverseOrder());
+            if (!test.name.startsWith("reverse")) {
+                Collections.reverse(list);
+            }
+            CollectionAsserts.assertContents(list, original);
+
+            CollectionSupplier.shuffle(list);
+            list.sort(BIT_COUNT_COMPARATOR);
+            CollectionAsserts.assertSorted(list, BIT_COUNT_COMPARATOR);
+            // check sort by verifying that bitCount increases and never drops
+            int minBitCount = 0;
+            int bitCount = 0;
+            for (final Integer i : list) {
+                bitCount = Integer.bitCount(i);
+                assertTrue(bitCount >= minBitCount);
+                minBitCount = bitCount;
+            }
+
+            @SuppressWarnings("unchecked")
+            final Constructor<? extends List<?>> defaultConstructor = ((Class<? extends List<?>>)test.collection.getClass()).getConstructor();
+            final List<AtomicInteger> incomparables = (List<AtomicInteger>) defaultConstructor.newInstance();
+
+            for (int i=0; i < test.expected.size(); i++) {
+                incomparables.add(new AtomicInteger(i));
+            }
+            CollectionSupplier.shuffle(incomparables);
+            incomparables.sort(ATOMIC_INTEGER_COMPARATOR);
+            for (int i=0; i < test.expected.size(); i++) {
+                assertEquals(i, incomparables.get(i).intValue());
+            }
+
+            if (original.size() > SUBLIST_SIZE) {
+                final List<Integer> copy = new ArrayList<>(list);
+                final List<Integer> subList = list.subList(SUBLIST_FROM, SUBLIST_TO);
+                CollectionSupplier.shuffle(subList);
+                subList.sort(Comparator.<Integer>naturalOrder());
+                CollectionAsserts.assertSorted(subList, Comparator.<Integer>naturalOrder());
+                // verify that elements [0, from) remain unmodified
+                for (int i = 0; i < SUBLIST_FROM; i++) {
+                    assertTrue(list.get(i) == copy.get(i),
+                            "mismatch at index " + i);
+                }
+                // verify that elements [to, size) remain unmodified
+                for (int i = SUBLIST_TO; i < list.size(); i++) {
+                    assertTrue(list.get(i) == copy.get(i),
+                            "mismatch at index " + i);
+                }
+            }
+        }
+
+        for (final CollectionSupplier.TestCase test : supplier.get()) {
+            final List<Integer> list = ((List<Integer>) test.collection);
+            trimmedSubList(list, new Callback() {
+                @Override
+                public void call(final List<Integer> list) {
+                    final List<Integer> copy = new ArrayList<>(list);
+                    CollectionSupplier.shuffle(list);
+                    list.sort(Comparator.<Integer>naturalOrder());
+                    CollectionAsserts.assertSorted(list, Comparator.<Integer>naturalOrder());
+                }
+            });
+        }
+    }
+
+    @Test
+    public void testForEachThrowsCME() throws Exception {
+        final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CME_CLASSES, SIZE);
+        for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
+            final List<Integer> list = ((List<Integer>) test.collection);
+
+            if (list.size() <= 1) {
+                continue;
+            }
+            boolean gotException = false;
+            try {
+                // bad predicate that modifies its list, should throw CME
+                list.forEach((x) -> {list.add(x);});
+            } catch (ConcurrentModificationException cme) {
+                gotException = true;
+            }
+            if (!gotException) {
+                fail("expected CME was not thrown from " + test);
+            }
+        }
+    }
+
+    @Test
+    public void testRemoveIfThrowsCME() throws Exception {
+        final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CME_CLASSES, SIZE);
+        for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
+            final List<Integer> original = ((List<Integer>) test.expected);
+            final List<Integer> list = ((List<Integer>) test.collection);
+
+            if (list.size() <= 1) {
+                continue;
+            }
+            boolean gotException = false;
+            try {
+                // bad predicate that modifies its list, should throw CME
+                list.removeIf((x) -> {return list.add(x);});
+            } catch (ConcurrentModificationException cme) {
+                gotException = true;
+            }
+            if (!gotException) {
+                fail("expected CME was not thrown from " + test);
+            }
+        }
+    }
+
+    @Test
+    public void testReplaceAllThrowsCME() throws Exception {
+        final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CME_CLASSES, SIZE);
+        for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
+            final List<Integer> list = ((List<Integer>) test.collection);
+
+            if (list.size() <= 1) {
+                continue;
+            }
+            boolean gotException = false;
+            try {
+                // bad predicate that modifies its list, should throw CME
+                list.replaceAll(x -> {int n = 3 * x; list.add(n); return n;});
+            } catch (ConcurrentModificationException cme) {
+                gotException = true;
+            }
+            if (!gotException) {
+                fail("expected CME was not thrown from " + test);
+            }
+        }
+    }
+
+    @Test
+    public void testSortThrowsCME() throws Exception {
+        final CollectionSupplier<List<Integer>> supplier = new CollectionSupplier((Supplier<List<Integer>>[])LIST_CME_CLASSES, SIZE);
+        for (final CollectionSupplier.TestCase<List<Integer>> test : supplier.get()) {
+            final List<Integer> list = ((List<Integer>) test.collection);
+
+            if (list.size() <= 1) {
+                continue;
+            }
+            boolean gotException = false;
+            try {
+                // bad predicate that modifies its list, should throw CME
+                list.sort((x, y) -> {list.add(x); return x - y;});
+            } catch (ConcurrentModificationException cme) {
+                gotException = true;
+            }
+            if (!gotException) {
+                fail("expected CME was not thrown from " + test);
+            }
+        }
+    }
+
+    private static final List<Integer> SLICED_EXPECTED = Arrays.asList(0, 1, 2, 3, 5, 6, 7, 8, 9);
+    private static final List<Integer> SLICED_EXPECTED2 = Arrays.asList(0, 1, 2, 5, 6, 7, 8, 9);
+
+    @DataProvider(name="shortIntListProvider", parallel=true)
+    public static Object[][] intListCases() {
+        final Integer[] DATA = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+        final List<Object[]> cases = new LinkedList<>();
+        cases.add(new Object[] { new ArrayList<>(Arrays.asList(DATA)) });
+        cases.add(new Object[] { new LinkedList<>(Arrays.asList(DATA)) });
+        cases.add(new Object[] { new Vector<>(Arrays.asList(DATA)) });
+        cases.add(new Object[] { new CopyOnWriteArrayList<>(Arrays.asList(DATA)) });
+        cases.add(new Object[] { new ExtendsAbstractList<>(Arrays.asList(DATA)) });
+        return cases.toArray(new Object[0][cases.size()]);
+    }
+
+    @Test(dataProvider = "shortIntListProvider")
+    public void testRemoveIfFromSlice(final List<Integer> list) throws Exception {
+        final List<Integer> sublist = list.subList(3, 6);
+        assertTrue(sublist.removeIf(x -> x == 4));
+        CollectionAsserts.assertContents(list, SLICED_EXPECTED);
+
+        final List<Integer> sublist2 = list.subList(2, 5);
+        assertTrue(sublist2.removeIf(x -> x == 3));
+        CollectionAsserts.assertContents(list, SLICED_EXPECTED2);
+    }
+}
--- a/jdk/test/java/util/Map/CheckRandomHashSeed.java	Tue Sep 17 08:08:07 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/**
- * @test
- * @bug 8005698
- * @summary Check operation of jdk.map.useRandomSeed property
- * @run main CheckRandomHashSeed
- * @run main/othervm -Djdk.map.useRandomSeed=false CheckRandomHashSeed
- * @run main/othervm -Djdk.map.useRandomSeed=bogus CheckRandomHashSeed
- * @run main/othervm -Djdk.map.useRandomSeed=true CheckRandomHashSeed true
- * @author Brent Christian
- */
-import java.lang.reflect.Field;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Hashtable;
-import java.util.WeakHashMap;
-
-public class CheckRandomHashSeed {
-    private final static String PROP_NAME = "jdk.map.useRandomSeed";
-    static boolean expectRandom = false;
-
-    public static void main(String[] args) {
-        if (args.length > 0 && args[0].equals("true")) {
-            expectRandom = true;
-        }
-        String hashSeedProp = System.getProperty(PROP_NAME);
-        boolean propSet = (null != hashSeedProp)
-                ? Boolean.parseBoolean(hashSeedProp) : false;
-        if (expectRandom != propSet) {
-            throw new Error("Error in test setup: " + (expectRandom ? "" : "not " ) + "expecting random hashSeed, but " + PROP_NAME + " is " + (propSet ? "" : "not ") + "enabled");
-        }
-
-        testMap(new HashMap());
-        testMap(new LinkedHashMap());
-        testMap(new WeakHashMap());
-        testMap(new Hashtable());
-    }
-
-    private static void testMap(Map map) {
-        int hashSeed = getHashSeed(map);
-        boolean hashSeedIsZero = (hashSeed == 0);
-
-        if (expectRandom != hashSeedIsZero) {
-            System.out.println("Test passed for " + map.getClass().getSimpleName() + " - expectRandom: " + expectRandom + ", hashSeed: " + hashSeed);
-        } else {
-            throw new Error ("Test FAILED for " + map.getClass().getSimpleName() + " -  expectRandom: " + expectRandom + ", hashSeed: " + hashSeed);
-        }
-    }
-
-    private static int getHashSeed(Map map) {
-        try {
-            if (map instanceof HashMap || map instanceof LinkedHashMap) {
-                map.put("Key", "Value");
-                Field hashSeedField = HashMap.class.getDeclaredField("hashSeed");
-                hashSeedField.setAccessible(true);
-                int hashSeed = hashSeedField.getInt(map);
-                return hashSeed;
-            } else {
-                map.put("Key", "Value");
-                Field hashSeedField = map.getClass().getDeclaredField("hashSeed");
-                hashSeedField.setAccessible(true);
-                int hashSeed = hashSeedField.getInt(map);
-                return hashSeed;
-            }
-        } catch(Exception e) {
-            e.printStackTrace();
-            throw new Error(e);
-        }
-    }
-}
--- a/jdk/test/java/util/Map/Collisions.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/util/Map/Collisions.java	Wed Jul 05 19:11:53 2017 +0200
@@ -25,8 +25,6 @@
  * @test
  * @bug 7126277
  * @run main Collisions -shortrun
- * @run main/othervm -Djdk.map.althashing.threshold=0 Collisions -shortrun
- * @run main/othervm -Djdk.map.useRandomSeed=true Collisions -shortrun
  * @summary Ensure Maps behave well with lots of hashCode() collisions.
  * @author Mike Duigou
  */
--- a/jdk/test/java/util/Map/Defaults.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/util/Map/Defaults.java	Wed Jul 05 19:11:53 2017 +0200
@@ -155,7 +155,7 @@
         assertThrows(
             () -> { map.replaceAll((k,v) -> null); },
             NullPointerException.class,
-            description);
+            description + " should not allow replacement with null value");
     }
 
     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=withNull values=withNull")
@@ -194,6 +194,15 @@
         assertSame(map.get(null), EXTRA_VALUE);
     }
 
+    @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull")
+    public void testReplaceKVNoNulls(String description, Map<IntegerEnum, String> map) {
+        assertTrue(map.containsKey(FIRST_KEY), "expected key missing");
+        assertSame(map.get(FIRST_KEY), FIRST_VALUE, "found wrong value");
+        assertThrows( () -> {map.replace(FIRST_KEY, null);}, NullPointerException.class, description + ": should throw NPE");
+        assertSame(map.replace(FIRST_KEY, EXTRA_VALUE), FIRST_VALUE, description + ": replaced wrong value");
+        assertSame(map.get(FIRST_KEY), EXTRA_VALUE, "found wrong value");
+    }
+
     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
     public void testReplaceKV(String description, Map<IntegerEnum, String> map) {
         assertTrue(map.containsKey(KEYS[1]));
@@ -224,6 +233,16 @@
         assertSame(map.get(null), EXTRA_VALUE);
     }
 
+    @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=nonNull values=nonNull")
+    public void testReplaceKVVNoNulls(String description, Map<IntegerEnum, String> map) {
+        assertTrue(map.containsKey(FIRST_KEY), "expected key missing");
+        assertSame(map.get(FIRST_KEY), FIRST_VALUE, "found wrong value");
+        assertThrows( () -> {map.replace(FIRST_KEY, FIRST_VALUE, null);}, NullPointerException.class, description + ": should throw NPE");
+        assertThrows( () -> {if (!map.replace(FIRST_KEY, null, EXTRA_VALUE)) throw new NullPointerException("default returns false rather than throwing");}, NullPointerException.class,  description + ": should throw NPE");
+        assertTrue(map.replace(FIRST_KEY, FIRST_VALUE, EXTRA_VALUE), description + ": replaced wrong value");
+        assertSame(map.get(FIRST_KEY), EXTRA_VALUE, "found wrong value");
+    }
+
     @Test(dataProvider = "Map<IntegerEnum,String> rw=true keys=all values=all")
     public void testReplaceKVV(String description, Map<IntegerEnum, String> map) {
         assertTrue(map.containsKey(KEYS[1]));
@@ -470,6 +489,9 @@
             VALUES[each] = String.valueOf(each);
         }
     }
+
+    private static final IntegerEnum FIRST_KEY = KEYS[0];
+    private static final String FIRST_VALUE = VALUES[0];
     private static final IntegerEnum EXTRA_KEY = IntegerEnum.EXTRA_KEY;
     private static final String EXTRA_VALUE = String.valueOf(TEST_SIZE);
 
@@ -583,6 +605,8 @@
         return Arrays.asList(
                 // null key hostile
                 new Object[]{"EnumMap", makeMap(() -> new EnumMap(IntegerEnum.class), false, nulls)},
+                new Object[]{"TreeMap", makeMap(TreeMap::new, false, nulls)},
+                new Object[]{"ExtendsAbstractMap(TreeMap)", makeMap(() -> {return new ExtendsAbstractMap(new TreeMap());}, false, nulls)},
                 new Object[]{"Collections.synchronizedMap(EnumMap)", Collections.synchronizedMap(makeMap(() -> new EnumMap(IntegerEnum.class), false, nulls))}
                 );
     }
@@ -591,10 +615,11 @@
         return Arrays.asList(
             // null key and value hostile
             new Object[]{"Hashtable", makeMap(Hashtable::new, false, false)},
-            new Object[]{"TreeMap", makeMap(TreeMap::new, false, false)},
             new Object[]{"ConcurrentHashMap", makeMap(ConcurrentHashMap::new, false, false)},
             new Object[]{"ConcurrentSkipListMap", makeMap(ConcurrentSkipListMap::new, false, false)},
+            new Object[]{"Collections.synchronizedMap(ConcurrentHashMap)", Collections.synchronizedMap(makeMap(ConcurrentHashMap::new, false, false))},
             new Object[]{"Collections.checkedMap(ConcurrentHashMap)", Collections.checkedMap(makeMap(ConcurrentHashMap::new, false, false), IntegerEnum.class, String.class)},
+            new Object[]{"ExtendsAbstractMap(ConcurrentHashMap)", makeMap(() -> {return new ExtendsAbstractMap(new ConcurrentHashMap());}, false, false)},
             new Object[]{"ImplementsConcurrentMap", makeMap(ImplementsConcurrentMap::new, false, false)}
             );
     }
@@ -641,18 +666,17 @@
     }
 
     public static <T extends Throwable> void assertThrows(Thrower<T> thrower, Class<T> throwable, String message) {
-        Throwable result;
+        Throwable thrown;
         try {
             thrower.run();
-            result = null;
+            thrown = null;
         } catch (Throwable caught) {
-            result = caught;
+            thrown = caught;
         }
 
-        assertInstance(result, throwable,
-            (null != message)
-            ? message
-            : "Failed to throw " + throwable.getCanonicalName());
+        assertInstance(thrown, throwable,
+            ((null != message) ? message : "") +
+            " Failed to throw " + throwable.getCanonicalName());
     }
 
     public static <T extends Throwable> void assertThrows(Class<T> throwable, String message, Thrower<T>... throwers) {
@@ -661,11 +685,11 @@
         }
     }
 
-    public static <T> void assertInstance(T actual, Class<? extends T> expected) {
+    public static void assertInstance(Object actual, Class<?> expected) {
         assertInstance(expected.isInstance(actual), null);
     }
 
-    public static <T> void assertInstance(T actual, Class<? extends T> expected, String message) {
+    public static void assertInstance(Object actual, Class<?> expected, String message) {
         assertTrue(expected.isInstance(actual), message);
     }
 
--- a/jdk/test/java/util/Map/InPlaceOpsCollisions.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/util/Map/InPlaceOpsCollisions.java	Wed Jul 05 19:11:53 2017 +0200
@@ -25,7 +25,6 @@
  * @test
  * @bug 8005698
  * @run main InPlaceOpsCollisions -shortrun
- * @run main/othervm -Djdk.map.randomseed=true InPlaceOpsCollisions -shortrun
  * @summary Ensure overrides of in-place operations in Maps behave well with lots of collisions.
  * @author Brent Christian
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Map/MapBinToFromTreeTest.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BiConsumer;
+import java.util.stream.Collector;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import static org.testng.Assert.assertEquals;
+
+/*
+ * @test
+ * @bug 8023463
+ * @summary Test the case where a bin is treeified and vice verser
+ * @run testng MapBinToFromTreeTest
+ */
+
+@Test
+public class MapBinToFromTreeTest {
+
+    // Initial capacity of map
+    // Should be >= the map capacity for treeifiying, see HashMap/ConcurrentMap.MIN_TREEIFY_CAPACITY
+    static final int INITIAL_CAPACITY = 64;
+
+    // Maximum size of map
+    // Should be > the treeify threshold, see HashMap/ConcurrentMap.TREEIFY_THRESHOLD
+    // Should be > INITIAL_CAPACITY to ensure resize occurs
+    static final int SIZE = 256;
+
+    // Load factor of map
+    // A value 1.0 will ensure that a new threshold == capacity
+    static final float LOAD_FACTOR = 1.0f;
+
+    @DataProvider(name = "maps")
+    static Object[][] mapProvider() {
+        return new Object[][] {
+                // Pass in the class name as a description for test reporting
+                // purposes
+                { HashMap.class.getName(), new HashMap(INITIAL_CAPACITY, LOAD_FACTOR) },
+                { LinkedHashMap.class.getName(), new LinkedHashMap(INITIAL_CAPACITY, LOAD_FACTOR) },
+                { ConcurrentHashMap.class.getName(), new ConcurrentHashMap(INITIAL_CAPACITY, LOAD_FACTOR) },
+        };
+    }
+
+    @Test(dataProvider = "maps")
+    public void testPutThenGet(String d, Map<HashCodeInteger, Integer> m) {
+        put(SIZE, m, (i, s) -> {
+            for (int j = 0; j < s; j++) {
+                assertEquals(m.get(new HashCodeInteger(j)).intValue(), j,
+                             String.format("Map.get(%d)", j));
+            }
+        });
+    }
+
+    @Test(dataProvider = "maps")
+    public void testPutThenTraverse(String d, Map<HashCodeInteger, Integer> m) {
+        Collector<Integer, ?, ? extends Collection<Integer>> c = getCollector(m);
+
+        put(SIZE, m, (i, s) -> {
+            // Note that it is OK to collect to a Set (HashSet) as long as
+            // integer values are used since these tests only check for
+            // collisions and other tests will verify more general functionality
+            Collection<Integer> actual = m.keySet().stream().map(e -> e.value).collect(c);
+            Collection<Integer> expected = IntStream.range(0, s).boxed().collect(c);
+            assertEquals(actual, expected, "Map.keySet()");
+        });
+    }
+
+    @Test(dataProvider = "maps")
+    public void testRemoveThenGet(String d, Map<HashCodeInteger, Integer> m) {
+        put(SIZE, m, (i, s) -> { });
+
+        remove(m, (i, s) -> {
+            for (int j = i + 1; j < SIZE; j++) {
+                assertEquals(m.get(new HashCodeInteger(j)).intValue(), j,
+                             String.format("Map.get(%d)", j));
+            }
+        });
+    }
+
+    @Test(dataProvider = "maps")
+    public void testRemoveThenTraverse(String d, Map<HashCodeInteger, Integer> m) {
+        put(SIZE, m, (i, s) -> { });
+
+        Collector<Integer, ?, ? extends Collection<Integer>> c = getCollector(m);
+
+        remove(m, (i, s) -> {
+            Collection<Integer> actual = m.keySet().stream().map(e -> e.value).collect(c);
+            Collection<Integer> expected = IntStream.range(i + 1, SIZE).boxed().collect(c);
+            assertEquals(actual, expected, "Map.keySet()");
+        });
+    }
+
+    @Test(dataProvider = "maps")
+    public void testUntreeifyOnResizeWithGet(String d, Map<HashCodeInteger, Integer> m) {
+        // Fill the map with 64 entries grouped into 4 buckets
+        put(INITIAL_CAPACITY, m, (i, s) -> { });
+
+        for (int i = INITIAL_CAPACITY; i < SIZE; i++) {
+            // Add further entries in the 0'th bucket so as not to disturb
+            // other buckets, entries of which may be distributed and/or
+            // the bucket untreeified on resize
+            m.put(new HashCodeInteger(i, 0), i);
+
+            for (int j = 0; j < INITIAL_CAPACITY; j++) {
+                assertEquals(m.get(new HashCodeInteger(j)).intValue(), j,
+                             String.format("Map.get(%d) < INITIAL_CAPACITY", j));
+            }
+            for (int j = INITIAL_CAPACITY; j <= i; j++) {
+                assertEquals(m.get(new HashCodeInteger(j, 0)).intValue(), j,
+                             String.format("Map.get(%d) >= INITIAL_CAPACITY", j));
+            }
+        }
+    }
+
+    @Test(dataProvider = "maps")
+    public void testUntreeifyOnResizeWithTraverse(String d, Map<HashCodeInteger, Integer> m) {
+        // Fill the map with 64 entries grouped into 4 buckets
+        put(INITIAL_CAPACITY, m, (i, s) -> { });
+
+        Collector<Integer, ?, ? extends Collection<Integer>> c = getCollector(m);
+
+        for (int i = INITIAL_CAPACITY; i < SIZE; i++) {
+            // Add further entries in the 0'th bucket so as not to disturb
+            // other buckets, entries of which may be distributed and/or
+            // the bucket untreeified on resize
+            m.put(new HashCodeInteger(i, 0), i);
+
+            Collection<Integer> actual = m.keySet().stream().map(e -> e.value).collect(c);
+            Collection<Integer> expected = IntStream.rangeClosed(0, i).boxed().collect(c);
+            assertEquals(actual, expected, "Key set");
+        }
+    }
+
+    Collector<Integer, ?, ? extends Collection<Integer>> getCollector(Map<?, ?> m) {
+        Collector<Integer, ?, ? extends Collection<Integer>> collector = m instanceof LinkedHashMap
+                                                                         ? Collectors.toList()
+                                                                         : Collectors.toSet();
+        return collector;
+    }
+
+    void put(int size, Map<HashCodeInteger, Integer> m, BiConsumer<Integer, Integer> c) {
+        for (int i = 0; i < size; i++) {
+            m.put(new HashCodeInteger(i), i);
+
+            c.accept(i, m.size());
+        }
+    }
+
+    void remove(Map<HashCodeInteger, Integer> m, BiConsumer<Integer, Integer> c) {
+        int size = m.size();
+        // Remove all elements thus ensuring at some point trees will be
+        // converting back to bins
+        for (int i = 0; i < size; i++) {
+            m.remove(new HashCodeInteger(i));
+
+            c.accept(i, m.size());
+        }
+    }
+
+    final static class HashCodeInteger implements Comparable<HashCodeInteger> {
+        final int value;
+
+        final int hashcode;
+
+        HashCodeInteger(int value) {
+            this(value, hash(value));
+        }
+
+        HashCodeInteger(int value, int hashcode) {
+            this.value = value;
+            this.hashcode = hashcode;
+        }
+
+        static int hash(int i) {
+            // Assuming 64 entries with keys from 0 to 63 then a map:
+            // - of capacity 64 will have 4 buckets with 16 entries per-bucket
+            // - of capacity 128 will have 8 buckets with 8 entries per-bucket
+            // - of capacity 256 will have 16 buckets with 4 entries per-bucket
+            //
+            // Re-sizing will result in re-distribution, doubling the buckets
+            // and reducing the entries by half. This will result in
+            // untreeifying when the number of entries is less than untreeify
+            // threshold (see HashMap/ConcurrentMap.UNTREEIFY_THRESHOLD)
+            return (i % 4) + (i / 4) * INITIAL_CAPACITY;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof HashCodeInteger) {
+                HashCodeInteger other = (HashCodeInteger) obj;
+                return other.value == value;
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return hashcode;
+        }
+
+        @Override
+        public int compareTo(HashCodeInteger o) {
+            return value - o.value;
+        }
+
+        @Override
+        public String toString() {
+            return Integer.toString(value);
+        }
+    }
+}
--- a/jdk/test/java/util/Map/TreeBinSplitBackToEntries.java	Tue Sep 17 08:08:07 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,255 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.util.*;
-import java.lang.reflect.Field;
-
-/*
- * @test
- * @bug 8005698
- * @summary Test the case where TreeBin.splitTreeBin() converts a bin back to an Entry list
- * @run main TreeBinSplitBackToEntries unused
- * @author Brent Christian
- */
-
-public class TreeBinSplitBackToEntries {
-    private static int EXPECTED_TREE_THRESHOLD = 16;
-
-    // Easiest if this covers one bit higher then 'bit' in splitTreeBin() on the
-    // call where the TreeBin is converted back to an Entry list
-    private static int HASHMASK = 0x7F;
-    private static boolean verbose = false;
-    private static boolean fastFail = false;
-    private static boolean failed = false;
-
-    static void printlnIfVerbose(String msg) {
-        if (verbose) {System.out.println(msg); }
-    }
-
-    public static void main(String[] args) {
-        for (String arg : args) {
-            switch(arg) {
-                case "-verbose":
-                    verbose = true;
-                    break;
-                case "-fastfail":
-                    fastFail = true;
-                    break;
-            }
-        }
-        checkTreeThreshold();
-        testMapHiTree();
-        testMapLoTree();
-        if (failed) {
-            System.out.println("Test Failed");
-            System.exit(1);
-        } else {
-            System.out.println("Test Passed");
-        }
-    }
-
-    public static void checkTreeThreshold() {
-        int threshold = -1;
-        try {
-            Class treeBinClass = Class.forName("java.util.HashMap$TreeBin");
-            Field treeThreshold = treeBinClass.getDeclaredField("TREE_THRESHOLD");
-            treeThreshold.setAccessible(true);
-            threshold = treeThreshold.getInt(treeBinClass);
-        } catch (ClassNotFoundException|NoSuchFieldException|IllegalAccessException e) {
-            e.printStackTrace();
-            throw new Error("Problem accessing TreeBin.TREE_THRESHOLD", e);
-        }
-        check("Expected TREE_THRESHOLD: " + EXPECTED_TREE_THRESHOLD +", found: " + threshold,
-              threshold == EXPECTED_TREE_THRESHOLD);
-        printlnIfVerbose("TREE_THRESHOLD: " + threshold);
-    }
-
-    public static void testMapHiTree() {
-        Object[][] mapKeys = makeHiTreeTestData();
-        testMapsForKeys(mapKeys, "hiTree");
-    }
-
-    public static void testMapLoTree() {
-        Object[][] mapKeys = makeLoTreeTestData();
-
-        testMapsForKeys(mapKeys, "loTree");
-    }
-
-    public static void testMapsForKeys(Object[][] mapKeys, String desc) {
-        // loop through data sets
-        for (Object[] keys_desc : mapKeys) {
-            Map<Object, Object>[] maps = (Map<Object, Object>[]) new Map[]{
-              new HashMap<>(4, 0.8f),
-              new LinkedHashMap<>(4, 0.8f),
-            };
-            // for each map type.
-            for (Map<Object, Object> map : maps) {
-                Object[] keys = (Object[]) keys_desc[1];
-                System.out.println(desc + ": testPutThenGet() for " + map.getClass());
-                testPutThenGet(map, keys);
-            }
-        }
-    }
-
-    private static <T> void testPutThenGet(Map<T, T> map, T[] keys) {
-        for (T key : keys) {
-            printlnIfVerbose("put()ing 0x" + Integer.toHexString(Integer.parseInt(key.toString())) + ", hashCode=" + Integer.toHexString(key.hashCode()));
-            map.put(key, key);
-        }
-        for (T key : keys) {
-            check("key: 0x" + Integer.toHexString(Integer.parseInt(key.toString())) + " not found in resulting " + map.getClass().getSimpleName(), map.get(key) != null);
-        }
-    }
-
-    /* Data to force a non-empty loTree in TreeBin.splitTreeBin() to be converted back
-     * into an Entry list
-     */
-    private static Object[][] makeLoTreeTestData() {
-        HashableInteger COLLIDING_OBJECTS[] = new HashableInteger[] {
-            new HashableInteger( 0x23, HASHMASK),
-            new HashableInteger( 0x123, HASHMASK),
-            new HashableInteger( 0x323, HASHMASK),
-            new HashableInteger( 0x523, HASHMASK),
-
-            new HashableInteger( 0x723, HASHMASK),
-            new HashableInteger( 0x923, HASHMASK),
-            new HashableInteger( 0xB23, HASHMASK),
-            new HashableInteger( 0xD23, HASHMASK),
-
-            new HashableInteger( 0xF23, HASHMASK),
-            new HashableInteger( 0xF123, HASHMASK),
-            new HashableInteger( 0x1023, HASHMASK),
-            new HashableInteger( 0x1123, HASHMASK),
-
-            new HashableInteger( 0x1323, HASHMASK),
-            new HashableInteger( 0x1523, HASHMASK),
-            new HashableInteger( 0x1723, HASHMASK),
-            new HashableInteger( 0x1923, HASHMASK),
-
-            new HashableInteger( 0x1B23, HASHMASK),
-            new HashableInteger( 0x1D23, HASHMASK),
-            new HashableInteger( 0x3123, HASHMASK),
-            new HashableInteger( 0x3323, HASHMASK),
-            new HashableInteger( 0x3523, HASHMASK),
-
-            new HashableInteger( 0x3723, HASHMASK),
-            new HashableInteger( 0x1001, HASHMASK),
-            new HashableInteger( 0x4001, HASHMASK),
-            new HashableInteger( 0x1, HASHMASK),
-        };
-        return new Object[][] {
-            new Object[]{"Colliding Objects", COLLIDING_OBJECTS},
-        };
-    }
-
-    /* Data to force the hiTree in TreeBin.splitTreeBin() to be converted back
-     * into an Entry list
-     */
-    private static Object[][] makeHiTreeTestData() {
-        HashableInteger COLLIDING_OBJECTS[] = new HashableInteger[] {
-            new HashableInteger( 0x1, HASHMASK),
-            new HashableInteger( 0x101, HASHMASK),
-            new HashableInteger( 0x301, HASHMASK),
-            new HashableInteger( 0x501, HASHMASK),
-            new HashableInteger( 0x701, HASHMASK),
-
-            new HashableInteger( 0x1001, HASHMASK),
-            new HashableInteger( 0x1101, HASHMASK),
-            new HashableInteger( 0x1301, HASHMASK),
-
-            new HashableInteger( 0x1501, HASHMASK),
-            new HashableInteger( 0x1701, HASHMASK),
-            new HashableInteger( 0x4001, HASHMASK),
-            new HashableInteger( 0x4101, HASHMASK),
-            new HashableInteger( 0x4301, HASHMASK),
-
-            new HashableInteger( 0x4501, HASHMASK),
-            new HashableInteger( 0x4701, HASHMASK),
-            new HashableInteger( 0x8001, HASHMASK),
-            new HashableInteger( 0x8101, HASHMASK),
-
-
-            new HashableInteger( 0x8301, HASHMASK),
-            new HashableInteger( 0x8501, HASHMASK),
-            new HashableInteger( 0x8701, HASHMASK),
-            new HashableInteger( 0x9001, HASHMASK),
-
-            new HashableInteger( 0x23, HASHMASK),
-            new HashableInteger( 0x123, HASHMASK),
-            new HashableInteger( 0x323, HASHMASK),
-            new HashableInteger( 0x523, HASHMASK),
-        };
-        return new Object[][] {
-            new Object[]{"Colliding Objects", COLLIDING_OBJECTS},
-        };
-    }
-
-    static void check(String desc, boolean cond) {
-        if (!cond) {
-            fail(desc);
-        }
-    }
-
-    static void fail(String msg) {
-        failed = true;
-        (new Error("Failure: " + msg)).printStackTrace(System.err);
-        if (fastFail) {
-            System.exit(1);
-        }
-    }
-
-    final static class HashableInteger implements Comparable<HashableInteger> {
-        final int value;
-        final int hashmask; //yes duplication
-
-        HashableInteger(int value, int hashmask) {
-            this.value = value;
-            this.hashmask = hashmask;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (obj instanceof HashableInteger) {
-                HashableInteger other = (HashableInteger) obj;
-                return other.value == value;
-            }
-            return false;
-        }
-
-        @Override
-        public int hashCode() {
-            // This version ANDs the mask
-            return value & hashmask;
-        }
-
-        @Override
-        public int compareTo(HashableInteger o) {
-            return value - o.value;
-        }
-
-        @Override
-        public String toString() {
-            return Integer.toString(value);
-        }
-    }
-}
--- a/jdk/test/java/util/Spliterator/SpliteratorCharacteristics.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/util/Spliterator/SpliteratorCharacteristics.java	Wed Jul 05 19:11:53 2017 +0200
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @bug 8020156 8020009 8022326
+ * @bug 8020156 8020009 8022326 8012913
  * @run testng SpliteratorCharacteristics
  */
 
@@ -32,6 +32,10 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.SortedMap;
@@ -47,7 +51,27 @@
 @Test
 public class SpliteratorCharacteristics {
 
-    // TreeMap
+    public void testHashMap() {
+        assertMapCharacteristics(new HashMap<>(),
+                                 Spliterator.SIZED | Spliterator.DISTINCT);
+    }
+
+    public void testHashSet() {
+        assertSetCharacteristics(new HashSet<>(),
+                                 Spliterator.SIZED | Spliterator.DISTINCT);
+    }
+
+    public void testLinkedHashMap() {
+        assertMapCharacteristics(new LinkedHashMap<>(),
+                                 Spliterator.SIZED | Spliterator.DISTINCT |
+                                 Spliterator.ORDERED);
+    }
+
+    public void testLinkedHashSet() {
+        assertSetCharacteristics(new LinkedHashSet<>(),
+                                 Spliterator.SIZED | Spliterator.DISTINCT |
+                                 Spliterator.ORDERED);
+    }
 
     public void testTreeMap() {
         assertSortedMapCharacteristics(new TreeMap<>(),
@@ -61,9 +85,6 @@
                                        Spliterator.SORTED | Spliterator.ORDERED);
     }
 
-
-    // TreeSet
-
     public void testTreeSet() {
         assertSortedSetCharacteristics(new TreeSet<>(),
                                        Spliterator.SIZED | Spliterator.DISTINCT |
@@ -76,9 +97,6 @@
                                        Spliterator.SORTED | Spliterator.ORDERED);
     }
 
-
-    // ConcurrentSkipListMap
-
     public void testConcurrentSkipListMap() {
         assertSortedMapCharacteristics(new ConcurrentSkipListMap<>(),
                                        Spliterator.CONCURRENT | Spliterator.NONNULL |
@@ -93,9 +111,6 @@
                                        Spliterator.ORDERED);
     }
 
-
-    // ConcurrentSkipListSet
-
     public void testConcurrentSkipListSet() {
         assertSortedSetCharacteristics(new ConcurrentSkipListSet<>(),
                                        Spliterator.CONCURRENT | Spliterator.NONNULL |
@@ -113,35 +128,58 @@
 
     //
 
-    void assertSortedMapCharacteristics(SortedMap<Integer, String> m, int keyCharacteristics) {
+
+    void assertMapCharacteristics(Map<Integer, String> m, int keyCharacteristics) {
+        assertMapCharacteristics(m, keyCharacteristics, 0);
+    }
+
+    void assertMapCharacteristics(Map<Integer, String> m, int keyCharacteristics, int notValueCharacteristics) {
         initMap(m);
 
-        boolean hasComparator = m.comparator() != null;
+        assertCharacteristics(m.keySet(), keyCharacteristics);
+
+        assertCharacteristics(m.values(),
+                              keyCharacteristics & ~(Spliterator.DISTINCT | notValueCharacteristics));
+
+        assertCharacteristics(m.entrySet(), keyCharacteristics);
+
+        if ((keyCharacteristics & Spliterator.SORTED) == 0) {
+            assertISEComparator(m.keySet());
+            assertISEComparator(m.values());
+            assertISEComparator(m.entrySet());
+        }
+    }
+
+    void assertSetCharacteristics(Set<Integer> s, int keyCharacteristics) {
+        initSet(s);
+
+        assertCharacteristics(s, keyCharacteristics);
+
+        if ((keyCharacteristics & Spliterator.SORTED) == 0) {
+            assertISEComparator(s);
+        }
+    }
+
+    void assertSortedMapCharacteristics(SortedMap<Integer, String> m, int keyCharacteristics) {
+        assertMapCharacteristics(m, keyCharacteristics, Spliterator.SORTED);
 
         Set<Integer> keys = m.keySet();
-        assertCharacteristics(keys, keyCharacteristics);
-        if (hasComparator) {
+        if (m.comparator() != null) {
             assertNotNullComparator(keys);
         }
         else {
             assertNullComparator(keys);
         }
 
-        assertCharacteristics(m.values(),
-                              keyCharacteristics & ~(Spliterator.DISTINCT | Spliterator.SORTED));
         assertISEComparator(m.values());
 
-        assertCharacteristics(m.entrySet(), keyCharacteristics);
         assertNotNullComparator(m.entrySet());
     }
 
     void assertSortedSetCharacteristics(SortedSet<Integer> s, int keyCharacteristics) {
-        initSet(s);
+        assertSetCharacteristics(s, keyCharacteristics);
 
-        boolean hasComparator = s.comparator() != null;
-
-        assertCharacteristics(s, keyCharacteristics);
-        if (hasComparator) {
+        if (s.comparator() != null) {
             assertNotNullComparator(s);
         }
         else {
@@ -161,27 +199,18 @@
     }
 
     void assertCharacteristics(Collection<?> c, int expectedCharacteristics) {
-        assertCharacteristics(c.spliterator(), expectedCharacteristics);
-    }
-
-    void assertCharacteristics(Spliterator<?> s, int expectedCharacteristics) {
-        assertTrue(s.hasCharacteristics(expectedCharacteristics));
+        assertTrue(c.spliterator().hasCharacteristics(expectedCharacteristics),
+                   "Spliterator characteristics");
     }
 
     void assertNullComparator(Collection<?> c) {
-        assertNullComparator(c.spliterator());
-    }
-
-    void assertNullComparator(Spliterator<?> s) {
-        assertNull(s.getComparator());
+        assertNull(c.spliterator().getComparator(),
+                   "Comparator of Spliterator of Collection");
     }
 
     void assertNotNullComparator(Collection<?> c) {
-        assertNotNullComparator(c.spliterator());
-    }
-
-    void assertNotNullComparator(Spliterator<?> s) {
-        assertNotNull(s.getComparator());
+        assertNotNull(c.spliterator().getComparator(),
+                      "Comparator of Spliterator of Collection");
     }
 
     void assertISEComparator(Collection<?> c) {
@@ -196,6 +225,6 @@
         catch (IllegalStateException e) {
             caught = true;
         }
-        assertTrue(caught);
+        assertTrue(caught, "Throwing IllegalStateException");
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/concurrent/ConcurrentHashMap/ToArray.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 4486658 8010293
+ * @summary thread safety of toArray methods of subCollections
+ * @author Martin Buchholz
+ */
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.IntStream;
+
+public class ToArray {
+
+    public static void main(String[] args) throws Throwable {
+        // Execute a number of times to increase the probability of
+        // failure if there is an issue
+        for (int i = 0; i < 16; i++) {
+            executeTest();
+        }
+    }
+
+    static void executeTest() throws Throwable {
+        final Throwable throwable[] = new Throwable[1];
+        final ConcurrentHashMap<Integer, Integer> m = new ConcurrentHashMap<>();
+
+        // Number of workers equal to the number of processors
+        // Each worker will put globally unique keys into the map
+        final int nWorkers = Runtime.getRuntime().availableProcessors();
+        final int sizePerWorker = 1024;
+        final int maxSize = nWorkers * sizePerWorker;
+
+        // The foreman keeps checking that the size of the arrays
+        // obtained from the key and value sets is never less than the
+        // previously observed size and is never greater than the maximum size
+        // NOTE: these size constraints are not specific to toArray and are
+        // applicable to any form of traversal of the collection views
+        CompletableFuture<?> foreman = CompletableFuture.runAsync(new Runnable() {
+            private int prevSize = 0;
+
+            private boolean checkProgress(Object[] a) {
+                int size = a.length;
+                if (size < prevSize) throw new RuntimeException("WRONG WAY");
+                if (size > maxSize) throw new RuntimeException("OVERSHOOT");
+                if (size == maxSize) return true;
+                prevSize = size;
+                return false;
+            }
+
+            @Override
+            public void run() {
+                try {
+                    Integer[] empty = new Integer[0];
+                    while (true) {
+                        if (checkProgress(m.values().toArray())) return;
+                        if (checkProgress(m.keySet().toArray())) return;
+                        if (checkProgress(m.values().toArray(empty))) return;
+                        if (checkProgress(m.keySet().toArray(empty))) return;
+                    }
+                }
+                catch (Throwable t) {
+                    throwable[0] = t;
+                }
+            }
+        });
+
+        // Create workers
+        // Each worker will put globally unique keys into the map
+        CompletableFuture<?>[] workers = IntStream.range(0, nWorkers).
+                mapToObj(w -> CompletableFuture.runAsync(() -> {
+                    for (int i = 0, o = w * sizePerWorker; i < sizePerWorker; i++)
+                        m.put(o + i, i);
+                })).
+                toArray(CompletableFuture<?>[]::new);
+
+        // Wait for workers and then foreman to complete
+        CompletableFuture.allOf(workers).join();
+        foreman.join();
+
+        if (throwable[0] != null)
+            throw throwable[0];
+    }
+}
--- a/jdk/test/java/util/concurrent/ConcurrentHashMap/toArray.java	Tue Sep 17 08:08:07 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-/*
- * Copyright (c) 2004, 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 4486658
- * @summary thread safety of toArray methods of subCollections
- * @author Martin Buchholz
- */
-
-import java.util.*;
-import java.util.concurrent.*;
-
-public class toArray {
-
-    public static void main(String[] args) throws Throwable {
-        final Throwable throwable[] = new Throwable[1];
-        final int maxSize = 1000;
-        final ConcurrentHashMap<Integer, Integer> m
-            = new ConcurrentHashMap<Integer, Integer>();
-
-        final Thread t1 = new Thread() { public void run() {
-            for (int i = 0; i < maxSize; i++)
-                m.put(i,i);}};
-
-        final Thread t2 = new Thread() {
-            public Throwable exception = null;
-            private int prevSize = 0;
-
-            private boolean checkProgress(Object[] a) {
-                int size = a.length;
-                if (size < prevSize) throw new RuntimeException("WRONG WAY");
-                if (size > maxSize)  throw new RuntimeException("OVERSHOOT");
-                if (size == maxSize) return true;
-                prevSize = size;
-                return false;
-            }
-
-            public void run() {
-                try {
-                    Integer[] empty = new Integer[0];
-                    while (true) {
-                        if (checkProgress(m.values().toArray())) return;
-                        if (checkProgress(m.keySet().toArray())) return;
-                        if (checkProgress(m.values().toArray(empty))) return;
-                        if (checkProgress(m.keySet().toArray(empty))) return;
-                    }
-                } catch (Throwable t) {
-                   throwable[0] = t;
-                }}};
-
-        t2.start();
-        t1.start();
-
-        t1.join();
-        t2.join();
-
-        if (throwable[0] != null)
-            throw throwable[0];
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/function/BiFunction/BiFunctionTest.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8024500
+ * @run testng BiFunctionTest
+ */
+
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.fail;
+
+@Test(groups = "unit")
+public class BiFunctionTest {
+    static class Quote {
+        double unit_price;
+
+        Quote(double price) {
+            unit_price = price;
+        }
+    };
+
+    static class Order {
+        int quantity;
+
+        Order(int quantity) {
+            this.quantity = quantity;
+        }
+    };
+
+    BiFunction<Quote, Order, Double> estimate = (quote, order) -> {
+        if (quote.unit_price < 0) {
+            throw new IllegalArgumentException("quote");
+        }
+
+        if (order.quantity < 0) {
+            throw new IllegalArgumentException("order");
+        }
+
+        return quote.unit_price * order.quantity;
+    };
+
+    Function<Double, Long> creditcheck = total -> {
+        if (total > 100.00) {
+            throw new RuntimeException("overlimit");
+        }
+        return total.longValue();
+    };
+
+    public void testAndThen() {
+        try {
+            BiFunction<Quote, Order, Long> checkout = estimate.andThen(null);
+            fail("Null argument should throw NPE");
+        } catch (NullPointerException npe) {
+            // ignore
+        }
+
+        BiFunction<Quote, Order, Long> checkout = estimate.andThen(creditcheck);
+        try {
+            checkout.apply(new Quote(20.0), new Order(-1));
+            fail("First function delivers exception");
+        } catch (IllegalArgumentException e) {
+            assertEquals(e.getMessage(), "order");
+        }
+
+        try {
+            checkout.apply(new Quote(20.0), new Order(10));
+            fail("Second function delivers exception");
+        } catch (RuntimeException e) {
+            assertEquals(e.getMessage(), "overlimit");
+        }
+
+        assertEquals(49, checkout.apply(new Quote(24.99), new Order(2)).longValue());
+        assertEquals(50, checkout.apply(new Quote(25), new Order(2)).longValue());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/logging/LocalizedLevelName.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.*;
+import java.util.logging.*;
+
+/*
+ * @test
+ * @bug 8016127 8024131
+ * @summary test logging.properties localized
+ * @run main/othervm LocalizedLevelName
+ */
+
+public class LocalizedLevelName {
+    private static Object[] namesMap = {
+        "SEVERE",  Locale.ENGLISH, "Severe",        Level.SEVERE,
+        "WARNING", Locale.FRENCH,  "Avertissement", Level.WARNING,
+        "INFO",    Locale.ITALIAN, "Informazioni",  Level.INFO,
+        "SEVERE",  Locale.FRENCH,  "Grave",         Level.SEVERE,
+        "CONFIG",  Locale.GERMAN,  "Konfiguration", Level.CONFIG,
+        "ALL",     Locale.ROOT,    "All",           Level.ALL,
+        "SEVERE",  Locale.ROOT,    "Severe",        Level.SEVERE,
+        "WARNING", Locale.ROOT,    "Warning",       Level.WARNING,
+        "CONFIG",  Locale.ROOT,    "Config",        Level.CONFIG,
+        "INFO",    Locale.ROOT,    "Info",          Level.INFO,
+        "FINE",    Locale.ROOT,    "Fine",          Level.FINE,
+        "FINER",   Locale.ROOT,    "Finer",         Level.FINER,
+        "FINEST",  Locale.ROOT,    "Finest",        Level.FINEST
+    };
+
+    public static void main(String args[]) throws Exception {
+        Locale defaultLocale = Locale.getDefault();
+        for (int i=0; i<namesMap.length; i += 4) {
+            final String key = (String) namesMap[i];
+            final Locale locale = (Locale) namesMap[i+1];
+            final String expectedTranslation = (String) namesMap[i+2];
+            final Level level = (Level) namesMap[i+3];
+
+            final String en = getLocalizedMessage(Locale.ENGLISH, key);
+            final String other = getLocalizedMessage(locale, key);
+
+            System.out.println(locale + ": " + key + "=" + expectedTranslation
+                    + ", (Level." + level.getName() + ")");
+            System.out.println("     => localized(" + Locale.ENGLISH + ", "
+                    + key + ")=" + en);
+            System.out.println("     => localized(" + locale + ", " + key
+                    + ")=" + other);
+            if (!key.equals(en.toUpperCase(Locale.ROOT))) {
+                throw new RuntimeException("Expect " + key
+                        + " equals upperCase(" + en + ")");
+            }
+            if (!Locale.ENGLISH.equals(locale) && !Locale.ROOT.equals(locale)
+                    && key.equals(other.toUpperCase(Locale.ROOT))) {
+                throw new RuntimeException("Expect " + key
+                        + " not equals upperCase(" + other +")");
+            }
+            if ((Locale.ENGLISH.equals(locale) || Locale.ROOT.equals(locale))
+                    && !key.equals(other.toUpperCase(Locale.ROOT))) {
+                throw new RuntimeException("Expect " + key
+                        + " equals upperCase(" + other +")");
+            }
+            if (!other.equals(expectedTranslation)) {
+                throw new RuntimeException("Expected \"" + expectedTranslation
+                        + "\" for '" + locale + "' but got \"" + other + "\"");
+            }
+            Locale.setDefault(locale);
+            final String levelName = level.getLocalizedName();
+            System.out.println("Level.getLocalizedName() is: " + levelName);
+            if (!levelName.equals(other.toUpperCase(locale))) {
+                throw new RuntimeException("Expected \""
+                        + other.toUpperCase(locale) + "\" for '"
+                        + locale + "' but got \"" + levelName + "\"");
+            }
+            Locale.setDefault(defaultLocale);
+       }
+    }
+
+    private static final String RBNAME = "sun.util.logging.resources.logging";
+    private static String getLocalizedMessage(Locale locale, String key) {
+        ResourceBundle rb = ResourceBundle.getBundle(RBNAME, locale);
+        return rb.getString(key);
+    }
+}
--- a/jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobal.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobal.java	Wed Jul 05 19:11:53 2017 +0200
@@ -57,6 +57,12 @@
     }
 
     public static void main(String... args) {
+        final String manager = System.getProperty("java.util.logging.manager", null);
+
+        final String description = "TestGetGlobal"
+            + (System.getSecurityManager() == null ? " " :
+               " -Djava.security.manager ")
+            + (manager == null ? "" : "-Djava.util.logging.manager=" + manager);
 
         Logger.global.info(messages[0]); // at this point LogManager is not
              // initialized yet, so this message should not appear.
@@ -67,7 +73,9 @@
 
         final List<String> expected = Arrays.asList(Arrays.copyOfRange(messages, 1, messages.length));
         if (!testgetglobal.HandlerImpl.received.equals(expected)) {
-            throw new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected);
+            System.err.println("Test case failed: " + description);
+            throw new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected
+                            + "\n\t"+description);
         }
     }
 }
--- a/jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobalConcurrent.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobalConcurrent.java	Wed Jul 05 19:11:53 2017 +0200
@@ -22,17 +22,18 @@
  */
 import java.util.Arrays;
 import java.util.List;
+import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
  * @test
- * @bug 7184195
- * @summary checks that java.util.logging.Logger.getGlobal().info() logs without configuration
+ * @bug 7184195 8021003
+ * @summary Test that the global logger can log with no configuration when accessed from multiple threads.
  * @build TestGetGlobalConcurrent testgetglobal.HandlerImpl testgetglobal.LogManagerImpl1 testgetglobal.LogManagerImpl2 testgetglobal.LogManagerImpl3 testgetglobal.BadLogManagerImpl testgetglobal.DummyLogManagerImpl
  * @run main/othervm/timeout=10 TestGetGlobalConcurrent
  * @run main/othervm/timeout=10/policy=policy -Djava.security.manager TestGetGlobalConcurrent
- * @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.LogManagerImpl TestGetGlobalConcurrent
- * @run main/othervm/timeout=10/policy=policy -Djava.security.manager -Djava.util.logging.manager=testgetglobal.LogManagerImpl TestGetGlobalConcurrent
+ * @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.LogManagerImpl1 TestGetGlobalConcurrent
+ * @run main/othervm/timeout=10/policy=policy -Djava.security.manager -Djava.util.logging.manager=testgetglobal.LogManagerImpl1 TestGetGlobalConcurrent
  * @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.LogManagerImpl2 TestGetGlobalConcurrent
  * @run main/othervm/timeout=10/policy=policy -Djava.security.manager -Djava.util.logging.manager=testgetglobal.LogManagerImpl2 TestGetGlobalConcurrent
  * @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.LogManagerImpl3 TestGetGlobalConcurrent
@@ -69,7 +70,6 @@
              // initialize the LogManager - and thus this message should appear.
         Logger.global.info(messages[i+1]); // Now that the LogManager is
              // initialized, this message should appear too.
-
         final List<String> expected = Arrays.asList(Arrays.copyOfRange(messages, i, i+2));
         if (!testgetglobal.HandlerImpl.received.containsAll(expected)) {
             fail(new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected));
@@ -82,7 +82,6 @@
              // initialize the LogManager - and thus this message should appear.
         Logger.global.info(messages[i+1]); // Now that the LogManager is
              // initialized, this message should appear too.
-
         final List<String> expected = Arrays.asList(Arrays.copyOfRange(messages, i, i+2));
         if (!testgetglobal.HandlerImpl.received.containsAll(expected)) {
             fail(new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected));
@@ -96,7 +95,6 @@
              // initialize the LogManager - and thus this message should appear.
         Logger.global.info(messages[i+1]); // Now that the LogManager is
              // initialized, this message should appear too.
-
         final List<String> expected = Arrays.asList(Arrays.copyOfRange(messages, i, i+2));
         if (!testgetglobal.HandlerImpl.received.containsAll(expected)) {
             fail(new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected));
@@ -150,8 +148,17 @@
         public void run() { test4(); }
     }
 
+    static String description = "Unknown";
+
     public static void main(String... args) throws Exception {
 
+        final String manager = System.getProperty("java.util.logging.manager", null);
+
+        description = "TestGetGlobalConcurrent"
+            + (System.getSecurityManager() == null ? " " :
+               " -Djava.security.manager ")
+            + (manager == null ? "" : "-Djava.util.logging.manager=" + manager);
+
         final Thread t1 = new Thread(new WaitAndRun(new Run1()), "test1");
         final Thread t2 = new Thread(new WaitAndRun(new Run2()), "test2");
         final Thread t3 = new Thread(new WaitAndRun(new Run3()), "test3");
@@ -169,14 +176,13 @@
 
         final List<String> expected = Arrays.asList(Arrays.copyOfRange(messages, 1, 3));
         if (!testgetglobal.HandlerImpl.received.containsAll(expected)) {
-            throw new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected);
+            fail(new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected));
         }
 
-
         t1.join(); t2.join(); t3.join(); t4.join();
 
         if (failed != null) {
-             throw new Error("Test failed.", failed);
+             throw new Error("Test failed: "+description, failed);
         }
 
         System.out.println("Test passed");
--- a/jdk/test/java/util/logging/Logger/getGlobal/policy	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/util/logging/Logger/getGlobal/policy	Wed Jul 05 19:11:53 2017 +0200
@@ -1,6 +1,7 @@
 grant {
     permission java.util.PropertyPermission "java.util.logging.config.file", "write";
     permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "java.util.logging.manager", "read";
     permission java.lang.RuntimePermission "setContextClassLoader";
     permission java.lang.RuntimePermission "shutdownHooks";
     permission java.util.logging.LoggingPermission "control";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/logging/Logger/isLoggable/TestIsLoggable.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,512 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogManager;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
+/**
+ * @test
+ * @bug 8024525
+ * @summary checks that isLoggable() can be overridden to control logging.
+ * @author danielfuchs
+ * @run main/othervm TestIsLoggable
+ */
+public class TestIsLoggable {
+
+    // This logger can be configured to override its default level
+    // for a particular set of thread ids
+    public static final class ThreadLogger extends Logger {
+
+       final Map<Long, Level> threadMap =
+                Collections.synchronizedMap(new HashMap<Long, Level>());
+
+        public ThreadLogger(String name) {
+            super(name, null);
+        }
+
+        @Override
+        public boolean isLoggable(Level level) {
+            final Level threadLevel = threadMap.get(Thread.currentThread().getId());
+            if (threadLevel == null) return super.isLoggable(level);
+            final int levelValue = threadLevel.intValue();
+            final int offValue = Level.OFF.intValue();
+            if (level.intValue() < levelValue || levelValue == offValue) {
+                return false;
+            }
+            return true;
+        }
+
+    }
+
+    public static final class TestHandler extends Handler {
+
+        final List<String> messages = new CopyOnWriteArrayList<>();
+
+        @Override
+        public void publish(LogRecord record) {
+            messages.add(record.getMessage());
+        }
+
+        @Override
+        public void flush() {
+        }
+
+        @Override
+        public void close() throws SecurityException {
+            messages.clear();
+        }
+
+    }
+
+    // Sorted list of standard levels
+    static final List<Level> LEVELS = Collections.unmodifiableList(
+            java.util.Arrays.asList(new Level[] {
+                Level.SEVERE, Level.WARNING, Level.INFO, Level.CONFIG,
+                Level.FINE, Level.FINER, Level.FINEST
+            }));
+
+    // Test cases:
+    //   LEV_   test logger.severe(msg) .. logger.finest(msg)
+    //   LOG_   logger.log(Level.SEVERE, msg) ... logger.log(Level.FINEST, msg)
+    //   LOG1_  logger.log(Level.SEVERE, msg, param1) ...
+    //   LOG2_  logger.log(Level.SEVERE, msg, params[]) ...
+    //   LOG3_  logger.log(Level.SEVERE, msg, throwable) ...
+    //   LOGP_  logger.logp(Level.SEVERE, class, method, msg) ...
+    //   LOGP1_ logger.logp(Level.SEVERE, class, method, msg, param1) ...
+    //   LOGP2_ logger.logp(Level.SEVERE, class, method, msg, params[]) ...
+    //   LOGP3_ logger.logp(Level.SEVERE, class, method, msg, throwable) ...
+    public static enum LogTest {
+        LEV_SEVERE, LEV_WARNING, LEV_INFO, LEV_CONFIG, LEV_FINE, LEV_FINER, LEV_FINEST,
+        LOG_SEVERE, LOG_WARNING, LOG_INFO, LOG_CONFIG, LOG_FINE, LOG_FINER, LOG_FINEST,
+        LOG1_SEVERE, LOG1_WARNING, LOG1_INFO, LOG1_CONFIG, LOG1_FINE, LOG1_FINER, LOG1_FINEST,
+        LOG2_SEVERE, LOG2_WARNING, LOG2_INFO, LOG2_CONFIG, LOG2_FINE, LOG2_FINER, LOG2_FINEST,
+        LOG3_SEVERE, LOG3_WARNING, LOG3_INFO, LOG3_CONFIG, LOG3_FINE, LOG3_FINER, LOG3_FINEST,
+        LOGP_SEVERE, LOGP_WARNING, LOGP_INFO, LOGP_CONFIG, LOGP_FINE, LOGP_FINER, LOGP_FINEST,
+        LOGP1_SEVERE, LOGP1_WARNING, LOGP1_INFO, LOGP1_CONFIG, LOGP1_FINE, LOGP1_FINER, LOGP1_FINEST,
+        LOGP2_SEVERE, LOGP2_WARNING, LOGP2_INFO, LOGP2_CONFIG, LOGP2_FINE, LOGP2_FINER, LOGP2_FINEST,
+        LOGP3_SEVERE, LOGP3_WARNING, LOGP3_INFO, LOGP3_CONFIG, LOGP3_FINE, LOGP3_FINER, LOGP3_FINEST;
+
+        // call the method Logger.severe() ... Logger.finest() corresponding
+        // to the given level 'l' (severe() for SEVERE etc...)
+        public void loglevel(Level l, Logger logger, String message) {
+            LogTest test = LogTest.valueOf("LEV_"+l.getName());
+            switch(test) {
+                case LEV_SEVERE:
+                    logger.severe(message);
+                    break;
+                case LEV_WARNING:
+                    logger.warning(message);
+                    break;
+                case LEV_INFO:
+                    logger.info(message);
+                    break;
+                case LEV_CONFIG:
+                    logger.config(message);
+                    break;
+                case LEV_FINE:
+                    logger.fine(message);
+                    break;
+                case LEV_FINER:
+                    logger.finer(message);
+                    break;
+                case LEV_FINEST:
+                    logger.finest(message);
+                    break;
+            }
+        }
+
+        // The threshold at which the logger is expected to start logging.
+        // trick: we derive the threshold level from the testcase name...
+        public Level threshold() {
+            for (Level l : LEVELS ) {
+                if (this.toString().endsWith(l.getName())) {
+                    return l;
+                }
+            }
+            return Level.OFF;
+        }
+
+        // Levels for which the logger is expected to log something.
+        public List<Level> loggable() {
+            return LEVELS.subList(0, LEVELS.indexOf(threshold())+1);
+        }
+
+        // Levels which will be blocked because they are weaker than the
+        // threshold()
+        public List<Level> weaker() {
+            return LEVELS.subList(LEVELS.indexOf(threshold())+1, LEVELS.size());
+        }
+
+        // Log a message at this testcase threshold, using this testcase method.
+        public void log(Logger logger, String message) {
+            log(threshold(), logger, message);
+        }
+
+        // Log a message at the given level, using this testcase method.
+        public void log(Level level, Logger logger, String message) {
+            if (this.toString().startsWith("LOG_")) {
+                logger.log(level, message);
+            } else if (this.toString().startsWith("LOG1_")) {
+                logger.log(level, message, "dummy param");
+            } else if (this.toString().startsWith("LOG2_")) {
+                logger.log(level, message, new Object[] {"dummy", "param"});
+            } else if (this.toString().startsWith("LOG3_")) {
+                logger.log(level, message, new Exception("dummy exception"));
+            } else if (this.toString().startsWith("LOGP_")) {
+                logger.logp(level, "TestCase", "log", message);
+            } else if (this.toString().startsWith("LOGP1_")) {
+                logger.logp(level, "TestCase", "log", message, "dummy param");
+            } else if (this.toString().startsWith("LOGP2_")) {
+                logger.logp(level, "TestCase", "log", message,
+                        new Object[] {"dummy", "param"});
+            } else if (this.toString().startsWith("LOGP3_")) {
+                logger.logp(level, "TestCase", "log", message,
+                        new Exception("dummy exception"));
+            } else if (this.toString().startsWith("LEV_")) {
+                loglevel(level, logger, message);
+            }
+        }
+
+        // String description of the logging method called.
+        public String method() {
+            if (this.toString().startsWith("LOG_")) {
+                return "Logger.log(Level." + threshold().getName() +", msg): ";
+            } else if (this.toString().startsWith("LOG1_")) {
+                return "Logger.log(Level." + threshold().getName() +", msg, param1): ";
+            } else if (this.toString().startsWith("LOG2_")) {
+                return "Logger.log(Level." + threshold().getName() +", msg, params[]): ";
+            } else if (this.toString().startsWith("LOG3_")) {
+                return "Logger.log(Level." + threshold().getName() +", msg, throwable): ";
+            } else if (this.toString().startsWith("LEV_")) {
+                return "Logger."+threshold().getName().toLowerCase(Locale.ROOT)+"(): ";
+            } else if (this.toString().startsWith("LOGP_")) {
+                return "Logger.logp(Level." + threshold().getName() +", msg): ";
+            } else if (this.toString().startsWith("LOGP1_")) {
+                return "Logger.logp(Level." + threshold().getName() +", msg, param1): ";
+            } else if (this.toString().startsWith("LOGP2_")) {
+                return "Logger.logp(Level." + threshold().getName() +", msg, params[]): ";
+            } else if (this.toString().startsWith("LOGP3_")) {
+                return "Logger.logp(Level." + threshold().getName() +", msg, throwable): ";
+            }
+            throw new RuntimeException("Unknown test case: "+this);
+        }
+    }
+
+    // The purpose of this test is to verify that the various log methods in
+    // Logger now call Logger.isLoggable().
+    // To do that - we're going to use a subclass of Logger, ThreadLogger, which
+    // only overrides isLoggable() - and compare the level it is given to a level
+    // it finds in a map indexed with the current thread id.
+    // We will register a TestHandler with our ThreadLogger which will store
+    // the messages in a messages map. This will allow us to verify whether the
+    // logging method we're testing has or hasn't logged.
+    //
+    // The TestCase enum above allows us to test a combination of every possible
+    // log method with every possible level inside a loop - with the
+    // exception of exiting/entering/throwing that we will be testing
+    // outside of that loop.
+    //
+    public static void main(String... args) {
+        LogManager manager = LogManager.getLogManager();
+        ThreadLogger logger = new ThreadLogger("foo.bar");
+        //manager.addLogger(logger);
+        TestHandler handler = new TestHandler();
+        logger.addHandler(handler);
+
+        //By default, logger's level is Level.INFO
+        final List<Level> loggable = LEVELS.subList(0, LEVELS.indexOf(Level.INFO)+1);
+
+        // Check our test implementation of logger.isLoggable();
+        //
+        // Since we haven't put anything in the threadMap, isLoggable() should
+        // return true for all levels stronger or equals to Level.INFO.
+        // here we're just checking that our implementation of
+        // ThreadLogger.isLoggable() returns what we want - we're just testing
+        // the test code...
+        for (Level level : LEVELS) {
+            if (logger.isLoggable(level) != loggable.contains(level)) {
+                throw new RuntimeException(level +
+                        ": unexpected result for isLoggable(): expected " +
+                        (loggable.contains(level)));
+            }
+        }
+
+        // Test that entering/exiting/throwing call isLoggable()
+
+        // Here we test the default behavior: this call shouldn't log anything
+        //   because by default the logger level is Level.INFO and these
+        //   methods log at Level.FINER.
+        // So by default - these methods don't log anything. We check it here.
+        logger.entering("blah", "blah");
+        logger.entering("blah", "blah", "blah");
+        logger.entering("blah", "blah", new Object[] {"blah"});
+        if (!handler.messages.isEmpty()) {
+            throw new RuntimeException("Expected empty, got "+handler.messages);
+        }
+
+        logger.exiting("blah", "blah");
+        logger.exiting("blah", "blah", "blah");
+        logger.exiting("blah", "blah", new Object[] {"blah"});
+        if (!handler.messages.isEmpty()) {
+            throw new RuntimeException("Expected empty, got "+handler.messages);
+        }
+
+        logger.throwing("blah", "blah", new Exception("blah"));
+        if (!handler.messages.isEmpty()) {
+            throw new RuntimeException("Expected empty, got "+handler.messages);
+        }
+
+        // Now we're going to put each level in turn in the threadMap.
+        // This means that isLoggable(Level.FINER) should now return true if the
+        // level in the map is not one of the level in the 'stronger' list below
+        // (here stronger=stronger than FINER)
+        final List<Level> stronger = LEVELS.subList(0, LEVELS.indexOf(Level.FINER));
+        for (Level l : LEVELS) {
+
+            logger.threadMap.put(Thread.currentThread().getId(), l);
+
+            // Check that our implementation of isLoggable(level) now returns true
+            // if 'level' is stronger or equals to 'l' - here we're just checking
+            // that our implementation of ThreadLogger.isLoggable() returns what
+            // we want - we're just testing the test code...
+            final List<Level> loggableLevels = LEVELS.subList(0, LEVELS.indexOf(l)+1);
+            for (Level level : LEVELS) {
+                if (logger.isLoggable(level) != loggableLevels.contains(level)) {
+                    throw new RuntimeException(level +
+                            ": unexpected result for isLoggable(): expected " +
+                            (loggableLevels.contains(level)));
+                }
+            }
+
+            // These methods should now start to log when the level we put in
+            // the map is weaker or equals to Level.FINER.
+            // This validates that these methods now call ThreadLogger.isLoggable()
+            // since the default level for our logger is still Level.INFO.
+            // If the methods didn't call ThreadLogger.isLoggable() they wouldn't
+            // log anything, whatever we put in the threadMap...
+
+            logger.entering("blah", "blah");
+            logger.entering("blah", "blah", "blah");
+            logger.entering("blah", "blah", new Object[] {"blah"});
+            if (stronger.contains(l)) {
+                if (!handler.messages.isEmpty()) {
+                    throw new RuntimeException(l +
+                            ": Expected empty, got " + handler.messages);
+                }
+            } else {
+                if (handler.messages.size() != 3) {
+                    throw new RuntimeException(l +
+                            ": Expected size 3, got " + handler.messages);
+                }
+            }
+
+            logger.exiting("blah", "blah");
+            logger.exiting("blah", "blah", "blah");
+            logger.exiting("blah", "blah", new Object[] {"blah"});
+            if (stronger.contains(l)) {
+                if (!handler.messages.isEmpty()) {
+                    throw new RuntimeException(l +
+                            ": Expected empty, got " + handler.messages);
+                }
+            } else {
+                if (handler.messages.size() != 6) {
+                    throw new RuntimeException(l +
+                            ": Expected size 6, got " + handler.messages);
+                }
+            }
+
+            logger.throwing("blah", "blah", new Exception("blah"));
+            if (stronger.contains(l)) {
+                if (!handler.messages.isEmpty()) {
+                    throw new RuntimeException(l +
+                            ": Expected empty, got " + handler.messages);
+                }
+            } else {
+                if (handler.messages.size() != 7) {
+                    throw new RuntimeException(l +
+                            ": Expected size 7, got " + handler.messages);
+                }
+            }
+            if (!stronger.contains(l)) {
+                System.out.println(l + ": Logger.entering/exiting/throwing: " +
+                        handler.messages);
+            }
+            handler.messages.clear();
+        }
+
+        // Cleanup so that we can start the next test with a clean plate...
+        handler.messages.clear();
+        logger.threadMap.clear();
+
+        // Test that each logging method calls isLoggable()
+        //
+        for (LogTest testCase : LogTest.values()) {
+            // Each test case is a combination of:
+            //    1. A level to put in the threadMap.
+            //    2. A log method to call
+            final String method = testCase.method();
+
+            // check our implementation of logger.isLoggable();
+            // by default the logger level is Level.INFO, so our implementation
+            // of isLoggable() should return true for all levels stronger or
+            // equal to INFO and false for the others.
+            // We check that here.
+            for (Level level : LEVELS) {
+                if (logger.isLoggable(level) != loggable.contains(level)) {
+                    throw new RuntimeException(level +
+                            ": unexpected result for isLoggable(): expected " +
+                            (loggable.contains(level)));
+                }
+            }
+
+            // Check that by default the log method will not log for level
+            // weaker than Level.INFO.
+            for (Level l : LEVELS.subList(LEVELS.indexOf(Level.INFO) + 1, LEVELS.size())) {
+                final String test = method + l + ": ";
+                testCase.log(l, logger, "blah");
+                if (!handler.messages.isEmpty()) {
+                    throw new RuntimeException(test +
+                            "Expected empty, got " + handler.messages);
+                }
+            }
+
+            // Let's put Level.OFF in the threadMap. Nothing should be logged,
+            // whichever level is used...
+            logger.threadMap.put(Thread.currentThread().getId(), Level.OFF);
+
+            // Check that isLoggable() now always return false.
+            for (Level level : LEVELS) {
+                if (logger.isLoggable(level)) {
+                    throw new RuntimeException(level +
+                            ": unexpected result for isLoggable(): expected " +
+                            false);
+                }
+            }
+
+            // Check that the log method of the test case won't log, whatever
+            // level we pass to it. This validates that level method calls
+            // isLoggable() - because otherwise it would log for levels stronger
+            // or equal to INFO.
+            for (Level l : LEVELS) {
+                final String test = "[threadMap=OFF] " + method + l + ": ";
+                testCase.log(l, logger, "blah");
+                if (!handler.messages.isEmpty()) {
+                    throw new RuntimeException(test +
+                            "Expected empty, got " + handler.messages);
+                }
+            }
+            System.out.println("[threadMap=OFF] " + method + "logged " + handler.messages);
+
+            // Now put the testcase's level in the threadMap.
+            logger.threadMap.put(Thread.currentThread().getId(), testCase.threshold());
+
+            // The levels for which logging should happen are those that are stronger
+            // or equals to the testcase's  thresholds.
+            final List<Level> loggableLevels =
+                    LEVELS.subList(0, LEVELS.indexOf(testCase.threshold())+1);
+
+            // Check that our implementation of isLoggable() is taking into account
+            // what we put in the map.
+            for (Level level : LEVELS) {
+                if (logger.isLoggable(level) != loggableLevels.contains(level)) {
+                    throw new RuntimeException(level +
+                            ": unexpected result for isLoggable(): expected " +
+                            (loggableLevels.contains(level)));
+                }
+            }
+
+            // Now check that the log method is indeed calling our implementation
+            // of isLoggable(). We do this by first verifying that it won't log
+            // for levels weaker than what we put in the map.
+            //
+            for (Level l : testCase.weaker()) {
+                final String test = method + l + ": ";
+                testCase.log(l, logger, "blah");
+                if (!handler.messages.isEmpty()) {
+                    throw new RuntimeException(test +
+                            "Expected empty, got " + handler.messages);
+                }
+            }
+
+            // Then we check that it will log for the testcase threshold.
+            final String test2 = method + testCase.threshold() + ": ";
+            testCase.log(logger, testCase.threshold() + " blah");
+            if (handler.messages.isEmpty()) {
+                throw new RuntimeException(test2 +
+                        "Expected 1 message, but list is empty");
+            }
+            if (!handler.messages.contains(testCase.threshold() + " blah")) {
+                throw new RuntimeException(test2 + " blah not found: "
+                        + handler.messages);
+            }
+            handler.messages.clear();
+
+            // Now we check that it logs for all 'loggable' level (and doesn't
+            // log for the others).
+            for (Level l : LEVELS) {
+                final String test = method + l + ": ";
+                testCase.log(l, logger, l + ": blah");
+                if (testCase.loggable().contains(l)) {
+                    if (!handler.messages.contains(l + ": blah")) {
+                        throw new RuntimeException(test + "blah not found: " +
+                                handler.messages);
+                    }
+                } else {
+                    if (handler.messages.contains(l + ": blah")) {
+                        throw new RuntimeException(test + "blah found: " +
+                                handler.messages);
+                    }
+                }
+            }
+            if (handler.messages.size() != testCase.loggable().size()) {
+                throw new RuntimeException(method +
+                        " Sizes don't match: expected " +
+                        testCase.loggable().size() + " got " +
+                        handler.messages);
+            }
+
+            // Some visual feedback on what happened.
+            System.out.println(method + "logged " + handler.messages);
+
+            // Cleanup for next step.
+            // Since we're iterating over all possible levels we can be
+            // sure that we haven't missed anything.
+            // For instance - it could be argued that logger.severe() will
+            // always log. But since we have 1 case where we put Level.OFF in
+            // the map and we have verified that severe() didn't log in that
+            // case, but that it logged in any other case, then we know
+            // beyond doubt that it called our implementation of isLoggable().
+            logger.threadMap.clear();
+            handler.messages.clear();
+        }
+
+    }
+}
--- a/jdk/test/java/util/logging/ParentLoggersTest.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/util/logging/ParentLoggersTest.java	Wed Jul 05 19:11:53 2017 +0200
@@ -29,7 +29,7 @@
  * @author  ss45998
  *
  * @build ParentLoggersTest
- * @run main/othervm ParentLoggersTest
+ * @run main ParentLoggersTest
  */
 
 /*
--- a/jdk/test/java/util/logging/TestAppletLoggerContext.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/util/logging/TestAppletLoggerContext.java	Wed Jul 05 19:11:53 2017 +0200
@@ -38,7 +38,7 @@
 
 /*
  * @test
- * @bug 8017174 8010727
+ * @bug 8017174 8010727 8019945
  * @summary  NPE when using Logger.getAnonymousLogger or
  *           LogManager.getLogManager().getLogger
  *
@@ -110,28 +110,19 @@
             }
 
             TestExc exc;
-            TestExc global = new TestExc();
 
             @Override
-            public Object getContext() { return active ? global : null; }
-            @Override
-            public Object getExecutionContext() { return active ? exc : null; }
+            public Object getAppletContext() { return active ? exc : null; }
             @Override
-            public Object get(Object o, Object o1) { return TestExc.exc(o).get(o1); }
-            @Override
-            public void put(Object o, Object o1, Object o2) { TestExc.exc(o).put(o1, o2); }
+            public Object get(Object o) { return exc.get(o); }
             @Override
-            public void remove(Object o, Object o1) { TestExc.exc(o).remove(o1); }
-            @Override
-            public Object get(Object o) { return global.get(o); }
+            public void put(Object o, Object o1) { exc.put(o, o1); }
             @Override
-            public void put(Object o, Object o1) { global.put(o, o1); }
-            @Override
-            public void remove(Object o) { global.remove(o); }
+            public void remove(Object o) { exc.remove(o); }
             @Override
             public boolean isDisposed() { return false; }
             @Override
-            public boolean isMainAppContext() { return exc == null; }
+            public boolean isMainAppContext() { return !active || exc == null; }
         }
 
         final static JavaAWTAccessStub javaAwtAccess = new JavaAWTAccessStub();
@@ -441,45 +432,36 @@
             assertNull(manager.getLogger(""));
             assertNull(manager.getLogger(""));
 
-            Bridge.changeContext();
+            for (int j = 0; j<3; j++) {
+                Bridge.changeContext();
 
-            // this is not a supported configuration:
-            // We are in an applet context with several log managers.
-            // We however need to check our assumptions...
+                // this is not a supported configuration:
+                // We are in an applet context with several log managers.
+                // We however need to check our assumptions...
 
-            // Applet context => root logger and global logger are not null.
-            //   root == LogManager.getLogManager().rootLogger
-            //   global == Logger.global
+                // Applet context => root logger and global logger should also be null.
 
-            Logger logger3 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
-            Logger logger3b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
-            assertNotNull(logger3);
-            assertNotNull(logger3b);
-            Logger expected = (System.getSecurityManager() != null
-                  ? Logger.getGlobal()
-                  : global);
-            assertEquals(logger3, expected); // in applet context, we will not see
-                  // the LogManager's custom global logger added above...
-            assertEquals(logger3b, expected); // in applet context, we will not see
-                  // the LogManager's custom global logger added above...
-            Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME);
-            manager.addLogger(global2); // adding a global logger will not work in applet context
-               // we will always get back the global logger.
-               // this could be considered as a bug...
-            Logger logger4 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
-            Logger logger4b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
-            assertNotNull(logger4);
-            assertNotNull(logger4b);
-            assertEquals(logger4,  expected); // adding a global logger will not work in applet context
-            assertEquals(logger4b, expected); // adding a global logger will not work in applet context
+                Logger expected = (System.getSecurityManager() == null ? global : null);
+                Logger logger3 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
+                Logger logger3b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
+                assertEquals(expected, logger3);
+                assertEquals(expected, logger3b);
+                Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME);
+                manager.addLogger(global2);
+                Logger logger4 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
+                Logger logger4b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
+                assertNotNull(logger4);
+                assertNotNull(logger4b);
+                expected = (System.getSecurityManager() == null ? global : global2);;
+                assertEquals(logger4,  expected);
+                assertEquals(logger4b, expected);
 
-            Logger logger5 = manager.getLogger("");
-            Logger logger5b = manager.getLogger("");
-            Logger expectedRoot = (System.getSecurityManager() != null
-                  ? LogManager.getLogManager().getLogger("")
-                  : null);
-            assertEquals(logger5, expectedRoot);
-            assertEquals(logger5b, expectedRoot);
+                Logger logger5 = manager.getLogger("");
+                Logger logger5b = manager.getLogger("");
+                Logger expectedRoot = null;
+                assertEquals(logger5, expectedRoot);
+                assertEquals(logger5b, expectedRoot);
+            }
 
         }
     }
@@ -520,57 +502,53 @@
             assertEquals(logger4, root);
             assertEquals(logger4b, root);
 
-            Bridge.changeContext();
+            for (int j = 0 ; j < 3 ; j++) {
+                Bridge.changeContext();
 
-            // this is not a supported configuration:
-            // We are in an applet context with several log managers.
-            // We haowever need to check our assumptions...
+                // this is not a supported configuration:
+                // We are in an applet context with several log managers.
+                // We however need to check our assumptions...
 
-            // Applet context => root logger and global logger are not null.
-            //   root == LogManager.getLogManager().rootLogger
-            //   global == Logger.global
+                // Applet context => root logger and global logger should also be null.
 
-            Logger logger5 = manager.getLogger("");
-            Logger logger5b = manager.getLogger("");
-            Logger expectedRoot = (System.getSecurityManager() != null
-                  ? LogManager.getLogManager().getLogger("")
-                  : root);
+                Logger logger5 = manager.getLogger("");
+                Logger logger5b = manager.getLogger("");
+                Logger expectedRoot = (System.getSecurityManager() == null ? root : null);
+                assertEquals(logger5, expectedRoot);
+                assertEquals(logger5b, expectedRoot);
 
-            assertNotNull(logger5);
-            assertNotNull(logger5b);
-            assertEquals(logger5, expectedRoot);
-            assertEquals(logger5b, expectedRoot);
-            if (System.getSecurityManager() != null) {
-                assertNotEquals(logger5, root);
-                assertNotEquals(logger5b, root);
-            }
+                if (System.getSecurityManager() != null) {
+                    assertNull(manager.getLogger(Logger.GLOBAL_LOGGER_NAME));
+                } else {
+                    assertEquals(global, manager.getLogger(Logger.GLOBAL_LOGGER_NAME));
+                }
 
-            Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME);
-            manager.addLogger(global2); // adding a global logger will not work in applet context
-               // we will always get back the global logger.
-               // this could be considered as a bug...
-            Logger logger6 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
-            Logger logger6b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
-            Logger expectedGlobal = (System.getSecurityManager() != null
-                  ? Logger.getGlobal()
-                  : global);
-            assertNotNull(logger6);
-            assertNotNull(logger6b);
-            assertEquals(logger6, expectedGlobal); // adding a global logger will not work in applet context
-            assertEquals(logger6b, expectedGlobal); // adding a global logger will not work in applet context
+                Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME);
+                manager.addLogger(global2);
+                Logger logger6 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
+                Logger logger6b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
+                Logger expectedGlobal = (System.getSecurityManager() == null ? global : global2);
 
-            Logger root2 = new Bridge.CustomLogger("");
-            manager.addLogger(root2); // adding a root logger will not work in applet context
-               // we will always get back the default manager's root logger.
-               // this could be considered as a bug...
-            Logger logger7 = manager.getLogger("");
-            Logger logger7b = manager.getLogger("");
-            assertNotNull(logger7);
-            assertNotNull(logger7b);
-            assertEquals(logger7, expectedRoot); // adding a global logger will not work in applet context
-            assertEquals(logger7b, expectedRoot); // adding a global logger will not work in applet context
-            assertNotEquals(logger7, root2);
-            assertNotEquals(logger7b, root2);
+                assertNotNull(logger6);
+                assertNotNull(logger6b);
+                assertEquals(logger6, expectedGlobal);
+                assertEquals(logger6b, expectedGlobal);
+                if (System.getSecurityManager() != null) {
+                    assertNull(manager.getLogger(""));
+                } else {
+                    assertEquals(root, manager.getLogger(""));
+                }
+
+                Logger root2 = new Bridge.CustomLogger("");
+                manager.addLogger(root2);
+                expectedRoot = (System.getSecurityManager() == null ? root : root2);
+                Logger logger7 = manager.getLogger("");
+                Logger logger7b = manager.getLogger("");
+                assertNotNull(logger7);
+                assertNotNull(logger7b);
+                assertEquals(logger7, expectedRoot);
+                assertEquals(logger7b, expectedRoot);
+            }
         }
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/logging/TestLoggingWithMainAppContext.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.logging.Logger;
+import javax.imageio.ImageIO;
+
+/**
+ * @test
+ * @bug 8019853 8023258
+ * @summary Test that the default user context is used when in the main
+ *          application context. This test must not be run in same VM or agent
+ *          VM mode: it would not test the intended behavior.
+ * @run main/othervm TestLoggingWithMainAppContext
+ */
+public class TestLoggingWithMainAppContext {
+
+    public static void main(String[] args) throws IOException {
+        System.out.println("Creating loggers.");
+
+        // These loggers will be created in the default user context.
+        final Logger foo1 = Logger.getLogger( "foo" );
+        final Logger bar1 = Logger.getLogger( "foo.bar" );
+        if (bar1.getParent() != foo1) {
+            throw new RuntimeException("Parent logger of bar1 "+bar1+" is not "+foo1);
+        }
+        System.out.println("bar1.getParent() is the same as foo1");
+
+        // Set a security manager
+        System.setSecurityManager(new SecurityManager());
+        System.out.println("Now running with security manager");
+
+        // Triggers the creation of the main AppContext
+        ByteArrayInputStream is = new ByteArrayInputStream(new byte[] { 0, 1 });
+        ImageIO.read(is); // triggers calls to system loggers & creation of main AppContext
+
+        // verify that we're still using the default user context
+        final Logger bar2 = Logger.getLogger( "foo.bar" );
+        if (bar1 != bar2) {
+            throw new RuntimeException("bar2 "+bar2+" is not the same as bar1 "+bar1);
+        }
+        System.out.println("bar2 is the same as bar1");
+        if (bar2.getParent() != foo1) {
+            throw new RuntimeException("Parent logger of bar2 "+bar2+" is not foo1 "+foo1);
+        }
+        System.out.println("bar2.getParent() is the same as foo1");
+        final Logger foo2 = Logger.getLogger("foo");
+        if (foo1 != foo2) {
+            throw new RuntimeException("foo2 "+foo2+" is not the same as foo1 "+foo1);
+        }
+        System.out.println("foo2 is the same as foo1");
+
+        System.out.println("Test passed.");
+    }
+}
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/DoubleStreamTestScenario.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/util/stream/bootlib/java/util/stream/DoubleStreamTestScenario.java	Wed Jul 05 19:11:53 2017 +0200
@@ -40,7 +40,7 @@
 @SuppressWarnings({"rawtypes", "unchecked"})
 public enum DoubleStreamTestScenario implements OpTestCase.BaseStreamTestScenario {
 
-    STREAM_FOR_EACH(false) {
+    STREAM_FOR_EACH_WITH_CLOSE(false) {
         <T, S_IN extends BaseStream<T, S_IN>>
         void _run(TestData<T, S_IN> data, DoubleConsumer b, Function<S_IN, DoubleStream> m) {
             DoubleStream s = m.apply(data.stream());
@@ -48,6 +48,7 @@
                 s = s.sequential();
             }
             s.forEach(b);
+            s.close();
         }
     },
 
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/IntStreamTestScenario.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/util/stream/bootlib/java/util/stream/IntStreamTestScenario.java	Wed Jul 05 19:11:53 2017 +0200
@@ -40,7 +40,7 @@
 @SuppressWarnings({"rawtypes", "unchecked"})
 public enum IntStreamTestScenario implements OpTestCase.BaseStreamTestScenario {
 
-    STREAM_FOR_EACH(false) {
+    STREAM_FOR_EACH_WITH_CLOSE(false) {
         <T, S_IN extends BaseStream<T, S_IN>>
         void _run(TestData<T, S_IN> data, IntConsumer b, Function<S_IN, IntStream> m) {
             IntStream s = m.apply(data.stream());
@@ -48,6 +48,7 @@
                 s = s.sequential();
             }
             s.forEach(b);
+            s.close();
         }
     },
 
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/LongStreamTestScenario.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/util/stream/bootlib/java/util/stream/LongStreamTestScenario.java	Wed Jul 05 19:11:53 2017 +0200
@@ -40,7 +40,7 @@
 @SuppressWarnings({"rawtypes", "unchecked"})
 public enum LongStreamTestScenario implements OpTestCase.BaseStreamTestScenario {
 
-    STREAM_FOR_EACH(false) {
+    STREAM_FOR_EACH_WITH_CLOSE(false) {
         <T, S_IN extends BaseStream<T, S_IN>>
         void _run(TestData<T, S_IN> data, LongConsumer b, Function<S_IN, LongStream> m) {
             LongStream s = m.apply(data.stream());
@@ -48,6 +48,7 @@
                 s = s.sequential();
             }
             s.forEach(b);
+            s.close();
         }
     },
 
--- a/jdk/test/java/util/stream/bootlib/java/util/stream/StreamTestScenario.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/java/util/stream/bootlib/java/util/stream/StreamTestScenario.java	Wed Jul 05 19:11:53 2017 +0200
@@ -39,7 +39,7 @@
 @SuppressWarnings({"rawtypes", "unchecked"})
 public enum StreamTestScenario implements OpTestCase.BaseStreamTestScenario {
 
-    STREAM_FOR_EACH(false) {
+    STREAM_FOR_EACH_WITH_CLOSE(false) {
         <T, U, S_IN extends BaseStream<T, S_IN>>
         void _run(TestData<T, S_IN> data, Consumer<U> b, Function<S_IN, Stream<U>> m) {
             Stream<U> s = m.apply(data.stream());
@@ -47,6 +47,7 @@
                 s = s.sequential();
             }
             s.forEach(b);
+            s.close();
         }
     },
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/StreamCloseTest.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.tests.java.util.stream;
+
+import java.util.Arrays;
+import java.util.stream.OpTestCase;
+import java.util.stream.Stream;
+
+import org.testng.annotations.Test;
+
+import static java.util.stream.LambdaTestHelpers.countTo;
+
+/**
+ * StreamCloseTest
+ *
+ * @author Brian Goetz
+ */
+@Test(groups = { "serialization-hostile" })
+public class StreamCloseTest extends OpTestCase {
+    public void testEmptyCloseHandler() {
+        try (Stream<Integer> ints = countTo(100).stream()) {
+            ints.forEach(i -> {});
+        }
+    }
+
+    public void testOneCloseHandler() {
+        final boolean[] holder = new boolean[1];
+        Runnable closer = () -> { holder[0] = true; };
+
+        try (Stream<Integer> ints = countTo(100).stream()) {
+            ints.onClose(closer);
+            ints.forEach(i -> {});
+        }
+        assertTrue(holder[0]);
+
+        Arrays.fill(holder, false);
+        try (Stream<Integer> ints = countTo(100).stream().onClose(closer)) {
+            ints.forEach(i -> {});
+        }
+        assertTrue(holder[0]);
+
+        Arrays.fill(holder, false);
+        try (Stream<Integer> ints = countTo(100).stream().filter(e -> true).onClose(closer)) {
+            ints.forEach(i -> {});
+        }
+        assertTrue(holder[0]);
+
+        Arrays.fill(holder, false);
+        try (Stream<Integer> ints = countTo(100).stream().filter(e -> true).onClose(closer).filter(e -> true)) {
+            ints.forEach(i -> {});
+        }
+        assertTrue(holder[0]);
+    }
+
+    public void testTwoCloseHandlers() {
+        final boolean[] holder = new boolean[2];
+        Runnable close1 = () -> { holder[0] = true; };
+        Runnable close2 = () -> { holder[1] = true; };
+
+        try (Stream<Integer> ints = countTo(100).stream()) {
+            ints.onClose(close1).onClose(close2);
+            ints.forEach(i -> {});
+        }
+        assertTrue(holder[0] && holder[1]);
+
+        Arrays.fill(holder, false);
+        try (Stream<Integer> ints = countTo(100).stream().onClose(close1).onClose(close2)) {
+            ints.forEach(i -> {});
+        }
+        assertTrue(holder[0] && holder[1]);
+
+        Arrays.fill(holder, false);
+        try (Stream<Integer> ints = countTo(100).stream().filter(e -> true).onClose(close1).onClose(close2)) {
+            ints.forEach(i -> {});
+        }
+        assertTrue(holder[0] && holder[1]);
+
+        Arrays.fill(holder, false);
+        try (Stream<Integer> ints = countTo(100).stream().filter(e -> true).onClose(close1).onClose(close2).filter(e -> true)) {
+            ints.forEach(i -> {});
+        }
+        assertTrue(holder[0] && holder[1]);
+    }
+
+    public void testCascadedExceptions() {
+        final boolean[] holder = new boolean[3];
+        boolean caught = false;
+        Runnable close1 = () -> { holder[0] = true; throw new RuntimeException("1"); };
+        Runnable close2 = () -> { holder[1] = true; throw new RuntimeException("2"); };
+        Runnable close3 = () -> { holder[2] = true; throw new RuntimeException("3"); };
+
+        try (Stream<Integer> ints = countTo(100).stream()) {
+            ints.onClose(close1).onClose(close2).onClose(close3);
+            ints.forEach(i -> {});
+        }
+        catch (RuntimeException e) {
+            assertCascaded(e, 3);
+            assertTrue(holder[0] && holder[1] && holder[2]);
+            caught = true;
+        }
+        assertTrue(caught);
+
+        Arrays.fill(holder, false);
+        caught = false;
+        try (Stream<Integer> ints = countTo(100).stream().onClose(close1).onClose(close2).onClose(close3)) {
+            ints.forEach(i -> {});
+        }
+        catch (RuntimeException e) {
+            assertCascaded(e, 3);
+            assertTrue(holder[0] && holder[1] && holder[2]);
+            caught = true;
+        }
+        assertTrue(caught);
+
+        caught = false;
+        Arrays.fill(holder, false);
+        try (Stream<Integer> ints = countTo(100).stream().filter(e -> true).onClose(close1).onClose(close2).onClose(close3)) {
+            ints.forEach(i -> {});
+        }
+        catch (RuntimeException e) {
+            assertCascaded(e, 3);
+            assertTrue(holder[0] && holder[1] && holder[2]);
+            caught = true;
+        }
+        assertTrue(caught);
+
+        caught = false;
+        Arrays.fill(holder, false);
+        try (Stream<Integer> ints = countTo(100).stream().filter(e -> true).onClose(close1).onClose(close2).filter(e -> true).onClose(close3)) {
+            ints.forEach(i -> {});
+        }
+        catch (RuntimeException e) {
+            assertCascaded(e, 3);
+            assertTrue(holder[0] && holder[1] && holder[2]);
+            caught = true;
+        }
+        assertTrue(caught);
+    }
+
+    private void assertCascaded(RuntimeException e, int n) {
+        assertTrue(e.getMessage().equals("1"));
+        assertTrue(e.getSuppressed().length == n - 1);
+        for (int i=0; i<n-1; i++)
+        assertTrue(e.getSuppressed()[i].getMessage().equals(String.valueOf(i + 2)));
+    }
+}
--- a/jdk/test/javax/imageio/plugins/jpeg/JpegWriterLeakTest.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/javax/imageio/plugins/jpeg/JpegWriterLeakTest.java	Wed Jul 05 19:11:53 2017 +0200
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @bug     8020983
+ * @bug     8020983 8024697
  * @summary Test verifies that jpeg writer instances are collected
  *          even if destroy() or reset() methods is not invoked.
  *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/MBeanInfo/MBeanInfoHashCodeNPETest.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import javax.management.MBeanAttributeInfo;
+import javax.management.MBeanConstructorInfo;
+import javax.management.MBeanInfo;
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
+import javax.management.modelmbean.DescriptorSupport;
+import javax.management.openmbean.SimpleType;
+
+/*
+ * @test
+ * @bug 8023669
+ * @summary Test that hashCode()throws NullPointerException
+ * @author Shanliang JIANG
+ * @run clean MBeanInfoHashCodeNPETest
+ * @run build MBeanInfoHashCodeNPETest
+ * @run main MBeanInfoHashCodeNPETest
+ */
+public class MBeanInfoHashCodeNPETest {
+    private static int failed = 0;
+
+    public static void main(String[] args) throws Exception {
+        System.out.println("---MBeanInfoHashCodeNPETest-main ...");
+
+        // ----
+        System.out.println("\n---Testing on MBeanAttributeInfo...");
+        MBeanAttributeInfo mbeanAttributeInfo = new MBeanAttributeInfo(
+                null, SimpleType.INTEGER.getClassName(), "description", true, true, false);
+        test(mbeanAttributeInfo, "class name");
+
+        mbeanAttributeInfo = new MBeanAttributeInfo(
+                "name", null, "description", true, true, false);
+        test(mbeanAttributeInfo, "type");
+
+        mbeanAttributeInfo = new MBeanAttributeInfo(
+                "name", SimpleType.INTEGER.getClassName(), null, true, true, false);
+        test(mbeanAttributeInfo, "description");
+
+        // ----
+        System.out.println("\n---Testing on MBeanConstructorInfo...");
+        MBeanConstructorInfo mbeanConstructorInfo = new MBeanConstructorInfo(
+                null, "", new MBeanParameterInfo[]{}, new DescriptorSupport());
+        test(mbeanConstructorInfo, "name");
+
+        mbeanConstructorInfo = new MBeanConstructorInfo(
+                "", null, new MBeanParameterInfo[]{}, new DescriptorSupport());
+        test(mbeanConstructorInfo, "description");
+
+        mbeanConstructorInfo = new MBeanConstructorInfo(
+                "", "", null, new DescriptorSupport());
+        test(mbeanConstructorInfo, "MBeanParameterInfo");
+
+        mbeanConstructorInfo = new MBeanConstructorInfo(
+                "", "", new MBeanParameterInfo[]{}, null);
+        test(mbeanConstructorInfo, "descriptor");
+
+        // ----
+        System.out.println("\n---Testing on MBeanOperationInfo...");
+        MBeanOperationInfo mbeanOperationInfo = new MBeanOperationInfo(
+                null, "description", new MBeanParameterInfo[]{}, "type", 1, new DescriptorSupport());
+        test(mbeanOperationInfo, "name");
+
+        mbeanOperationInfo = new MBeanOperationInfo(
+                "name", null, new MBeanParameterInfo[]{}, "type", 1, new DescriptorSupport());
+        test(mbeanOperationInfo, "description");
+
+        mbeanOperationInfo = new MBeanOperationInfo(
+                "name", "description", null, "type", 1, new DescriptorSupport());
+        test(mbeanOperationInfo, "MBeanParameterInfo");
+
+        mbeanOperationInfo = new MBeanOperationInfo(
+                "name", "description", new MBeanParameterInfo[]{}, null, 1, new DescriptorSupport());
+        test(mbeanOperationInfo, "type");
+
+        mbeanOperationInfo = new MBeanOperationInfo(
+                "name", "description", new MBeanParameterInfo[]{}, "type", -1, new DescriptorSupport());
+        test(mbeanOperationInfo, "native impact");
+
+        mbeanOperationInfo = new MBeanOperationInfo(
+                "name", "description", new MBeanParameterInfo[]{}, "type", 1, null);
+        test(mbeanOperationInfo, "Descriptor");
+
+        // ----
+        System.out.println("\n---Testing on MBeanParameterInfo...");
+        MBeanParameterInfo mbeanParameterInfo = new MBeanParameterInfo(
+                null, "type", "description", new DescriptorSupport());
+        test(mbeanParameterInfo, "name");
+
+        mbeanParameterInfo = new MBeanParameterInfo(
+                "name", null, "description", new DescriptorSupport());
+        test(mbeanParameterInfo, "description");
+
+        mbeanParameterInfo = new MBeanParameterInfo(
+                "name", "type", null, new DescriptorSupport());
+        test(mbeanParameterInfo, "description");
+
+        mbeanParameterInfo = new MBeanParameterInfo(
+                "name", "type", "description", null);
+        test(mbeanParameterInfo, "Descriptor");
+
+        // ----
+        System.out.println("\n---Testing on MBeanInfo...");
+        String className = "toto";
+        String description = "titi";
+        MBeanAttributeInfo[] attrInfos = new MBeanAttributeInfo[]{};
+        MBeanConstructorInfo[] constrInfos = new MBeanConstructorInfo[]{};
+        MBeanOperationInfo[] operaInfos = new MBeanOperationInfo[]{};
+        MBeanNotificationInfo[] notifInfos = new MBeanNotificationInfo[]{};
+
+        MBeanInfo minfo = new MBeanInfo(null, description, attrInfos, constrInfos, operaInfos, notifInfos);
+        test(minfo, "class name");
+
+        minfo = new MBeanInfo(className, description, attrInfos, constrInfos, operaInfos, notifInfos);
+        test(minfo, "name");
+
+        minfo = new MBeanInfo(className, null, attrInfos, constrInfos, operaInfos, notifInfos);
+        test(minfo, "description");
+
+        minfo = new MBeanInfo(className, description, null, constrInfos, operaInfos, notifInfos);
+        test(minfo, "attrInfos");
+
+        minfo = new MBeanInfo(className, description, attrInfos, constrInfos, null, notifInfos);
+        test(minfo, "operaInfos");
+
+        minfo = new MBeanInfo(className, description, attrInfos, constrInfos, operaInfos, null);
+        test(minfo, "notifInfos");
+
+        Thread.sleep(100);
+        if (failed > 0) {
+            throw new RuntimeException("Test failed: "+failed);
+        } else {
+            System.out.println("---Test: PASSED");
+        }
+    }
+
+    private static void test(Object obj, String param) {
+        try {
+            obj.hashCode();
+            System.out.println("OK: "+obj.getClass().getSimpleName()+".hashCode worked with a null "+param);
+        } catch (NullPointerException npe) {
+            System.out.println("--->KO!!! "+obj.getClass().getSimpleName()+".hashCode got NPE with a null "+param);
+            failed++;
+        }
+
+        try {
+            obj.toString();
+            System.out.println("OK: "+obj.getClass().getSimpleName()+".toString worked with a null "+param);
+        } catch (NullPointerException npe) {
+            System.out.println("--->KO!!! "+obj.getClass().getSimpleName()+".toString got NPE.");
+            failed++;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/openmbean/OpenMBeanInfoEqualsNPETest.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import javax.management.MBeanNotificationInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.modelmbean.DescriptorSupport;
+import javax.management.openmbean.OpenMBeanAttributeInfo;
+import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
+import javax.management.openmbean.OpenMBeanConstructorInfo;
+import javax.management.openmbean.OpenMBeanConstructorInfoSupport;
+import javax.management.openmbean.OpenMBeanInfo;
+import javax.management.openmbean.OpenMBeanInfoSupport;
+import javax.management.openmbean.OpenMBeanOperationInfo;
+import javax.management.openmbean.OpenMBeanOperationInfoSupport;
+import javax.management.openmbean.OpenMBeanParameterInfo;
+import javax.management.openmbean.OpenMBeanParameterInfoSupport;
+import javax.management.openmbean.SimpleType;
+
+/*
+ * @test
+ * @bug 8023529
+ * @summary Test that OpenMBean*Info.equals do not throw NPE
+ * @author Shanliang JIANG
+ * @run clean OpenMBeanInfoEqualsNPETest
+ * @run build OpenMBeanInfoEqualsNPETest
+ * @run main OpenMBeanInfoEqualsNPETest
+ */
+public class OpenMBeanInfoEqualsNPETest {
+    private static int failed = 0;
+
+    public static void main(String[] args) throws Exception {
+        System.out.println("---OpenMBeanInfoEqualsNPETest-main ...");
+
+        // ----
+        System.out.println("\n---Testing on OpenMBeanAttributeInfoSupport...");
+        OpenMBeanAttributeInfo openMBeanAttributeInfo0 = new OpenMBeanAttributeInfoSupport(
+                "name", "description", SimpleType.INTEGER, true, true, false, 1, new Integer[]{1, 2, 3});
+        OpenMBeanAttributeInfo openMBeanAttributeInfo = new OpenMBeanAttributeInfoSupport(
+                "name", "description", SimpleType.INTEGER, true, true, false, null, new Integer[]{1, 2, 3});
+        test(openMBeanAttributeInfo0, openMBeanAttributeInfo, "defaultValue");
+
+        openMBeanAttributeInfo = new OpenMBeanAttributeInfoSupport(
+                "name", "description", SimpleType.INTEGER, true, true, false, 1, null);
+        test(openMBeanAttributeInfo0, openMBeanAttributeInfo, "legalValues");
+
+        // ----
+        System.out.println("\n---Testing on OpenMBeanConstructorInfoSupport...");
+        OpenMBeanConstructorInfo openMBeanConstructorInfo0 = new OpenMBeanConstructorInfoSupport(
+                "name", "description", new OpenMBeanParameterInfo[]{}, new DescriptorSupport());
+        OpenMBeanConstructorInfo openMBeanConstructorInfo;
+
+        openMBeanConstructorInfo = new OpenMBeanConstructorInfoSupport(
+                "name", "description", null, new DescriptorSupport());
+        test(openMBeanConstructorInfo0, openMBeanConstructorInfo, "sigs");
+
+        openMBeanConstructorInfo = new OpenMBeanConstructorInfoSupport(
+                "name", "description", new OpenMBeanParameterInfo[]{}, null);
+        test(openMBeanConstructorInfo0, openMBeanConstructorInfo, "Descriptor");
+
+        // ----
+        System.out.println("\n---Testing on OpenMBeanOperationInfoSupport...");
+        OpenMBeanOperationInfo openMBeanOperationInfo0 = new OpenMBeanOperationInfoSupport(
+                "name", "description", new OpenMBeanParameterInfo[]{},  SimpleType.INTEGER, 1, new DescriptorSupport());
+        OpenMBeanOperationInfo openMBeanOperationInfo;
+
+        openMBeanOperationInfo = new OpenMBeanOperationInfoSupport(
+                "name", "description", null,  SimpleType.INTEGER, 1, new DescriptorSupport());
+        test(openMBeanOperationInfo0, openMBeanOperationInfo, "sigs");
+
+        openMBeanOperationInfo = new OpenMBeanOperationInfoSupport(
+                "name", "description", new OpenMBeanParameterInfo[]{},  SimpleType.INTEGER, MBeanOperationInfo.UNKNOWN, null);
+        test(openMBeanOperationInfo0, openMBeanOperationInfo, "Descriptor");
+
+        // ----
+        System.out.println("\n---Testing on OpenMBeanParameterInfoSupport 1...");
+        OpenMBeanParameterInfo openMBeanParameterInfo0 = new OpenMBeanParameterInfoSupport(
+                "name", "description", SimpleType.INTEGER, 0, -1, 1);
+        OpenMBeanParameterInfo openMBeanParameterInfo;
+
+        openMBeanParameterInfo = new OpenMBeanParameterInfoSupport(
+                "name", "description", SimpleType.INTEGER, null, -1, 1);
+        test(openMBeanParameterInfo0, openMBeanParameterInfo, "default value");
+
+        openMBeanParameterInfo = new OpenMBeanParameterInfoSupport(
+                "name", "description", SimpleType.INTEGER, 0, null, 1);
+        test(openMBeanParameterInfo0, openMBeanParameterInfo, "min value");
+
+        openMBeanParameterInfo = new OpenMBeanParameterInfoSupport(
+                "name", "description", SimpleType.INTEGER, 0, -1, null);
+        test(openMBeanParameterInfo0, openMBeanParameterInfo, "max value");
+
+        // ----
+        System.out.println("\n---Testing on OpenMBeanParameterInfoSupport 2...");
+        openMBeanParameterInfo0 = new OpenMBeanParameterInfoSupport(
+                "name", "description", SimpleType.INTEGER, 1, new Integer[]{-1, 1, 2});
+
+        openMBeanParameterInfo = new OpenMBeanParameterInfoSupport(
+                "name", "description", SimpleType.INTEGER, null, new Integer[]{-1, 1, 2});
+        test(openMBeanParameterInfo0, openMBeanParameterInfo, "default value");
+
+        openMBeanParameterInfo = new OpenMBeanParameterInfoSupport(
+                "name", "description", SimpleType.INTEGER, 1, null);
+        test(openMBeanParameterInfo0, openMBeanParameterInfo, "legal values");
+
+        // ----
+        System.out.println("\n---Testing on OpenMBeanInfoSupport...");
+        String className = "toto";
+        String description = "titi";
+        OpenMBeanAttributeInfo[] attrInfos = new OpenMBeanAttributeInfo[]{};
+        OpenMBeanConstructorInfo[] constrInfos = new OpenMBeanConstructorInfo[]{};
+        OpenMBeanOperationInfo[] operaInfos = new OpenMBeanOperationInfo[]{};
+        MBeanNotificationInfo[] notifInfos = new MBeanNotificationInfo[]{};
+
+        OpenMBeanInfo ominfo0 = new OpenMBeanInfoSupport("toto", description, attrInfos, constrInfos, operaInfos, notifInfos);
+        OpenMBeanInfo ominfo = new OpenMBeanInfoSupport(null, description, attrInfos, constrInfos, operaInfos, notifInfos);
+        test(ominfo0, ominfo, "class name");
+
+        ominfo = new OpenMBeanInfoSupport(className, null, attrInfos, constrInfos, operaInfos, notifInfos);
+        test(ominfo0, ominfo, "description");
+
+        ominfo = new OpenMBeanInfoSupport(className, description, null, constrInfos, operaInfos, notifInfos);
+        test(ominfo0, ominfo, "attrInfos");
+
+        ominfo = new OpenMBeanInfoSupport(className, description, attrInfos, null, operaInfos, notifInfos);
+        test(ominfo0, ominfo, "constructor infos");
+
+        ominfo = new OpenMBeanInfoSupport(className, description, attrInfos, constrInfos, null, notifInfos);
+        test(ominfo0, ominfo, "operation infos");
+
+        ominfo = new OpenMBeanInfoSupport(className, description, attrInfos, constrInfos, operaInfos, null);
+        test(ominfo0, ominfo, "notif infos");
+
+        if (failed > 0) {
+            throw new RuntimeException("Test failed: "+failed);
+        } else {
+            System.out.println("---Test: PASSED");
+        }
+    }
+
+    private static void test(Object obj1, Object obj2, String param) {
+        try {
+            obj1.equals(obj2);
+            System.out.println("OK-1: "+obj1.getClass().getSimpleName()+
+                    ".equals worked with a null field: "+param);
+        } catch (NullPointerException npe) {
+            System.out.println("--->KO-1!!! "+obj1.getClass().getSimpleName()+
+                    ".equals got NPE with a null field: "+param);
+            npe.printStackTrace();
+            failed++;
+        }
+
+        try {
+            obj2.equals(obj1);
+            System.out.println("OK-2: "+obj2.getClass().getSimpleName()+
+                    ".equals worked with a null field: "+param);
+        } catch (NullPointerException npe) {
+            System.out.println("--->KO-2!!! "+obj2.getClass().getSimpleName()+
+                    ".equals got NPE with a null field: "+param);
+            npe.printStackTrace();
+            failed++;
+        }
+
+        try {
+            obj1.equals(null);
+            obj2.equals(null);
+
+            System.out.println("OK-3: "+obj1.getClass().getSimpleName()+
+                    ".equals worked with a null object.");
+        } catch (NullPointerException npe) {
+            System.out.println("--->KO-3!!! "+obj1.getClass().getSimpleName()+
+                    ".equals got NPE with a null object.");
+            npe.printStackTrace();
+            failed++;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/openmbean/OpenMBeanInfoHashCodeNPETest.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import javax.management.MBeanNotificationInfo;
+import javax.management.modelmbean.DescriptorSupport;
+import javax.management.openmbean.OpenMBeanAttributeInfo;
+import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
+import javax.management.openmbean.OpenMBeanConstructorInfo;
+import javax.management.openmbean.OpenMBeanConstructorInfoSupport;
+import javax.management.openmbean.OpenMBeanInfo;
+import javax.management.openmbean.OpenMBeanInfoSupport;
+import javax.management.openmbean.OpenMBeanOperationInfo;
+import javax.management.openmbean.OpenMBeanOperationInfoSupport;
+import javax.management.openmbean.OpenMBeanParameterInfo;
+import javax.management.openmbean.OpenMBeanParameterInfoSupport;
+import javax.management.openmbean.SimpleType;
+
+/*
+ * @test
+ * @bug 8023529
+ * @summary Test that OpenMBean*Info.hashCode do not throw NPE
+ * @author Shanliang JIANG
+ * @run clean OpenMBeanInfoHashCodeNPETest
+ * @run build OpenMBeanInfoHashCodeNPETest
+ * @run main OpenMBeanInfoHashCodeNPETest
+ */
+public class OpenMBeanInfoHashCodeNPETest {
+    private static int failed = 0;
+
+    public static void main(String[] args) throws Exception {
+        System.out.println("---OpenMBeanInfoHashCodeNPETest-main ...");
+
+        // ----
+        System.out.println("\n---Testing on OpenMBeanInfohashCodeTest...");
+        OpenMBeanAttributeInfo openMBeanAttributeInfo = new OpenMBeanAttributeInfoSupport(
+                "name", "description", SimpleType.INTEGER, true, true, false, null, new Integer[]{1, 2, 3});
+        test(openMBeanAttributeInfo, "defaultValue");
+
+        openMBeanAttributeInfo = new OpenMBeanAttributeInfoSupport(
+                "name", "description", SimpleType.INTEGER, true, true, false, 1, null);
+        test(openMBeanAttributeInfo, "legalValues");
+
+        // ----
+        System.out.println("\n---Testing on OpenMBeanConstructorInfoSupport...");
+        OpenMBeanConstructorInfo openMBeanConstructorInfo;
+
+        openMBeanConstructorInfo = new OpenMBeanConstructorInfoSupport(
+                "name", "description", null, new DescriptorSupport());
+        test(openMBeanConstructorInfo, "sigs");
+
+        openMBeanConstructorInfo = new OpenMBeanConstructorInfoSupport(
+                "name", "description", new OpenMBeanParameterInfo[]{}, null);
+        test(openMBeanConstructorInfo, "Descriptor");
+
+        // ----
+        System.out.println("\n---Testing on OpenMBeanOperationInfoSupport...");
+        OpenMBeanOperationInfo openMBeanOperationInfo;
+
+        openMBeanOperationInfo = new OpenMBeanOperationInfoSupport(
+                "name", "description", null,  SimpleType.INTEGER, 1, new DescriptorSupport());
+        test(openMBeanOperationInfo, "sigs");
+
+        openMBeanOperationInfo = new OpenMBeanOperationInfoSupport(
+                "name", "description", new OpenMBeanParameterInfo[]{},  SimpleType.INTEGER, 1, null);
+        test(openMBeanOperationInfo, "Descriptor");
+
+        // ----
+        System.out.println("\n---Testing on OpenMBeanParameterInfoSupport 1...");
+        OpenMBeanParameterInfo openMBeanParameterInfo;
+
+        openMBeanParameterInfo = new OpenMBeanParameterInfoSupport(
+                "name", "description", SimpleType.INTEGER, null, -1, 1);
+        test(openMBeanParameterInfo, "default value");
+
+        openMBeanParameterInfo = new OpenMBeanParameterInfoSupport(
+                "name", "description", SimpleType.INTEGER, 0, null, 1);
+        test(openMBeanParameterInfo, "min value");
+
+        openMBeanParameterInfo = new OpenMBeanParameterInfoSupport(
+                "name", "description", SimpleType.INTEGER, 0, -1, null);
+        test(openMBeanParameterInfo, "max value");
+
+        // ----
+        System.out.println("\n---Testing on OpenMBeanParameterInfoSupport 2...");
+        openMBeanParameterInfo = new OpenMBeanParameterInfoSupport(
+                "name", "description", SimpleType.INTEGER, 1, new Integer[]{-1, 1, 2});
+
+        openMBeanParameterInfo = new OpenMBeanParameterInfoSupport(
+                "name", "description", SimpleType.INTEGER, null, new Integer[]{-1, 1, 2});
+        test(openMBeanParameterInfo, "default value");
+
+        openMBeanParameterInfo = new OpenMBeanParameterInfoSupport(
+                "name", "description", SimpleType.INTEGER, 1, null);
+        test(openMBeanParameterInfo, "legal values");
+
+        // ----
+        System.out.println("\n---Testing on OpenMBeanInfoSupport...");
+        String className = "toto";
+        String description = "titi";
+        OpenMBeanAttributeInfo[] attrInfos = new OpenMBeanAttributeInfo[]{};
+        OpenMBeanConstructorInfo[] constrInfos = new OpenMBeanConstructorInfo[]{};
+        OpenMBeanOperationInfo[] operaInfos = new OpenMBeanOperationInfo[]{};
+        MBeanNotificationInfo[] notifInfos = new MBeanNotificationInfo[]{};
+
+        OpenMBeanInfo ominfo = new OpenMBeanInfoSupport(null, description, attrInfos, constrInfos, operaInfos, notifInfos);
+        test(ominfo, "class name");
+
+        ominfo = new OpenMBeanInfoSupport(className, null, attrInfos, constrInfos, operaInfos, notifInfos);
+        test(ominfo, "description");
+
+        ominfo = new OpenMBeanInfoSupport(className, description, null, constrInfos, operaInfos, notifInfos);
+        test(ominfo, "attrInfos");
+
+        ominfo = new OpenMBeanInfoSupport(className, description, attrInfos, null, operaInfos, notifInfos);
+        test(ominfo, "constructor infos");
+
+        ominfo = new OpenMBeanInfoSupport(className, description, attrInfos, constrInfos, null, notifInfos);
+        test(ominfo, "operation infos");
+
+        ominfo = new OpenMBeanInfoSupport(className, description, attrInfos, constrInfos, operaInfos, null);
+        test(ominfo, "notif infos");
+
+        if (failed > 0) {
+            throw new RuntimeException("Test failed: "+failed);
+        } else {
+            System.out.println("---Test: PASSED");
+        }
+    }
+
+    private static void test(Object obj, String param) {
+        try {
+            obj.hashCode();
+            System.out.println("OK-1: "+obj.getClass().getSimpleName()+
+                    ".hashCode worked with a null paramer: "+param);
+        } catch (NullPointerException npe) {
+            System.out.println("--->KO-1!!! "+obj.getClass().getSimpleName()+
+                    ".hashCode got NPE with null paramer: "+param);
+            npe.printStackTrace();
+            failed++;
+        }
+
+        try {
+            obj.toString();
+            System.out.println("OK-1: "+obj.getClass().getSimpleName()+
+                    ".toString worked with a null paramer: "+param);
+        } catch (NullPointerException npe) {
+            System.out.println("--->KO-1!!! "+obj.getClass().getSimpleName()+
+                    ".toString got NPE with null paramer: "+param);
+            npe.printStackTrace();
+            failed++;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorInternalMapTest.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.management.ManagementFactory;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
+import java.util.Collections;
+import java.util.Map;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXPrincipal;
+import javax.management.remote.JMXServiceURL;
+import javax.management.remote.rmi.RMIConnector;
+import javax.security.auth.Subject;
+
+/*
+ * @test
+ * @bug 6566891
+ * @summary Check no memory leak on RMIConnector's rmbscMap
+ * @author Shanliang JIANG
+ * @run clean RMIConnectorInternalMapTest
+ * @run build RMIConnectorInternalMapTest
+ * @run main RMIConnectorInternalMapTest
+ */
+
+public class RMIConnectorInternalMapTest {
+    public static void main(String[] args) throws Exception {
+        System.out.println("---RMIConnectorInternalMapTest starting...");
+
+        JMXConnectorServer connectorServer = null;
+        JMXConnector connectorClient = null;
+
+        try {
+            MBeanServer mserver = ManagementFactory.getPlatformMBeanServer();
+            JMXServiceURL serverURL = new JMXServiceURL("rmi", "localhost", 0);
+            connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(serverURL, null, mserver);
+            connectorServer.start();
+
+            JMXServiceURL serverAddr = connectorServer.getAddress();
+            connectorClient = JMXConnectorFactory.connect(serverAddr, null);
+            connectorClient.connect();
+
+            Field rmbscMapField = RMIConnector.class.getDeclaredField("rmbscMap");
+            rmbscMapField.setAccessible(true);
+            Map<Subject, WeakReference<MBeanServerConnection>> map =
+                    (Map<Subject, WeakReference<MBeanServerConnection>>) rmbscMapField.get(connectorClient);
+            if (map != null && !map.isEmpty()) { // failed
+                throw new RuntimeException("RMIConnector's rmbscMap must be empty at the initial time.");
+            }
+
+            Subject delegationSubject =
+                    new Subject(true,
+                    Collections.singleton(new JMXPrincipal("delegate")),
+                    Collections.EMPTY_SET,
+                    Collections.EMPTY_SET);
+            MBeanServerConnection mbsc1 =
+                    connectorClient.getMBeanServerConnection(delegationSubject);
+            MBeanServerConnection mbsc2 =
+                    connectorClient.getMBeanServerConnection(delegationSubject);
+
+            if (mbsc1 == null) {
+                throw new RuntimeException("Got null connection.");
+            }
+            if (mbsc1 != mbsc2) {
+                throw new RuntimeException("Not got same connection with a same subject.");
+            }
+
+            map = (Map<Subject, WeakReference<MBeanServerConnection>>) rmbscMapField.get(connectorClient);
+            if (map == null || map.isEmpty()) { // failed
+                throw new RuntimeException("RMIConnector's rmbscMap has wrong size "
+                        + "after creating a delegated connection.");
+            }
+
+            delegationSubject = null;
+            mbsc1 = null;
+            mbsc2 = null;
+
+            int i = 0;
+            while (!map.isEmpty() && i++ < 60) {
+                System.gc();
+                Thread.sleep(100);
+            }
+            System.out.println("---GC times: " + i);
+
+            if (!map.isEmpty()) {
+                throw new RuntimeException("Failed to clean RMIConnector's rmbscMap");
+            } else {
+                System.out.println("---RMIConnectorInternalMapTest: PASSED!");
+            }
+        } finally {
+            try {
+                connectorClient.close();
+                connectorServer.stop();
+            } catch (Exception e) {
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/management/remote/mandatory/connection/RMIConnectorNullSubjectConnTest.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.management.ManagementFactory;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerConnection;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+import javax.management.remote.rmi.RMIConnector;
+
+/*
+ * @test
+ * @bug 6566891
+ * @summary Check no memory leak on RMIConnector's nullSubjectConn
+ * @author Shanliang JIANG
+ * @run clean RMIConnectorNullSubjectConnTest
+ * @run build RMIConnectorNullSubjectConnTest
+ * @run main RMIConnectorNullSubjectConnTest
+ */
+
+public class RMIConnectorNullSubjectConnTest {
+    public static void main(String[] args) throws Exception {
+        System.out.println("---RMIConnectorNullSubjectConnTest starting...");
+
+        JMXConnectorServer connectorServer = null;
+        JMXConnector connectorClient = null;
+
+        try {
+            MBeanServer mserver = ManagementFactory.getPlatformMBeanServer();
+            JMXServiceURL serverURL = new JMXServiceURL("rmi", "localhost", 0);
+            connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(serverURL, null, mserver);
+            connectorServer.start();
+
+            JMXServiceURL serverAddr = connectorServer.getAddress();
+            connectorClient = JMXConnectorFactory.connect(serverAddr, null);
+            connectorClient.connect();
+
+            Field nullSubjectConnField = RMIConnector.class.getDeclaredField("nullSubjectConnRef");
+            nullSubjectConnField.setAccessible(true);
+
+            WeakReference<MBeanServerConnection> weak =
+                    (WeakReference<MBeanServerConnection>)nullSubjectConnField.get(connectorClient);
+
+            if (weak != null && weak.get() != null) {
+                throw new RuntimeException("nullSubjectConnRef must be null at initial time.");
+            }
+
+            MBeanServerConnection conn1 = connectorClient.getMBeanServerConnection(null);
+            MBeanServerConnection conn2 = connectorClient.getMBeanServerConnection(null);
+            if (conn1 == null) {
+                throw new RuntimeException("A connection with null subject should not be null.");
+            } else if (conn1 != conn2) {
+                throw new RuntimeException("The 2 connections with null subject are not equal.");
+            }
+
+            conn1 = null;
+            conn2 = null;
+            int i = 1;
+            do {
+                System.gc();
+                Thread.sleep(100);
+                weak = (WeakReference<MBeanServerConnection>)nullSubjectConnField.get(connectorClient);
+            } while ((weak != null && weak.get() != null) && i++ < 60);
+
+            System.out.println("---GC times: " + i);
+
+            if (weak != null && weak.get() != null) {
+                throw new RuntimeException("Failed to clean RMIConnector's nullSubjectConn");
+            } else {
+                System.out.println("---RMIConnectorNullSubjectConnTest: PASSED!");
+            }
+        } finally {
+            try {
+                connectorClient.close();
+                connectorServer.stop();
+            } catch (Exception e) {
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/jdk/lambda/MethodReferenceTestCallerSensitive.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import org.testng.annotations.Test;
+
+import java.lang.reflect.Field;
+import java.util.function.Function;
+
+
+/**
+ * @author Robert Field
+ */
+
+@Test
+public class MethodReferenceTestCallerSensitive {
+
+    private static <T> void getF(T arg) {
+        Function<Class<T>,Field[]> firstFunction = Class<T>::getFields;
+    }
+
+    public void testConstructorReferenceVarArgs() {
+        getF("Hello World");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/java2d/cmm/ProfileOp/DisposalCrashTest.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug     8024511
+ * @summary Verifies that instances of color profiles are destroyed correctly.
+ *          A crash during profile destruction indicates failure.
+ *
+ * @run     main DisposalCrashTest
+ */
+
+import static java.awt.color.ColorSpace.*;
+import java.awt.color.ICC_Profile;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.Vector;
+
+public class DisposalCrashTest {
+
+    static final ReferenceQueue<ICC_Profile> queue = new ReferenceQueue<>();
+    static final Vector<Reference<? extends ICC_Profile>> v = new Vector<>();
+
+    public static void main(String[] args) {
+        int[] ids = new int[]{
+            CS_sRGB, CS_CIEXYZ, CS_GRAY, CS_LINEAR_RGB, CS_PYCC
+        };
+
+        for (int id : ids) {
+            ICC_Profile p = getCopyOf(id);
+        }
+
+        while (!v.isEmpty()) {
+            System.gc();
+            System.out.println(".");
+            try {
+                Thread.sleep(500);
+            } catch (InterruptedException e) {};
+
+            final Reference<? extends ICC_Profile> ref = queue.poll();
+            System.out.println("Got reference: " + ref);
+
+            v.remove(ref);
+        }
+
+        System.out.println("Test PASSED.");
+    }
+
+    private static ICC_Profile getCopyOf(int id) {
+        ICC_Profile std = ICC_Profile.getInstance(id);
+
+        byte[] data = std.getData();
+
+        ICC_Profile p = ICC_Profile.getInstance(data);
+
+        WeakReference<ICC_Profile> ref = new WeakReference<>(p, queue);
+
+        v.add(ref);
+
+        return p;
+    }
+}
--- a/jdk/test/sun/java2d/cmm/ProfileOp/ReadWriteProfileTest.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/sun/java2d/cmm/ProfileOp/ReadWriteProfileTest.java	Wed Jul 05 19:11:53 2017 +0200
@@ -23,7 +23,7 @@
 
 /**
  * @test
- * @bug 6476665 6523403 6733501 7042594
+ * @bug 6476665 6523403 6733501 7042594 7043064
  * @summary Verifies reading and writing profiles and tags of the standard color
  * spaces
  * @run main ReadWriteProfileTest
@@ -82,6 +82,7 @@
 
     public void run() {
         for (int i = 0; i < cspaces.length; i++) {
+            System.out.println("Profile: " + csNames[i]);
             ICC_Profile pf = ICC_Profile.getInstance(cspaces[i]);
             byte [] data = pf.getData();
             pf = ICC_Profile.getInstance(data);
@@ -92,6 +93,10 @@
             }
 
             for (int tagSig : tags[i].keySet()) {
+                String signature = SigToString(tagSig);
+                System.out.printf("Tag: %s\n", signature);
+                System.out.flush();
+
                 byte [] tagData = pf.getData(tagSig);
                 byte [] empty = new byte[tagData.length];
                 boolean emptyDataRejected = false;
@@ -104,15 +109,23 @@
                     throw new
                         RuntimeException("Test failed: empty tag data was not rejected.");
                 }
-                pf.setData(tagSig, tagData);
-
+                try {
+                    pf.setData(tagSig, tagData);
+                } catch (IllegalArgumentException e) {
+                    // let's ignore this exception for Kodak proprietary tags
+                    if (isKodakExtention(signature)) {
+                        System.out.println("Ignore Kodak tag: " + signature);
+                    } else {
+                        throw new RuntimeException("Test failed!", e);
+                    }
+                }
                 byte [] tagData1 = pf.getData(tagSig);
 
                 if (!Arrays.equals(tagData1, tags[i].get(tagSig)))
                 {
                     System.err.println("Incorrect result of getData(int) with" +
                                        " tag " +
-                                       Integer.toHexString(tagSig) +
+                                       SigToString(tagSig) +
                                        " of " + csNames[i] + " profile");
 
                     throw new RuntimeException("Incorrect result of " +
@@ -122,6 +135,19 @@
         }
     }
 
+    private static boolean isKodakExtention(String signature) {
+        return signature.matches("K\\d\\d\\d");
+    }
+
+    private static String SigToString(int tagSig ) {
+              return String.format("%c%c%c%c",
+                        (char)(0xff & (tagSig >> 24)),
+                        (char)(0xff & (tagSig >> 16)),
+                        (char)(0xff & (tagSig >>  8)),
+                        (char)(0xff & (tagSig)));
+
+    }
+
     public static void main(String [] args) {
         ReadWriteProfileTest test = new ReadWriteProfileTest();
         test.run();
--- a/jdk/test/sun/security/krb5/runNameEquals.sh	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/sun/security/krb5/runNameEquals.sh	Wed Jul 05 19:11:53 2017 +0200
@@ -22,7 +22,7 @@
 #
 
 # @test
-# @bug 6317711 6944847
+# @bug 6317711 6944847 8024046
 # @summary Ensure the GSSName has the correct impl which respects
 # the contract for equals and hashCode across different configurations.
 
@@ -56,6 +56,15 @@
     PATHSEP=":"
     FILESEP="/"
     NATIVE=true
+    # Not all *nix has native GSS libs installed
+    krb5-config --libs gssapi 2> /dev/null
+    if [ $? != 0 ]; then
+        # Fedora has a different path
+        /usr/kerberos/bin/krb5-config --libs gssapi 2> /dev/null
+        if [ $? != 0 ]; then
+            NATIVE=false
+        fi
+    fi
     ;;
   CYGWIN* )
     PATHSEP=";"
--- a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/CloseEngineException.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/CloseEngineException.java	Wed Jul 05 19:11:53 2017 +0200
@@ -21,17 +21,24 @@
  * questions.
  */
 
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
 /*
  * @test
  * @bug 4969799
  * @summary javax.net.ssl.SSLSocket.SSLSocket(InetAddress,int) shouldn't
  *              throw exception
- *
- * This is making sure that starting a new handshake throws the right
- * exception.  There is a similar test for SSLSocket.
- *
+ * @run main/othervm CloseEngineException
  */
 
+//
+// This is making sure that starting a new handshake throws the right
+// exception.  There is a similar test for SSLSocket.
+//
+
 import javax.net.ssl.*;
 import javax.net.ssl.SSLEngineResult.*;
 import java.io.*;
--- a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/CloseInboundException.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/CloseInboundException.java	Wed Jul 05 19:11:53 2017 +0200
@@ -21,11 +21,17 @@
  * questions.
  */
 
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
 /*
  * @test
  * @bug 4931274
  * @summary closeInbound does not signal when a close_notify has not
  *              been received.
+ * @run main/othervm CloseInboundException
  * @author Brad Wetmore
  */
 
--- a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/CloseStart.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/CloseStart.java	Wed Jul 05 19:11:53 2017 +0200
@@ -21,15 +21,22 @@
  * questions.
  */
 
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
 /*
  * @test
  * @bug 5019096
  * @summary Add scatter/gather APIs for SSLEngine
- *
- * Check to see if the args are being parsed properly.
- *
+ * @run main/othervm CloseStart
  */
 
+//
+// Check to see if the args are being parsed properly.
+//
+
 import javax.net.ssl.*;
 import javax.net.ssl.SSLEngineResult.*;
 import java.io.*;
--- a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/DelegatedTaskWrongException.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/DelegatedTaskWrongException.java	Wed Jul 05 19:11:53 2017 +0200
@@ -21,11 +21,16 @@
  * questions.
  */
 
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
 /*
  * @test
  * @bug 4969459
  * @summary Delegated tasks are not reflecting the subclasses of SSLException
- *
+ * @run main/othervm DelegatedTaskWrongException
  */
 
 import javax.net.ssl.*;
--- a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/EmptyExtensionData.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/EmptyExtensionData.java	Wed Jul 05 19:11:53 2017 +0200
@@ -21,10 +21,16 @@
  * questions.
  */
 
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
 /*
  * @test
  * @bug 6728126
  * @summary Parsing Extensions in Client Hello message is done in a wrong way
+ * @run main/othervm EmptyExtensionData
  */
 
 import javax.net.ssl.*;
--- a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/EngineEnforceUseClientMode.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/EngineEnforceUseClientMode.java	Wed Jul 05 19:11:53 2017 +0200
@@ -21,11 +21,16 @@
  * questions.
  */
 
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
 /*
  * @test
  * @bug 4980882
  * @summary SSLEngine should enforce setUseClientMode
- *
+ * @run main/othervm EngineEnforceUseClientMode
  * @author Brad R. Wetmore
  */
 
--- a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/RehandshakeFinished.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/SSLEngineImpl/RehandshakeFinished.java	Wed Jul 05 19:11:53 2017 +0200
@@ -21,16 +21,21 @@
  * questions.
  */
 
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
 /*
  * @test
  * @bug 6207322
  * @summary SSLEngine is returning a premature FINISHED message when doing
- * an abbreviated handshake.
+ *     an abbreviated handshake.
  * @run main/othervm RehandshakeFinished
- *
- *     SunJSSE does not support dynamic system properties, no way to re-use
- *     system properties in samevm/agentvm mode.
- *
+ * @author Brad Wetmore
+ */
+
+/*
  * This test may need some updating if the messages change order.
  * Currently I'm expecting that there is a simple renegotiation, with
  * each message being contained in a single SSL packet.
@@ -41,8 +46,6 @@
  *                              FINISHED
  *      CCS
  *      FINISHED
- *
- * @author Brad Wetmore
  */
 
 /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/ssl/javax/net/ssl/SSLParameters/UseCipherSuitesOrder.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @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_RC4_128_SHA
+ */
+
+import java.io.*;
+import java.net.*;
+import javax.net.ssl.*;
+import java.util.Arrays;
+
+public class UseCipherSuitesOrder {
+
+    /*
+     * =============================================================
+     * Set the various variables needed for the tests, then
+     * specify what tests to run on each side.
+     */
+
+    /*
+     * Should we run the client or server in a separate thread?
+     * Both sides can throw exceptions, but do you have a preference
+     * as to which side should be the main thread.
+     */
+    static boolean separateServerThread = false;
+
+    /*
+     * Where do we find the keystores?
+     */
+    static String pathToStores = "../../../../etc";
+    static String keyStoreFile = "keystore";
+    static String trustStoreFile = "truststore";
+    static String passwd = "passphrase";
+
+    /*
+     * Is the server ready to serve?
+     */
+    volatile static boolean serverReady = false;
+
+    /*
+     * Turn on SSL debugging?
+     */
+    static boolean debug = false;
+
+    /*
+     * If the client or server is doing some kind of object creation
+     * that the other side depends on, and that thread prematurely
+     * exits, you may experience a hang.  The test harness will
+     * terminate all hung threads after its timeout has expired,
+     * currently 3 minutes by default, but you might try to be
+     * smart about it....
+     */
+
+    /*
+     * Define the server side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doServerSide() throws Exception {
+        SSLServerSocketFactory sslssf =
+            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+        SSLServerSocket sslServerSocket =
+            (SSLServerSocket) sslssf.createServerSocket(serverPort);
+        serverPort = sslServerSocket.getLocalPort();
+
+        // use local cipher suites preference
+        SSLParameters params = sslServerSocket.getSSLParameters();
+        params.setUseCipherSuitesOrder(true);
+        params.setCipherSuites(srvEnabledCipherSuites);
+        sslServerSocket.setSSLParameters(params);
+
+        /*
+         * Signal Client, we're ready for his connect.
+         */
+        serverReady = true;
+
+        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        sslIS.read();
+        sslOS.write(85);
+        sslOS.flush();
+
+        SSLSession session = sslSocket.getSession();
+        if (!srvEnabledCipherSuites[0].equals(session.getCipherSuite())) {
+            throw new Exception(
+                "Expected to negotiate " + srvEnabledCipherSuites[0] +
+                " , but not " + session.getCipherSuite());
+        }
+
+        sslSocket.close();
+    }
+
+    /*
+     * Define the client side of the test.
+     *
+     * If the server prematurely exits, serverReady will be set to true
+     * to avoid infinite hangs.
+     */
+    void doClientSide() throws Exception {
+
+        /*
+         * Wait for server to get started.
+         */
+        while (!serverReady) {
+            Thread.sleep(50);
+        }
+
+        SSLSocketFactory sslsf =
+            (SSLSocketFactory) SSLSocketFactory.getDefault();
+        SSLSocket sslSocket = (SSLSocket)
+            sslsf.createSocket("localhost", serverPort);
+        sslSocket.setEnabledCipherSuites(cliEnabledCipherSuites);
+
+        InputStream sslIS = sslSocket.getInputStream();
+        OutputStream sslOS = sslSocket.getOutputStream();
+
+        sslOS.write(280);
+        sslOS.flush();
+        sslIS.read();
+
+        sslSocket.close();
+    }
+
+    // client enabled cipher suites
+    private static String[] cliEnabledCipherSuites;
+
+    // server enabled cipher suites
+    private static String[] srvEnabledCipherSuites;
+
+    private static void parseArguments(String[] args) throws Exception {
+        if (args.length != 1) {
+            System.out.println("Usage: java UseCipherSuitesOrder ciphersuites");
+            System.out.println("\tciphersuites: " +
+                    "a list of enabled cipher suites, separated with comma");
+            throw new Exception("Incorrect usage");
+        }
+
+        cliEnabledCipherSuites = args[0].split(",");
+
+        if (cliEnabledCipherSuites.length < 2) {
+            throw new Exception("Need to enable at least two cipher suites");
+        }
+
+        // Only need to use 2 cipher suites in server side.
+        srvEnabledCipherSuites = Arrays.<String>copyOf(
+                                            cliEnabledCipherSuites, 2);
+
+        // Reverse the cipher suite preference in server side.
+        srvEnabledCipherSuites[0] = cliEnabledCipherSuites[1];
+        srvEnabledCipherSuites[1] = cliEnabledCipherSuites[0];
+    }
+
+    /*
+     * =============================================================
+     * The remainder is just support stuff
+     */
+
+    // use any free port by default
+    volatile int serverPort = 0;
+
+    volatile Exception serverException = null;
+    volatile Exception clientException = null;
+
+    public static void main(String[] args) throws Exception {
+        // parse the arguments
+        parseArguments(args);
+
+        String keyFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + keyStoreFile;
+        String trustFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + trustStoreFile;
+
+        System.setProperty("javax.net.ssl.keyStore", keyFilename);
+        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
+        System.setProperty("javax.net.ssl.trustStore", trustFilename);
+        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
+
+        if (debug)
+            System.setProperty("javax.net.debug", "all");
+
+        /*
+         * Start the tests.
+         */
+        new UseCipherSuitesOrder();
+    }
+
+    Thread clientThread = null;
+    Thread serverThread = null;
+
+    /*
+     * Primary constructor, used to drive remainder of the test.
+     *
+     * Fork off the other side, then do your work.
+     */
+    UseCipherSuitesOrder() throws Exception {
+        Exception startException = null;
+        try {
+            if (separateServerThread) {
+                startServer(true);
+                startClient(false);
+            } else {
+                startClient(true);
+                startServer(false);
+            }
+        } catch (Exception e) {
+            startException = e;
+        }
+
+        /*
+         * Wait for other side to close down.
+         */
+        if (separateServerThread) {
+            if (serverThread != null) {
+                serverThread.join();
+            }
+        } else {
+            if (clientThread != null) {
+                clientThread.join();
+            }
+        }
+
+        /*
+         * When we get here, the test is pretty much over.
+         * Which side threw the error?
+         */
+        Exception local;
+        Exception remote;
+
+        if (separateServerThread) {
+            remote = serverException;
+            local = clientException;
+        } else {
+            remote = clientException;
+            local = serverException;
+        }
+
+        Exception exception = null;
+
+        /*
+         * Check various exception conditions.
+         */
+        if ((local != null) && (remote != null)) {
+            // If both failed, return the curthread's exception.
+            local.initCause(remote);
+            exception = local;
+        } else if (local != null) {
+            exception = local;
+        } else if (remote != null) {
+            exception = remote;
+        } else if (startException != null) {
+            exception = startException;
+        }
+
+        /*
+         * If there was an exception *AND* a startException,
+         * output it.
+         */
+        if (exception != null) {
+            if (exception != startException && startException != null) {
+                exception.addSuppressed(startException);
+            }
+            throw exception;
+        }
+
+        // Fall-through: no exception to throw!
+    }
+
+    void startServer(boolean newThread) throws Exception {
+        if (newThread) {
+            serverThread = new Thread() {
+                public void run() {
+                    try {
+                        doServerSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our server thread just died.
+                         *
+                         * Release the client, if not active already...
+                         */
+                        System.err.println("Server died...");
+                        serverReady = true;
+                        serverException = e;
+                    }
+                }
+            };
+            serverThread.start();
+        } else {
+            try {
+                doServerSide();
+            } catch (Exception e) {
+                serverException = e;
+            } finally {
+                serverReady = true;
+            }
+        }
+    }
+
+    void startClient(boolean newThread) throws Exception {
+        if (newThread) {
+            clientThread = new Thread() {
+                public void run() {
+                    try {
+                        doClientSide();
+                    } catch (Exception e) {
+                        /*
+                         * Our client thread just died.
+                         */
+                        System.err.println("Client died...");
+                        clientException = e;
+                    }
+                }
+            };
+            clientThread.start();
+        } else {
+            try {
+                doClientSide();
+            } catch (Exception e) {
+                clientException = e;
+            }
+        }
+    }
+}
--- a/jdk/test/sun/security/ssl/javax/net/ssl/ServerName/IllegalSNIName.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/sun/security/ssl/javax/net/ssl/ServerName/IllegalSNIName.java	Wed Jul 05 19:11:53 2017 +0200
@@ -34,7 +34,7 @@
 
     public static void main(String[] args) throws Exception {
         String[] illegalNames = {
-                "example\u3003\u3002com",
+                "example\u3002\u3002com",
                 "example..com",
                 "com\u3002",
                 "com.",
--- a/jdk/test/sun/tools/jconsole/ImmutableResourceTest.java	Tue Sep 17 08:08:07 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/**
- *
- *
- *  This isn't the test case: ImmutableResourceTest.sh is.
- *  Refer to ImmutableResourceTest.sh when running this test.
- *
- *  @bug        6287579
- *  @summary    SubClasses of ListResourceBundle should fix getContents()
- */
-import java.util.ResourceBundle;
-
-public class ImmutableResourceTest {
-
-    public static void main(String[] args) throws Exception {
-
-        /* Reach under the covers and get the message strings */
-        sun.tools.jconsole.resources.JConsoleResources jcr =
-            new sun.tools.jconsole.resources.JConsoleResources ();
-        Object [][] testData = jcr.getContents();
-
-        /* Shred our copy of the message strings */
-        for (int ii = 0; ii < testData.length; ii++) {
-            testData[ii][0] = "xxx";
-            testData[ii][1] = "yyy";
-        }
-
-        /*
-         * Try a lookup for the shredded key.
-         * If this is successful we have a problem.
-         */
-        String ss = sun.tools.jconsole.Resources.getText("xxx");
-        if ("yyy".equals(ss)) {
-            throw new Exception ("SubClasses of ListResourceBundle should fix getContents()");
-        }
-        System.out.println("...Finished.");
-    }
-}
--- a/jdk/test/sun/tools/jconsole/ImmutableResourceTest.sh	Tue Sep 17 08:08:07 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,111 +0,0 @@
-#
-# Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-#   @test
-#   @bug        6287579
-#   @summary    SubClasses of ListResourceBundle should fix getContents()
-#
-#   @run shell ImmutableResourceTest.sh
-
-# Beginning of subroutines:
-status=1
-
-#Call this from anywhere to fail the test with an error message
-# usage: fail "reason why the test failed"
-fail()
- { echo "The test failed :-("
-   echo "$*" 1>&2
-   echo "exit status was $status"
-   exit $status
- } #end of fail()
-
-#Call this from anywhere to pass the test with a message
-# usage: pass "reason why the test passed if applicable"
-pass()
- { echo "The test passed!!!"
-   echo "$*" 1>&2
-   exit 0
- } #end of pass()
-
-# end of subroutines
-
-# The beginning of the script proper
-
-OS=`uname -s`
-case "$OS" in
-   SunOS | Linux | Darwin )
-      PATHSEP=":"
-      ;;
-
-   Windows* | CYGWIN*)
-      PATHSEP=";"
-      ;;
-
-   # catch all other OSs
-   * )
-      echo "Unrecognized system!  $OS"
-      fail "Unrecognized system!  $OS"
-      ;;
-esac
-
-TARGETCLASS="ImmutableResourceTest"
-if [ -z "${TESTJAVA}" ] ; then
-   # TESTJAVA is not set, so the test is running stand-alone.
-   # TESTJAVA holds the path to the root directory of the build of the JDK
-   # to be tested.  That is, any java files run explicitly in this shell
-   # should use TESTJAVA in the path to the java interpreter.
-   # So, we'll set this to the JDK spec'd on the command line.  If none
-   # is given on the command line, tell the user that and use a default.
-   # THIS IS THE JDK BEING TESTED.
-   if [ -n "$1" ] ; then
-          TESTJAVA=$1
-      else
-          TESTJAVA=$JAVA_HOME
-   fi
-   TESTSRC=.
-   TESTCLASSES=.
-   #Deal with .class files:
-fi
-#
-echo "JDK under test is: $TESTJAVA"
-#
-CP="-classpath ${TESTCLASSES}${PATHSEP}${TESTJAVA}/lib/jconsole.jar"
-# Compile the test class using the classpath we need:
-#
-env
-#
-set -vx
-#
-#Compile.  jconsole.jar is required on the classpath.
-${TESTJAVA}/bin/javac -d "${TESTCLASSES}" ${CP} -g \
-                         "${TESTSRC}"/"${TARGETCLASS}".java
-#
-#Run the test class, again with the classpath we need:
-${TESTJAVA}/bin/java ${CP} ${TARGETCLASS}
-status=$?
-echo "test status was: $status"
-if [ $status -eq "0" ];
-   then pass ""
-
-   else fail "unspecified test failure"
-fi
--- a/jdk/test/sun/tools/jconsole/ResourceCheckTest.java	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/sun/tools/jconsole/ResourceCheckTest.java	Wed Jul 05 19:11:53 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,377 +27,134 @@
  *  This isn't the test case: ResourceCheckTest.sh is.
  *  Refer to ResourceCheckTest.sh when running this test.
  *
- *  @bug 5008856 5023573 5024917 5062569
+ *  @bug 5008856 5023573 5024917 5062569 7172176
  *  @summary 'missing resource key' error for key = "Operating system"
  */
 
-import java.awt.event.KeyEvent;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.ResourceBundle;
 
+import sun.tools.jconsole.Messages;
 import sun.tools.jconsole.Resources;
 
+/*
+ * Ensures that there is a one-to-one mapping between constants in the
+ * Message class and the keys in the sun.tools.jconsole.resources.messages
+ * bundle.
+ *
+ * An error will be thrown if there is a:
+ *
+ * - key in the resource bundle that doesn't have a public static field with
+ *   the same name in the Message class.
+ *
+ * - public static field in the Message class that doesn't have a key with
+ *   the same name in the resource bundle.
+ *
+ * - message with a mnemonic identifier(&) for which a mnemonic can't
+ *   be looked up using Resources#getMnemonicInt().
+ *
+ */
 public class ResourceCheckTest {
+    private static final String MISSING_RESOURCE_KEY_PREFIX = "missing message for";
+    private static final String RESOURCE_BUNDLE = "sun.tools.jconsole.resources.messages";
+    private static final String NEW_LINE = String.format("%n");
 
-    public static void main(String[] args){
-        Object [][] testData = {
-            {"<", "", "", "", ""},
-            {"<<", "", "", "", ""},
-            {">", "", "", "", ""},
-            {" 1 day", "", "", "", ""},
-            {" 1 hour", "", "", "", ""},
-            {" 1 min", "", "", "", ""},
-            {" 1 month", "", "", "", ""},
-            {" 1 year", "", "", "", ""},
-            {" 2 hours", "", "", "", ""},
-            {" 3 hours", "", "", "", ""},
-            {" 3 months", "", "", "", ""},
-            {" 5 min", "", "", "", ""},
-            {" 6 hours", "", "", "", ""},
-            {" 6 months", "", "", "", ""},
-            {" 7 days", "", "", "", ""},
-            {"10 min", "", "", "", ""},
-            {"12 hours", "", "", "", ""},
-            {"30 min", "", "", "", ""},
-            {"ACTION", "", "", "", ""},
-            {"ACTION_INFO", "", "", "", ""},
-            {"All", "", "", "", ""},
-            {"Architecture", "", "", "", ""},
-            {"Attribute", "", "", "", ""},
-            {"Attribute value", "", "", "", ""},
-            {"Attribute values", "", "", "", ""},
-            {"Attributes", "", "", "", ""},
-            {"Blank", "", "", "", ""},
-            {"BlockedCount WaitedCount", "BlockedCount", "WaitedCount", "", ""},
-            {"Boot class path", "", "", "", ""},
-            {"BorderedComponent.moreOrLessButton.toolTip", "", "", "", ""},
-            {"Close", "", "", "", ""},
-            {"CPU Usage", "", "", "", ""},
-            {"CPUUsageFormat","PhonyPercentage", "", "", ""},
-            {"Cancel", "", "", "", ""},
-            {"Cascade", "", "", "", ""},
-            {"Cascade.mnemonic", "", "", "", ""},
-            {"Chart:", "", "", "", ""},
-            {"Chart:.mnemonic", "", "", "", ""},
-            {"ClassTab.infoLabelFormat", "LoadedCount", "UnloadedCount", "TotalCount", ""},
-            {"ClassTab.loadedClassesPlotter.accessibleName", "", "", "", ""},
-            {"Class path", "", "", "", ""},
-            {"Classes", "", "", "", ""},
-            {"ClassName", "", "", "", ""},
-            {"Column.Name", "", "", "", ""},
-            {"Column.PID", "", "", "", ""},
-            {"Committed", "", "", "", ""},
-            {"Committed memory", "", "", "", ""},
-            {"Committed virtual memory", "", "", "", ""},
-            {"Compiler", "", "", "", ""},
-            {"Connect...", "", "", "", ""},
-            {"Connect", "", "", "", ""},
-            {"Connect.mnemonic", "", "", "", ""},
-            {"ConnectDialog.connectButton.toolTip", "", "", "", ""},
-            {"ConnectDialog.accessibleDescription", "", "", "", ""},
-            {"ConnectDialog.masthead.accessibleName", "", "", "", ""},
-            {"ConnectDialog.masthead.title", "", "", "", ""},
-            {"ConnectDialog.statusBar.accessibleName", "", "", "", ""},
-            {"ConnectDialog.title", "", "", "", ""},
-            {"Connected. Click to disconnect.", "", "", "", ""},
-            {"connectingTo1", "PhonyConnectionName", "", "", ""},
-            {"connectingTo2", "PhonyConnectionName", "", "", ""},
-            {"connectionFailed1", "", "", "", ""},
-            {"connectionFailed2", "PhonyConnectionName", "", "", ""},
-            {"connectionLost1", "", "", "", ""},
-            {"connectionLost2", "PhonyConnectionName", "", "", ""},
-            {"Connection failed", "", "", "", ""},
-            {"Connection", "", "", "", ""},
-            {"Connection.mnemonic", "", "", "", ""},
-            {"Connection name", "", "", "", ""},
-            {"ConnectionName (disconnected)", "Phony", "Phony", "", ""},
-            {"Constructor", "", "", "", ""},
-            {"Create", "Phony", "Phony", "", ""},
-            {"Current classes loaded", "", "", "", ""},
-            {"Current heap size", "", "", "", ""},
-            {"Current value", "PhonyValue", "", "", ""},
-            {"Daemon threads", "", "", "", ""},
-            {"deadlockAllTab", "", "", "", ""},
-            {"deadlockTab", "", "", "", ""},
-            {"deadlockTabN", "PhonyInt", "", "", ""},
-            {"Description", "", "", "", ""},
-            {"Descriptor", "", "", "", ""},
-            {"Details", "", "", "", ""},
-            {"Detect Deadlock", "", "", "", ""},
-            {"Detect Deadlock.mnemonic", "", "", "", ""},
-            {"Detect Deadlock.toolTip", "", "", "", ""},
-            {"Dimension is not supported:", "", "", "", ""},
-            {"Discard chart", "", "", "", ""},
-            {"Disconnected. Click to connect.", "", "", "", ""},
-            {"Double click to expand/collapse", "", "", "", ""},
-            {"Double click to visualize", "", "", "", ""},
-            {"DurationDaysHoursMinutes", 0, 13, 54, ""},
-            {"DurationDaysHoursMinutes", 1, 13, 54, ""},
-            {"DurationDaysHoursMinutes", 2, 13, 54, ""},
-            {"DurationDaysHoursMinutes", 1024, 13, 45, ""},
-            {"DurationHoursMinutes", 0, 13, "", ""},
-            {"DurationHoursMinutes", 1, 0, "", ""},
-            {"DurationHoursMinutes", 1, 1, "", ""},
-            {"DurationHoursMinutes", 2, 42, "", ""},
-            {"DurationMinutes", 0, "", "", ""},
-            {"DurationMinutes", 1, "", "", ""},
-            {"DurationMinutes", 2, "", "", ""},
-            {"DurationSeconds", 0, "", "", ""},
-            {"DurationSeconds", 1, "", "", ""},
-            {"DurationSeconds", 2, "", "", ""},
-            {"Empty array", "", "", "", ""},
-            {"Error", "", "", "", ""},
-            {"Error: MBeans already exist", "", "", "", ""},
-            {"Error: MBeans do not exist", "", "", "", ""},
-            {"Event", "", "", "", ""},
-            {"Exit", "", "", "", ""},
-            {"Exit.mnemonic", "", "", "", ""},
-            {"expand", "", "", "", ""},
-            {"Fail to load plugin", "", "", "", ""},
-            {"FileChooser.fileExists.cancelOption", "", "", "", ""},
-            {"FileChooser.fileExists.message", "PhonyFileName", "", "", ""},
-            {"FileChooser.fileExists.okOption", "", "", "", ""},
-            {"FileChooser.fileExists.title", "", "", "", ""},
-            {"FileChooser.savedFile", "PhonyFilePath", "PhonyFileSize", "", ""},
-            {"FileChooser.saveFailed.message", "PhonyFilePath", "PhonyMessage", "", ""},
-            {"FileChooser.saveFailed.title", "", "", "", ""},
-            {"Free physical memory", "", "", "", ""},
-            {"Free swap space", "", "", "", ""},
-            {"Garbage collector", "", "", "", ""},
-            {"GC time", "", "", "", ""},
-            {"GC time details", 54, "Phony", 11, ""},
-            {"GcInfo", "Phony", -1, 768, ""},
-            {"GcInfo", "Phony", 0, 768, ""},
-            {"GcInfo", "Phony", 1, 768, ""},
-            {"Heap", "", "", "", ""},
-            {"Heap Memory Usage", "", "", "", ""},
-            {"Help.AboutDialog.accessibleDescription", "", "", "", ""},
-            {"Help.AboutDialog.jConsoleVersion", "DummyVersion", "", "", ""},
-            {"Help.AboutDialog.javaVersion", "DummyVersion", "", "", ""},
-            {"Help.AboutDialog.masthead.accessibleName", "", "", "", ""},
-            {"Help.AboutDialog.masthead.title", "", "", "", ""},
-            {"Help.AboutDialog.title", "", "", "", ""},
-            {"Help.AboutDialog.userGuideLink", "DummyMessage", "", "", ""},
-            {"Help.AboutDialog.userGuideLink.mnemonic", "", "", "", ""},
-            {"Help.AboutDialog.userGuideLink.url", "DummyURL", "", "", ""},
-            {"HelpMenu.About.title", "", "", "", ""},
-            {"HelpMenu.About.title.mnemonic", "", "", "", ""},
-            {"HelpMenu.UserGuide.title", "", "", "", ""},
-            {"HelpMenu.UserGuide.title.mnemonic", "", "", "", ""},
-            {"HelpMenu.title", "", "", "", ""},
-            {"HelpMenu.title.mnemonic", "", "", "", ""},
-            {"Hotspot MBeans...", "", "", "", ""},
-            {"Hotspot MBeans....mnemonic", "", "", "", ""},
-            {"Hotspot MBeans.dialog.accessibleDescription", "", "", "", ""},
-            {"Impact", "", "", "", ""},
-            {"Info", "", "", "", ""},
-            {"INFO", "", "", "", ""},
-            {"Invalid plugin path", "", "", "", ""},
-            {"Invalid URL", "", "", "", ""},
-            {"Is", "", "", "", ""},
-            {"Java Monitoring & Management Console", "", "", "", ""},
-            {"Java Virtual Machine", "", "", "", ""},
-            {"JConsole: ", "", "", "", ""},
-            {"JConsole.accessibleDescription", "", "", "", ""},
-            {"JConsole version", "PhonyVersion", "", "", ""},
-            {"JIT compiler", "", "", "", ""},
-            {"Library path", "", "", "", ""},
-            {"Live Threads", "", "", "", ""},
-            {"Loaded", "", "", "", ""},
-            {"Local Process:", "", "", "", ""},
-            {"Local Process:.mnemonic", "", "", "", ""},
-            {"Manage Hotspot MBeans in: ", "", "", "", ""},
-            {"Management Not Enabled", "", "", "", ""},
-            {"Management Will Be Enabled", "", "", "", ""},
-            {"Masthead.font", "", "", "", ""},
-            {"Max", "", "", "", ""},
-            {"Max", "", "", "", ""},
-            {"Maximum heap size", "", "", "", ""},
-            {"MBeanAttributeInfo", "", "", "", ""},
-            {"MBeanInfo", "", "", "", ""},
-            {"MBeanNotificationInfo", "", "", "", ""},
-            {"MBeanOperationInfo", "", "", "", ""},
-            {"MBeans", "", "", "", ""},
-            {"MBeansTab.clearNotificationsButton", "", "", "", ""},
-            {"MBeansTab.clearNotificationsButton.mnemonic", "", "", "", ""},
-            {"MBeansTab.clearNotificationsButton.toolTip", "", "", "", ""},
-            {"MBeansTab.compositeNavigationMultiple", 0, 0, "", ""},
-            {"MBeansTab.compositeNavigationSingle", "", "", "", ""},
-            {"MBeansTab.refreshAttributesButton", "", "", "", ""},
-            {"MBeansTab.refreshAttributesButton.mnemonic", "", "", "", ""},
-            {"MBeansTab.refreshAttributesButton.toolTip", "", "", "", ""},
-            {"MBeansTab.subscribeNotificationsButton", "", "", "", ""},
-            {"MBeansTab.subscribeNotificationsButton.mnemonic", "", "", "", ""},
-            {"MBeansTab.subscribeNotificationsButton.toolTip", "", "", "", ""},
-            {"MBeansTab.tabularNavigationMultiple", 0, 0, "", ""},
-            {"MBeansTab.tabularNavigationSingle", "", "", "", ""},
-            {"MBeansTab.unsubscribeNotificationsButton", "", "", "", ""},
-            {"MBeansTab.unsubscribeNotificationsButton.mnemonic", "", "", "", ""},
-            {"MBeansTab.unsubscribeNotificationsButton.toolTip", "", "", "", ""},
-            {"Memory", "", "", "", ""},
-            {"MemoryPoolLabel", "PhonyMemoryPool", "", "", ""},
-            {"MemoryTab.heapPlotter.accessibleName", "", "", "", ""},
-            {"MemoryTab.infoLabelFormat", "UsedCount", "CommittedCount", "MaxCount", ""},
-            {"MemoryTab.nonHeapPlotter.accessibleName", "", "", "", ""},
-            {"MemoryTab.poolChart.aboveThreshold", "Threshold", "", "", ""},
-            {"MemoryTab.poolChart.accessibleName", "", "", "", ""},
-            {"MemoryTab.poolChart.belowThreshold", "Threshold", "", "", ""},
-            {"MemoryTab.poolPlotter.accessibleName", "PhonyMemoryPool", "", "", ""},
-            {"Message", "", "", "", ""},
-            {"Method successfully invoked", "", "", "", ""},
-            {"Monitor locked", "", "", "", ""},
-            {"Minimize All", "", "", "", ""},
-            {"Minimize All.mnemonic", "", "", "", ""},
-            {"Name", "", "", "", ""},
-            {"Name and Build", "PhonyName", "PhonyBuild", "", ""},
-            {"Name Build and Mode", "PhonyName", "PhonyBuild", "PhonyMode", ""},
-            {"Name State", "PhonyName", "PhonyState", "", ""},
-            {"Name State LockName", "PhonyName", "PhonyState", "PhonyLock", ""},
-            {"Name State LockName LockOwner", "PhonyName", "PhonyState", "PhonyLock", "PhonyOwner"},
-            {"New Connection...", "", "", "", ""},
-            {"New Connection....mnemonic", "", "", "", ""},
-            {"No deadlock detected", "", "", "", ""},
-            {"Non-Heap", "", "", "", ""},
-            {"Non-Heap Memory Usage", "", "", "", ""},
-            {"Notification", "", "", "", ""},
-            {"Notification buffer", "", "", "", ""},
-            {"Notifications", "", "", "", ""},
-            {"NotifTypes", "", "", "", ""},
-            {"Number of Loaded Classes", "", "", "", ""},
-            {"Number of processors", "", "", "", ""},
-            {"Number of Threads", "", "", "", ""},
-            {"ObjectName", "", "", "", ""},
-            {"Operating System", "", "", "", ""},
-            {"Operation", "", "", "", ""},
-            {"Operation invocation", "", "", "", ""},
-            {"Operation return value", "", "", "", ""},
-            {"Operations", "", "", "", ""},
-            {"Overview", "", "", "", ""},
-            {"OverviewPanel.plotter.accessibleName", "PhonyPlotter", "", "", ""},
-            {"Parameter", "", "", "", ""},
-            {"Password: ", "", "", "", ""},
-            {"Password: .mnemonic", "", "", "", ""},
-            {"Password.accessibleName", "", "", "", ""},
-            {"Peak", "", "", "", ""},
-            {"Perform GC", "", "", "", ""},
-            {"Perform GC.mnemonic", "", "", "", ""},
-            {"Perform GC.toolTip", "", "", "", ""},
-            {"Plotter.accessibleName", "", "", "", ""},
-            {"Plotter.accessibleName.keyAndValue", "Key", "Value", "", ""},
-            {"Plotter.accessibleName.noData", "", "", "", ""},
-            {"Plotter.saveAsMenuItem", "", "", "", ""},
-            {"Plotter.saveAsMenuItem.mnemonic", "", "", "", ""},
-            {"Plotter.timeRangeMenu", "", "", "", ""},
-            {"Plotter.timeRangeMenu.mnemonic", "", "", "", ""},
-            {"plot", "", "", "", ""},
-            {"Problem adding listener", "", "", "", ""},
-            {"Problem displaying MBean", "", "", "", ""},
-            {"Problem invoking", "", "", "", ""},
-            {"Problem removing listener", "", "", "", ""},
-            {"Problem setting attribute", "", "", "", ""},
-            {"Process CPU time", "", "", "", ""},
-            {"Readable", "", "", "", ""},
-            {"Reconnect", "", "", "", ""},
-            {"Remote Process:", "", "", "", ""},
-            {"Remote Process:.mnemonic", "", "", "", ""},
-            {"Remote Process.textField.accessibleName", "", "", "", ""},
-            {"remoteTF.usage", "", "", "", ""},
-            {"Restore All", "", "", "", ""},
-            {"Restore All.mnemonic", "", "", "", ""},
-            {"ReturnType", "", "", "", ""},
-            {"SeqNum", "", "", "", ""},
-            {"Size Bytes", 512, "", "", ""},
-            {"Size Gb", 512, "", "", ""},
-            {"Size Kb", 512, "", "", ""},
-            {"Size Mb", 512, "", "", ""},
-            {"Source", "", "", "", ""},
-            {"Stack trace", "", "", "", ""},
-            {"SummaryTab.headerDateTimeFormat", "", "", "", ""},
-            {"SummaryTab.pendingFinalization.label", "", "", "", ""},
-            {"SummaryTab.pendingFinalization.value", "ObjectCount", "", "", ""},
-            {"SummaryTab.tabName", "", "", "", ""},
-            {"SummaryTab.vmVersion",  "VMName", "VMVersion", "", ""},
-            {"ThreadTab.infoLabelFormat", "LiveCount", "PeakCount", "TotalCount", ""},
-            {"ThreadTab.threadInfo.accessibleName", "", "", "", ""},
-            {"ThreadTab.threadPlotter.accessibleName", "", "", "", ""},
-            {"Threads", "", "", "", ""},
-            {"Threshold", "", "", "", ""},
-            {"Tile", "", "", "", ""},
-            {"Tile.mnemonic", "", "", "", ""},
-            {"Time", "", "", "", ""},
-            {"Time Range:", "", "", "", ""},
-            {"Time Range:.mnemonic", "", "", "", ""},
-            {"TimeStamp", "", "", "", ""},
-            {"Total classes loaded", "", "", "", ""},
-            {"Total classes unloaded", "", "", "", ""},
-            {"Total compile time", "", "", "", ""},
-            {"Total Loaded", "", "", "", ""},
-            {"Total physical memory", "", "", "", ""},
-            {"Total swap space", "", "", "", ""},
-            {"Total threads started", "", "", "", ""},
-            {"Type", "", "", "", ""},
-            {"Unavailable", "", "", "", ""},
-            {"UNKNOWN", "", "", "", ""},
-            {"Unregister", "", "", "", ""},
-            {"Uptime", "", "", "", ""},
-            {"Usage Threshold", "", "", "", ""},
-            {"Used", "", "", "", ""},
-            {"Username: ", "", "", "", ""},
-            {"Username: .mnemonic", "", "", "", ""},
-            {"Username.accessibleName", "", "", "", ""},
-            {"UserData", "", "", "", ""},
-            {"Value", "", "", "", ""},
-            {"Vendor", "", "", "", ""},
-            {"Verbose Output", "", "", "", ""},
-            {"Verbose Output.toolTip", "", "", "", ""},
-            {"visualize", "", "", "", ""},
-            {"VM", "", "", "", ""},
-            {"VMInternalFrame.accessibleDescription", "", "", "", ""},
-            {"VM arguments", "", "", "", ""},
-            {"Virtual Machine", "", "", "", ""},
-            {"Window", "", "", "", ""},
-            {"Window.mnemonic", "", "", "", ""},
-            {"Writable", "", "", "", ""},
-            {"zz usage text", "PhonyName", "", "", ""},
-        };
-        //boolean verbose = false;
-        boolean verbose = true;
-
-        long badLookups = 0;
-        System.out.println("Start...");
-        for (int ii = 0; ii < testData.length; ii++) {
-            String key = (String)testData[ii][0];
-
-            if (key.endsWith(".mnemonic")) {
-                String baseKey = key.substring(0, key.length() - ".mnemonic".length());
-                int mnemonic = Resources.getMnemonicInt(baseKey);
-                if (mnemonic == 0) {
-                    badLookups++;
-                    System.out.println("****lookup failed for key = " + key);
+    public static void main(String... args) {
+        List<String> errors = new ArrayList<>();
+        // Ensure that all Message fields have a corresponding key/value
+        // in the resource bundle and that mnemonics can be looked
+        // up where applicable.
+        ResourceBundle rb = ResourceBundle.getBundle(RESOURCE_BUNDLE);
+        for (Field field : Messages.class.getFields()) {
+            if (isResourceKeyField(field)) {
+                String resourceKey = field.getName();
+                String message = readField(field);
+                if (message.startsWith(MISSING_RESOURCE_KEY_PREFIX)) {
+                    errors.add("Can't find message (and perhaps mnemonic) for "
+                            + Messages.class.getSimpleName() + "."
+                            + resourceKey + " in resource bundle.");
                 } else {
-                    if (verbose) {
-                        System.out.println("    mnemonic: " + KeyEvent.getKeyText(mnemonic));
+                    String resourceMessage = rb.getString(resourceKey);
+                    if (hasMnemonicIdentifier(resourceMessage)) {
+                        int mi = Resources.getMnemonicInt(message);
+                        if (mi == 0) {
+                            errors.add("Could not look up mnemonic for message '"
+                                    + message + "'.");
+                        }
                     }
                 }
-                continue;
-            }
-
-            String ss = Resources.getText(key,
-                                          testData[ii][1],
-                                          testData[ii][2],
-                                          testData[ii][3],
-                                          testData[ii][4]);
-            if (ss.startsWith("missing resource key")) {
-                badLookups++;
-                System.out.println("****lookup failed for key = " + key);
-            } else {
-                if (verbose) {
-                    System.out.println("  " + ss);
-                }
             }
         }
-        if (badLookups > 0) {
-            throw new Error ("Resource lookup failed " + badLookups +
-                             " time(s); Test failed");
+
+        // Ensure that there is Message class field for every resource key.
+        for (String key : Collections.list(rb.getKeys())) {
+            try {
+                Messages.class.getField(key);
+            } catch (NoSuchFieldException nfe) {
+                errors.add("Can't find static field ("
+                        + Messages.class.getSimpleName() + "." + key
+                        + ") matching '" + key
+                        + "' in resource bundle. Unused message?");
+            }
+        }
+
+        if (errors.size() > 0) {
+            throwError(errors);
+        }
+    }
+
+    private static String readField(Field field) {
+        try {
+            return (String) field.get(null);
+        } catch (IllegalArgumentException | IllegalAccessException e) {
+            throw new Error("Could not access field " + field.getName()
+                    + " when trying to read resource message.");
         }
-        System.out.println("...Finished.");
+    }
+
+    private static boolean isResourceKeyField(Field field) {
+        int modifiers = field.getModifiers();
+        return Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers);
+    }
+
+    private static boolean hasMnemonicIdentifier(String s) {
+        for (int i = 0; i < s.length() - 1; i++) {
+            if (s.charAt(i) == '&') {
+                if (s.charAt(i + 1) != '&') {
+                    return true;
+                } else {
+                    i++;
+                }
+            }
+        }
+        return false;
+    }
+
+    private static void throwError(List<String> errors) {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("Found ");
+        buffer.append(errors.size());
+        buffer.append(" error(s) when checking one-to-one mapping ");
+        buffer.append("between Message and resource bundle keys in ");
+        buffer.append(RESOURCE_BUNDLE);
+        buffer.append(" with ");
+        buffer.append(Locale.getDefault());
+        buffer.append(" locale.");
+        buffer.append(NEW_LINE);
+        int errorIndex = 1;
+        for (String error : errors) {
+            buffer.append("Error ");
+            buffer.append(errorIndex);
+            buffer.append(": ");
+            buffer.append(error);
+            buffer.append(NEW_LINE);
+            errorIndex++;
+        }
+        throw new Error(buffer.toString());
     }
 }
--- a/jdk/test/sun/tools/jconsole/ResourceCheckTest.sh	Tue Sep 17 08:08:07 2013 -0700
+++ b/jdk/test/sun/tools/jconsole/ResourceCheckTest.sh	Wed Jul 05 19:11:53 2017 +0200
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -54,7 +54,7 @@
 
 OS=`uname -s`
 case "$OS" in
-   SunOS | Linux )
+   SunOS | Linux | Darwin)
       PATHSEP=":"
       ;;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/util/locale/provider/Bug8024141.java	Wed Jul 05 19:11:53 2017 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8024141
+ * @summary Test for cache support of sun.util.locale.provider.LocaleResources.getTimeZoneNames
+ */
+
+import java.time.ZoneId;
+import static java.util.Locale.ENGLISH;
+import static java.time.format.TextStyle.FULL;
+import static java.time.format.TextStyle.SHORT;
+
+public class Bug8024141 {
+    // This test assumes that the two time zones are in GMT. If
+    // they become different zones, need to pick up another zones.
+    private static final String[] ZONES = {
+        "Africa/Abidjan",
+        "Africa/Bamako"
+    };
+
+    public static void main(String[] args) {
+        ZoneId gmt = ZoneId.of("GMT");
+        String gmtName = gmt.getDisplayName(FULL, ENGLISH);
+        String gmtAbbr = gmt.getDisplayName(SHORT, ENGLISH);
+
+        for (String zone : ZONES) {
+            ZoneId id = ZoneId.of(zone);
+            String name = id.getDisplayName(FULL, ENGLISH);
+            String abbr = id.getDisplayName(SHORT, ENGLISH);
+
+            if (!name.equals(gmtName) || !abbr.equals(gmtAbbr)) {
+                throw new RuntimeException("inconsistent name/abbr for " + zone + ":\n"
+                                           + "name=" + name + ", abbr=" + abbr);
+            }
+        }
+    }
+}
--- a/make/scripts/webrev.ksh	Tue Sep 17 08:08:07 2013 -0700
+++ b/make/scripts/webrev.ksh	Wed Jul 05 19:11:53 2017 +0200
@@ -27,7 +27,7 @@
 # Documentation is available via 'webrev -h'.
 #
 
-WEBREV_UPDATED=24.0-hg+jbs
+WEBREV_UPDATED=24.1-hg+openjdk.java.net
 
 HTML='<?xml version="1.0"?>
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
@@ -230,7 +230,7 @@
 #   $ sdiff_to_html old/usr/src/tools/scripts/webrev.sh \
 #         new/usr/src/tools/scripts/webrev.sh \
 #         webrev.sh usr/src/tools/scripts \
-#         '<a href="https://jbs.oracle.com/bugs/browse/JDK-1234567">
+#         '<a href="https://bugs.openjdk.java.net/browse/JDK-1234567">
 #          JDK-1234567</a> my bugid' > <file>.html
 #
 # framed_sdiff() is then called which creates $2.frames.html
@@ -1476,7 +1476,7 @@
     # The first and last are simple addition while the middle one
     # is a move/rename or a copy.  We can't distinguish from a rename vs a copy
     # without also getting the status of removed files.  The middle case above
-    # is a rename if File4 is also shown a being removed.  If File4 is not a 
+    # is a rename if File4 is also shown a being removed.  If File4 is not a
     # removed file, then the middle case is a copy from File4 to subdir/File4
     # FIXME - we're not distinguishing copy from rename
     $HGCMD -aC | $FILTER | while read LINE; do
@@ -1644,7 +1644,7 @@
         # The first and last are simple addition while the middle one
         # is a move/rename or a copy.  We can't distinguish from a rename vs a copy
         # without also getting the status of removed files.  The middle case above
-        # is a rename if File4 is also shown a being removed.  If File4 is not a 
+        # is a rename if File4 is also shown a being removed.  If File4 is not a
         # removed file, then the middle case is a copy from File4 to subdir/File4
         # FIXME - we're not distinguishing copy from rename
 
@@ -2529,7 +2529,7 @@
 #    Bug IDs will be replaced by a URL.  Order of precedence
 #    is: default location, $WEBREV_BUGURL, the -O flag.
 #
-BUGURL='https://jbs.oracle.com/bugs/browse/'
+BUGURL='https://bugs.openjdk.java.net/browse/'
 [[ -n $WEBREV_BUGURL ]] && BUGURL="$WEBREV_BUGURL"
 if [[ -n "$Oflag" ]]; then
     CRID=`echo $CRID | sed -e 's/JDK-//'`
@@ -3056,7 +3056,7 @@
     for id in $CRID
     do
         if [[ -z "$Oflag" ]]; then
-            #add "JDK-" to raw bug id for jbs links.
+            #add "JDK-" to raw bug id for openjdk.java.net links.
             id=`echo ${id} | sed 's/^\([0-9]\{5,\}\)$/JDK-\1/'`
         fi
         print "<tr><th>Bug id:</th><td>"