Merge
authorduke
Wed, 05 Jul 2017 20:37:09 +0200
changeset 31007 b2ea0d3316ef
parent 31006 9bccf568791d (current diff)
parent 30996 9133f892a9ae (diff)
child 31008 5b500c93ce48
Merge
jdk/src/java.base/share/classes/sun/misc/JavaBeansIntrospectorAccess.java
jdk/src/java.base/share/classes/sun/nio/cs/AbstractCharsetProvider.java
jdk/src/java.base/share/classes/sun/security/ssl/EngineArgs.java
jdk/src/java.base/share/classes/sun/security/ssl/EngineInputRecord.java
jdk/src/java.base/share/classes/sun/security/ssl/EngineOutputRecord.java
jdk/src/java.base/share/classes/sun/security/ssl/EngineWriter.java
jdk/src/java.base/share/classes/sun/security/ssl/KerberosClientKeyExchange.java
jdk/src/java.base/share/classes/sun/security/ssl/Krb5Helper.java
jdk/src/java.base/share/classes/sun/security/ssl/Krb5Proxy.java
jdk/src/java.security.jgss/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java
jdk/src/java.security.jgss/share/classes/sun/security/ssl/krb5/KerberosPreMasterSecret.java
jdk/src/java.security.jgss/share/classes/sun/security/ssl/krb5/Krb5ProxyImpl.java
jdk/test/java/lang/Character/UnicodeBlock/NonOptimalMapSize.java
--- a/.hgtags-top-repo	Thu Jun 04 18:50:30 2015 -0700
+++ b/.hgtags-top-repo	Wed Jul 05 20:37:09 2017 +0200
@@ -309,3 +309,4 @@
 82cf9aab9a83e41c8194ba01af9666afdb856cbe jdk9-b64
 7c31f9d7b932f7924f1258d52885b1c7c3e078c2 jdk9-b65
 dc6e8336f51bb6b67b7245766179eab5ca7720b4 jdk9-b66
+f546760134eb861fcfecd4ce611b0040b0d25a6a jdk9-b67
--- a/common/autoconf/flags.m4	Thu Jun 04 18:50:30 2015 -0700
+++ b/common/autoconf/flags.m4	Wed Jul 05 20:37:09 2017 +0200
@@ -338,14 +338,16 @@
       # no adjustment
       ;;
     slowdebug )
-      # Add runtime stack smashing and undefined behavior checks
-      CFLAGS_DEBUG_OPTIONS="-fstack-protector-all --param ssp-buffer-size=1"
-      CXXFLAGS_DEBUG_OPTIONS="-fstack-protector-all --param ssp-buffer-size=1"
+      # Add runtime stack smashing and undefined behavior checks.
+      # Not all versions of gcc support -fstack-protector
+      STACK_PROTECTOR_CFLAG="-fstack-protector-all"
+      FLAGS_COMPILER_CHECK_ARGUMENTS([$STACK_PROTECTOR_CFLAG], [], [STACK_PROTECTOR_CFLAG=""])
+
+      CFLAGS_DEBUG_OPTIONS="$STACK_PROTECTOR_CFLAG --param ssp-buffer-size=1"
+      CXXFLAGS_DEBUG_OPTIONS="$STACK_PROTECTOR_CFLAG --param ssp-buffer-size=1"
       ;;
     esac
   fi
-  AC_SUBST(CFLAGS_DEBUG_OPTIONS)
-  AC_SUBST(CXXFLAGS_DEBUG_OPTIONS)
 
   # Optimization levels
   if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
--- a/common/autoconf/generated-configure.sh	Thu Jun 04 18:50:30 2015 -0700
+++ b/common/autoconf/generated-configure.sh	Wed Jul 05 20:37:09 2017 +0200
@@ -718,8 +718,6 @@
 C_O_FLAG_NORM
 C_O_FLAG_HI
 C_O_FLAG_HIGHEST
-CXXFLAGS_DEBUG_OPTIONS
-CFLAGS_DEBUG_OPTIONS
 CXXFLAGS_DEBUG_SYMBOLS
 CFLAGS_DEBUG_SYMBOLS
 CXX_FLAG_DEPS
@@ -4366,7 +4364,7 @@
 #CUSTOM_AUTOCONF_INCLUDE
 
 # Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1432629750
+DATE_WHEN_GENERATED=1433337614
 
 ###############################################################################
 #
@@ -41837,15 +41835,81 @@
       # no adjustment
       ;;
     slowdebug )
-      # Add runtime stack smashing and undefined behavior checks
-      CFLAGS_DEBUG_OPTIONS="-fstack-protector-all --param ssp-buffer-size=1"
-      CXXFLAGS_DEBUG_OPTIONS="-fstack-protector-all --param ssp-buffer-size=1"
+      # Add runtime stack smashing and undefined behavior checks.
+      # Not all versions of gcc support -fstack-protector
+      STACK_PROTECTOR_CFLAG="-fstack-protector-all"
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if compiler supports \"$STACK_PROTECTOR_CFLAG\"" >&5
+$as_echo_n "checking if compiler supports \"$STACK_PROTECTOR_CFLAG\"... " >&6; }
+  supports=yes
+
+  saved_cflags="$CFLAGS"
+  CFLAGS="$CFLAGS $STACK_PROTECTOR_CFLAG"
+  ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int i;
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  supports=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+  CFLAGS="$saved_cflags"
+
+  saved_cxxflags="$CXXFLAGS"
+  CXXFLAGS="$CXXFLAG $STACK_PROTECTOR_CFLAG"
+  ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int i;
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+else
+  supports=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+  ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+  CXXFLAGS="$saved_cxxflags"
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $supports" >&5
+$as_echo "$supports" >&6; }
+  if test "x$supports" = "xyes" ; then
+    :
+  else
+    STACK_PROTECTOR_CFLAG=""
+  fi
+
+
+      CFLAGS_DEBUG_OPTIONS="$STACK_PROTECTOR_CFLAG --param ssp-buffer-size=1"
+      CXXFLAGS_DEBUG_OPTIONS="$STACK_PROTECTOR_CFLAG --param ssp-buffer-size=1"
       ;;
     esac
   fi
 
-
-
   # Optimization levels
   if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
     CC_HIGHEST="$CC_HIGHEST -fns -fsimple -fsingle -xbuiltin=%all -xdepend -xrestrict -xlibmil"
--- a/corba/.hgtags	Thu Jun 04 18:50:30 2015 -0700
+++ b/corba/.hgtags	Wed Jul 05 20:37:09 2017 +0200
@@ -309,3 +309,4 @@
 0a5e5a7c3539e8bde73d9fe55750e49a49cb8dac jdk9-b64
 afc1e295c4bf83f9a5dd539c29914edd4a754a3f jdk9-b65
 44ee68f7dbacab24a45115fd6a8ccdc7eb6e8f0b jdk9-b66
+4418697e56f1f43597f55c7cb6573549c6117868 jdk9-b67
--- a/hotspot/.hgtags	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/.hgtags	Wed Jul 05 20:37:09 2017 +0200
@@ -469,3 +469,4 @@
 bf92b8db249cdfa5651ef954b6c0743a7e0ea4cd jdk9-b64
 e7ae94c4f35e940ea423fc1dd260435df34a77c0 jdk9-b65
 197e94e0dacddd16816f101d24fc0442ab518326 jdk9-b66
+d47dfabd16d48eb96a451edd1b61194a39ee0eb5 jdk9-b67
--- a/hotspot/src/cpu/aarch64/vm/aarch64.ad	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad	Wed Jul 05 20:37:09 2017 +0200
@@ -161,70 +161,165 @@
 // the platform ABI treats v8-v15 as callee save). float registers
 // v16-v31 are SOC as per the platform spec
 
-  reg_def V0   ( SOC, SOC, Op_RegF,  0, v0->as_VMReg()         );
-  reg_def V0_H ( SOC, SOC, Op_RegF,  0, v0->as_VMReg()->next() );
-  reg_def V1   ( SOC, SOC, Op_RegF,  1, v1->as_VMReg()         );
-  reg_def V1_H ( SOC, SOC, Op_RegF,  1, v1->as_VMReg()->next() );
-  reg_def V2   ( SOC, SOC, Op_RegF,  2, v2->as_VMReg()         );
-  reg_def V2_H ( SOC, SOC, Op_RegF,  2, v2->as_VMReg()->next() );
-  reg_def V3   ( SOC, SOC, Op_RegF,  3, v3->as_VMReg()         );
-  reg_def V3_H ( SOC, SOC, Op_RegF,  3, v3->as_VMReg()->next() );
-  reg_def V4   ( SOC, SOC, Op_RegF,  4, v4->as_VMReg()         );
-  reg_def V4_H ( SOC, SOC, Op_RegF,  4, v4->as_VMReg()->next() );
-  reg_def V5   ( SOC, SOC, Op_RegF,  5, v5->as_VMReg()         );
-  reg_def V5_H ( SOC, SOC, Op_RegF,  5, v5->as_VMReg()->next() );
-  reg_def V6   ( SOC, SOC, Op_RegF,  6, v6->as_VMReg()         );
-  reg_def V6_H ( SOC, SOC, Op_RegF,  6, v6->as_VMReg()->next() );
-  reg_def V7   ( SOC, SOC, Op_RegF,  7, v7->as_VMReg()         );
-  reg_def V7_H ( SOC, SOC, Op_RegF,  7, v7->as_VMReg()->next() );
-  reg_def V8   ( SOC, SOE, Op_RegF,  8, v8->as_VMReg()         );
-  reg_def V8_H ( SOC, SOE, Op_RegF,  8, v8->as_VMReg()->next() );
-  reg_def V9   ( SOC, SOE, Op_RegF,  9, v9->as_VMReg()         );
-  reg_def V9_H ( SOC, SOE, Op_RegF,  9, v9->as_VMReg()->next() );
-  reg_def V10  ( SOC, SOE, Op_RegF, 10, v10->as_VMReg()        );
-  reg_def V10_H( SOC, SOE, Op_RegF, 10, v10->as_VMReg()->next());
-  reg_def V11  ( SOC, SOE, Op_RegF, 11, v11->as_VMReg()        );
-  reg_def V11_H( SOC, SOE, Op_RegF, 11, v11->as_VMReg()->next());
-  reg_def V12  ( SOC, SOE, Op_RegF, 12, v12->as_VMReg()        );
-  reg_def V12_H( SOC, SOE, Op_RegF, 12, v12->as_VMReg()->next());
-  reg_def V13  ( SOC, SOE, Op_RegF, 13, v13->as_VMReg()        );
-  reg_def V13_H( SOC, SOE, Op_RegF, 13, v13->as_VMReg()->next());
-  reg_def V14  ( SOC, SOE, Op_RegF, 14, v14->as_VMReg()        );
-  reg_def V14_H( SOC, SOE, Op_RegF, 14, v14->as_VMReg()->next());
-  reg_def V15  ( SOC, SOE, Op_RegF, 15, v15->as_VMReg()        );
-  reg_def V15_H( SOC, SOE, Op_RegF, 15, v15->as_VMReg()->next());
-  reg_def V16  ( SOC, SOC, Op_RegF, 16, v16->as_VMReg()        );
-  reg_def V16_H( SOC, SOC, Op_RegF, 16, v16->as_VMReg()->next());
-  reg_def V17  ( SOC, SOC, Op_RegF, 17, v17->as_VMReg()        );
-  reg_def V17_H( SOC, SOC, Op_RegF, 17, v17->as_VMReg()->next());
-  reg_def V18  ( SOC, SOC, Op_RegF, 18, v18->as_VMReg()        );
-  reg_def V18_H( SOC, SOC, Op_RegF, 18, v18->as_VMReg()->next());
-  reg_def V19  ( SOC, SOC, Op_RegF, 19, v19->as_VMReg()        );
-  reg_def V19_H( SOC, SOC, Op_RegF, 19, v19->as_VMReg()->next());
-  reg_def V20  ( SOC, SOC, Op_RegF, 20, v20->as_VMReg()        );
-  reg_def V20_H( SOC, SOC, Op_RegF, 20, v20->as_VMReg()->next());
-  reg_def V21  ( SOC, SOC, Op_RegF, 21, v21->as_VMReg()        );
-  reg_def V21_H( SOC, SOC, Op_RegF, 21, v21->as_VMReg()->next());
-  reg_def V22  ( SOC, SOC, Op_RegF, 22, v22->as_VMReg()        );
-  reg_def V22_H( SOC, SOC, Op_RegF, 22, v22->as_VMReg()->next());
-  reg_def V23  ( SOC, SOC, Op_RegF, 23, v23->as_VMReg()        );
-  reg_def V23_H( SOC, SOC, Op_RegF, 23, v23->as_VMReg()->next());
-  reg_def V24  ( SOC, SOC, Op_RegF, 24, v24->as_VMReg()        );
-  reg_def V24_H( SOC, SOC, Op_RegF, 24, v24->as_VMReg()->next());
-  reg_def V25  ( SOC, SOC, Op_RegF, 25, v25->as_VMReg()        );
-  reg_def V25_H( SOC, SOC, Op_RegF, 25, v25->as_VMReg()->next());
-  reg_def V26  ( SOC, SOC, Op_RegF, 26, v26->as_VMReg()        );
-  reg_def V26_H( SOC, SOC, Op_RegF, 26, v26->as_VMReg()->next());
-  reg_def V27  ( SOC, SOC, Op_RegF, 27, v27->as_VMReg()        );
-  reg_def V27_H( SOC, SOC, Op_RegF, 27, v27->as_VMReg()->next());
-  reg_def V28  ( SOC, SOC, Op_RegF, 28, v28->as_VMReg()        );
-  reg_def V28_H( SOC, SOC, Op_RegF, 28, v28->as_VMReg()->next());
-  reg_def V29  ( SOC, SOC, Op_RegF, 29, v29->as_VMReg()        );
-  reg_def V29_H( SOC, SOC, Op_RegF, 29, v29->as_VMReg()->next());
-  reg_def V30  ( SOC, SOC, Op_RegF, 30, v30->as_VMReg()        );
-  reg_def V30_H( SOC, SOC, Op_RegF, 30, v30->as_VMReg()->next());
-  reg_def V31  ( SOC, SOC, Op_RegF, 31, v31->as_VMReg()        );
-  reg_def V31_H( SOC, SOC, Op_RegF, 31, v31->as_VMReg()->next());
+  reg_def V0   ( SOC, SOC, Op_RegF,  0, v0->as_VMReg()          );
+  reg_def V0_H ( SOC, SOC, Op_RegF,  0, v0->as_VMReg()->next()  );
+  reg_def V0_J ( SOC, SOC, Op_RegF,  0, v0->as_VMReg()->next(2) );
+  reg_def V0_K ( SOC, SOC, Op_RegF,  0, v0->as_VMReg()->next(3) );
+
+  reg_def V1   ( SOC, SOC, Op_RegF,  1, v1->as_VMReg()          );
+  reg_def V1_H ( SOC, SOC, Op_RegF,  1, v1->as_VMReg()->next()  );
+  reg_def V1_J ( SOC, SOC, Op_RegF,  1, v1->as_VMReg()->next(2) );
+  reg_def V1_K ( SOC, SOC, Op_RegF,  1, v1->as_VMReg()->next(3) );
+
+  reg_def V2   ( SOC, SOC, Op_RegF,  2, v2->as_VMReg()          );
+  reg_def V2_H ( SOC, SOC, Op_RegF,  2, v2->as_VMReg()->next()  );
+  reg_def V2_J ( SOC, SOC, Op_RegF,  2, v2->as_VMReg()->next(2) );
+  reg_def V2_K ( SOC, SOC, Op_RegF,  2, v2->as_VMReg()->next(3) );
+
+  reg_def V3   ( SOC, SOC, Op_RegF,  3, v3->as_VMReg()          );
+  reg_def V3_H ( SOC, SOC, Op_RegF,  3, v3->as_VMReg()->next()  );
+  reg_def V3_J ( SOC, SOC, Op_RegF,  3, v3->as_VMReg()->next(2) );
+  reg_def V3_K ( SOC, SOC, Op_RegF,  3, v3->as_VMReg()->next(3) );
+
+  reg_def V4   ( SOC, SOC, Op_RegF,  4, v4->as_VMReg()          );
+  reg_def V4_H ( SOC, SOC, Op_RegF,  4, v4->as_VMReg()->next()  );
+  reg_def V4_J ( SOC, SOC, Op_RegF,  4, v4->as_VMReg()->next(2) );
+  reg_def V4_K ( SOC, SOC, Op_RegF,  4, v4->as_VMReg()->next(3) );
+
+  reg_def V5   ( SOC, SOC, Op_RegF,  5, v5->as_VMReg()          );
+  reg_def V5_H ( SOC, SOC, Op_RegF,  5, v5->as_VMReg()->next()  );
+  reg_def V5_J ( SOC, SOC, Op_RegF,  5, v5->as_VMReg()->next(2) );
+  reg_def V5_K ( SOC, SOC, Op_RegF,  5, v5->as_VMReg()->next(3) );
+
+  reg_def V6   ( SOC, SOC, Op_RegF,  6, v6->as_VMReg()          );
+  reg_def V6_H ( SOC, SOC, Op_RegF,  6, v6->as_VMReg()->next()  );
+  reg_def V6_J ( SOC, SOC, Op_RegF,  6, v6->as_VMReg()->next(2) );
+  reg_def V6_K ( SOC, SOC, Op_RegF,  6, v6->as_VMReg()->next(3) );
+
+  reg_def V7   ( SOC, SOC, Op_RegF,  7, v7->as_VMReg()          );
+  reg_def V7_H ( SOC, SOC, Op_RegF,  7, v7->as_VMReg()->next()  );
+  reg_def V7_J ( SOC, SOC, Op_RegF,  7, v7->as_VMReg()->next(2) );
+  reg_def V7_K ( SOC, SOC, Op_RegF,  7, v7->as_VMReg()->next(3) );
+
+  reg_def V8   ( SOC, SOC, Op_RegF,  8, v8->as_VMReg()          );
+  reg_def V8_H ( SOC, SOC, Op_RegF,  8, v8->as_VMReg()->next()  );
+  reg_def V8_J ( SOC, SOC, Op_RegF,  8, v8->as_VMReg()->next(2) );
+  reg_def V8_K ( SOC, SOC, Op_RegF,  8, v8->as_VMReg()->next(3) );
+
+  reg_def V9   ( SOC, SOC, Op_RegF,  9, v9->as_VMReg()          );
+  reg_def V9_H ( SOC, SOC, Op_RegF,  9, v9->as_VMReg()->next()  );
+  reg_def V9_J ( SOC, SOC, Op_RegF,  9, v9->as_VMReg()->next(2) );
+  reg_def V9_K ( SOC, SOC, Op_RegF,  9, v9->as_VMReg()->next(3) );
+
+  reg_def V10  ( SOC, SOC, Op_RegF, 10, v10->as_VMReg()         );
+  reg_def V10_H( SOC, SOC, Op_RegF, 10, v10->as_VMReg()->next() );
+  reg_def V10_J( SOC, SOC, Op_RegF, 10, v10->as_VMReg()->next(2));
+  reg_def V10_K( SOC, SOC, Op_RegF, 10, v10->as_VMReg()->next(3));
+
+  reg_def V11  ( SOC, SOC, Op_RegF, 11, v11->as_VMReg()         );
+  reg_def V11_H( SOC, SOC, Op_RegF, 11, v11->as_VMReg()->next() );
+  reg_def V11_J( SOC, SOC, Op_RegF, 11, v11->as_VMReg()->next(2));
+  reg_def V11_K( SOC, SOC, Op_RegF, 11, v11->as_VMReg()->next(3));
+
+  reg_def V12  ( SOC, SOC, Op_RegF, 12, v12->as_VMReg()         );
+  reg_def V12_H( SOC, SOC, Op_RegF, 12, v12->as_VMReg()->next() );
+  reg_def V12_J( SOC, SOC, Op_RegF, 12, v12->as_VMReg()->next(2));
+  reg_def V12_K( SOC, SOC, Op_RegF, 12, v12->as_VMReg()->next(3));
+
+  reg_def V13  ( SOC, SOC, Op_RegF, 13, v13->as_VMReg()         );
+  reg_def V13_H( SOC, SOC, Op_RegF, 13, v13->as_VMReg()->next() );
+  reg_def V13_J( SOC, SOC, Op_RegF, 13, v13->as_VMReg()->next(2));
+  reg_def V13_K( SOC, SOC, Op_RegF, 13, v13->as_VMReg()->next(3));
+
+  reg_def V14  ( SOC, SOC, Op_RegF, 14, v14->as_VMReg()         );
+  reg_def V14_H( SOC, SOC, Op_RegF, 14, v14->as_VMReg()->next() );
+  reg_def V14_J( SOC, SOC, Op_RegF, 14, v14->as_VMReg()->next(2));
+  reg_def V14_K( SOC, SOC, Op_RegF, 14, v14->as_VMReg()->next(3));
+
+  reg_def V15  ( SOC, SOC, Op_RegF, 15, v15->as_VMReg()         );
+  reg_def V15_H( SOC, SOC, Op_RegF, 15, v15->as_VMReg()->next() );
+  reg_def V15_J( SOC, SOC, Op_RegF, 15, v15->as_VMReg()->next(2));
+  reg_def V15_K( SOC, SOC, Op_RegF, 15, v15->as_VMReg()->next(3));
+
+  reg_def V16  ( SOC, SOC, Op_RegF, 16, v16->as_VMReg()         );
+  reg_def V16_H( SOC, SOC, Op_RegF, 16, v16->as_VMReg()->next() );
+  reg_def V16_J( SOC, SOC, Op_RegF, 16, v16->as_VMReg()->next(2));
+  reg_def V16_K( SOC, SOC, Op_RegF, 16, v16->as_VMReg()->next(3));
+
+  reg_def V17  ( SOC, SOC, Op_RegF, 17, v17->as_VMReg()         );
+  reg_def V17_H( SOC, SOC, Op_RegF, 17, v17->as_VMReg()->next() );
+  reg_def V17_J( SOC, SOC, Op_RegF, 17, v17->as_VMReg()->next(2));
+  reg_def V17_K( SOC, SOC, Op_RegF, 17, v17->as_VMReg()->next(3));
+
+  reg_def V18  ( SOC, SOC, Op_RegF, 18, v18->as_VMReg()         );
+  reg_def V18_H( SOC, SOC, Op_RegF, 18, v18->as_VMReg()->next() );
+  reg_def V18_J( SOC, SOC, Op_RegF, 18, v18->as_VMReg()->next(2));
+  reg_def V18_K( SOC, SOC, Op_RegF, 18, v18->as_VMReg()->next(3));
+
+  reg_def V19  ( SOC, SOC, Op_RegF, 19, v19->as_VMReg()         );
+  reg_def V19_H( SOC, SOC, Op_RegF, 19, v19->as_VMReg()->next() );
+  reg_def V19_J( SOC, SOC, Op_RegF, 19, v19->as_VMReg()->next(2));
+  reg_def V19_K( SOC, SOC, Op_RegF, 19, v19->as_VMReg()->next(3));
+
+  reg_def V20  ( SOC, SOC, Op_RegF, 20, v20->as_VMReg()         );
+  reg_def V20_H( SOC, SOC, Op_RegF, 20, v20->as_VMReg()->next() );
+  reg_def V20_J( SOC, SOC, Op_RegF, 20, v20->as_VMReg()->next(2));
+  reg_def V20_K( SOC, SOC, Op_RegF, 20, v20->as_VMReg()->next(3));
+
+  reg_def V21  ( SOC, SOC, Op_RegF, 21, v21->as_VMReg()         );
+  reg_def V21_H( SOC, SOC, Op_RegF, 21, v21->as_VMReg()->next() );
+  reg_def V21_J( SOC, SOC, Op_RegF, 21, v21->as_VMReg()->next(2));
+  reg_def V21_K( SOC, SOC, Op_RegF, 21, v21->as_VMReg()->next(3));
+
+  reg_def V22  ( SOC, SOC, Op_RegF, 22, v22->as_VMReg()         );
+  reg_def V22_H( SOC, SOC, Op_RegF, 22, v22->as_VMReg()->next() );
+  reg_def V22_J( SOC, SOC, Op_RegF, 22, v22->as_VMReg()->next(2));
+  reg_def V22_K( SOC, SOC, Op_RegF, 22, v22->as_VMReg()->next(3));
+
+  reg_def V23  ( SOC, SOC, Op_RegF, 23, v23->as_VMReg()         );
+  reg_def V23_H( SOC, SOC, Op_RegF, 23, v23->as_VMReg()->next() );
+  reg_def V23_J( SOC, SOC, Op_RegF, 23, v23->as_VMReg()->next(2));
+  reg_def V23_K( SOC, SOC, Op_RegF, 23, v23->as_VMReg()->next(3));
+
+  reg_def V24  ( SOC, SOC, Op_RegF, 24, v24->as_VMReg()         );
+  reg_def V24_H( SOC, SOC, Op_RegF, 24, v24->as_VMReg()->next() );
+  reg_def V24_J( SOC, SOC, Op_RegF, 24, v24->as_VMReg()->next(2));
+  reg_def V24_K( SOC, SOC, Op_RegF, 24, v24->as_VMReg()->next(3));
+
+  reg_def V25  ( SOC, SOC, Op_RegF, 25, v25->as_VMReg()         );
+  reg_def V25_H( SOC, SOC, Op_RegF, 25, v25->as_VMReg()->next() );
+  reg_def V25_J( SOC, SOC, Op_RegF, 25, v25->as_VMReg()->next(2));
+  reg_def V25_K( SOC, SOC, Op_RegF, 25, v25->as_VMReg()->next(3));
+
+  reg_def V26  ( SOC, SOC, Op_RegF, 26, v26->as_VMReg()         );
+  reg_def V26_H( SOC, SOC, Op_RegF, 26, v26->as_VMReg()->next() );
+  reg_def V26_J( SOC, SOC, Op_RegF, 26, v26->as_VMReg()->next(2));
+  reg_def V26_K( SOC, SOC, Op_RegF, 26, v26->as_VMReg()->next(3));
+
+  reg_def V27  ( SOC, SOC, Op_RegF, 27, v27->as_VMReg()         );
+  reg_def V27_H( SOC, SOC, Op_RegF, 27, v27->as_VMReg()->next() );
+  reg_def V27_J( SOC, SOC, Op_RegF, 27, v27->as_VMReg()->next(2));
+  reg_def V27_K( SOC, SOC, Op_RegF, 27, v27->as_VMReg()->next(3));
+
+  reg_def V28  ( SOC, SOC, Op_RegF, 28, v28->as_VMReg()         );
+  reg_def V28_H( SOC, SOC, Op_RegF, 28, v28->as_VMReg()->next() );
+  reg_def V28_J( SOC, SOC, Op_RegF, 28, v28->as_VMReg()->next(2));
+  reg_def V28_K( SOC, SOC, Op_RegF, 28, v28->as_VMReg()->next(3));
+
+  reg_def V29  ( SOC, SOC, Op_RegF, 29, v29->as_VMReg()         );
+  reg_def V29_H( SOC, SOC, Op_RegF, 29, v29->as_VMReg()->next() );
+  reg_def V29_J( SOC, SOC, Op_RegF, 29, v29->as_VMReg()->next(2));
+  reg_def V29_K( SOC, SOC, Op_RegF, 29, v29->as_VMReg()->next(3));
+
+  reg_def V30  ( SOC, SOC, Op_RegF, 30, v30->as_VMReg()         );
+  reg_def V30_H( SOC, SOC, Op_RegF, 30, v30->as_VMReg()->next() );
+  reg_def V30_J( SOC, SOC, Op_RegF, 30, v30->as_VMReg()->next(2));
+  reg_def V30_K( SOC, SOC, Op_RegF, 30, v30->as_VMReg()->next(3));
+
+  reg_def V31  ( SOC, SOC, Op_RegF, 31, v31->as_VMReg()         );
+  reg_def V31_H( SOC, SOC, Op_RegF, 31, v31->as_VMReg()->next() );
+  reg_def V31_J( SOC, SOC, Op_RegF, 31, v31->as_VMReg()->next(2));
+  reg_def V31_K( SOC, SOC, Op_RegF, 31, v31->as_VMReg()->next(3));
 
 // ----------------------------
 // Special Registers
@@ -291,42 +386,42 @@
 alloc_class chunk1(
 
     // no save
-    V16, V16_H,
-    V17, V17_H,
-    V18, V18_H,
-    V19, V19_H,
-    V20, V20_H,
-    V21, V21_H,
-    V22, V22_H,
-    V23, V23_H,
-    V24, V24_H,
-    V25, V25_H,
-    V26, V26_H,
-    V27, V27_H,
-    V28, V28_H,
-    V29, V29_H,
-    V30, V30_H,
-    V31, V31_H,
+    V16, V16_H, V16_J, V16_K,
+    V17, V17_H, V17_J, V17_K,
+    V18, V18_H, V18_J, V18_K,
+    V19, V19_H, V19_J, V19_K,
+    V20, V20_H, V20_J, V20_K,
+    V21, V21_H, V21_J, V21_K,
+    V22, V22_H, V22_J, V22_K,
+    V23, V23_H, V23_J, V23_K,
+    V24, V24_H, V24_J, V24_K,
+    V25, V25_H, V25_J, V25_K,
+    V26, V26_H, V26_J, V26_K,
+    V27, V27_H, V27_J, V27_K,
+    V28, V28_H, V28_J, V28_K,
+    V29, V29_H, V29_J, V29_K,
+    V30, V30_H, V30_J, V30_K,
+    V31, V31_H, V31_J, V31_K,
 
     // arg registers
-    V0, V0_H,
-    V1, V1_H,
-    V2, V2_H,
-    V3, V3_H,
-    V4, V4_H,
-    V5, V5_H,
-    V6, V6_H,
-    V7, V7_H,
+    V0, V0_H, V0_J, V0_K,
+    V1, V1_H, V1_J, V1_K,
+    V2, V2_H, V2_J, V2_K,
+    V3, V3_H, V3_J, V3_K,
+    V4, V4_H, V4_J, V4_K,
+    V5, V5_H, V5_J, V5_K,
+    V6, V6_H, V6_J, V6_K,
+    V7, V7_H, V7_J, V7_K,
 
     // non-volatiles
-    V8, V8_H,
-    V9, V9_H,
-    V10, V10_H,
-    V11, V11_H,
-    V12, V12_H,
-    V13, V13_H,
-    V14, V14_H,
-    V15, V15_H,
+    V8, V8_H, V8_J, V8_K,
+    V9, V9_H, V9_J, V9_K,
+    V10, V10_H, V10_J, V10_K,
+    V11, V11_H, V11_J, V11_K,
+    V12, V12_H, V12_J, V12_K,
+    V13, V13_H, V13_J, V13_K,
+    V14, V14_H, V14_J, V14_K,
+    V15, V15_H, V15_J, V15_K,
 );
 
 alloc_class chunk2(RFLAGS);
@@ -770,6 +865,42 @@
     V31, V31_H
 );
 
+// Class for all 128bit vector registers
+reg_class vectorx_reg(
+    V0, V0_H, V0_J, V0_K,
+    V1, V1_H, V1_J, V1_K,
+    V2, V2_H, V2_J, V2_K,
+    V3, V3_H, V3_J, V3_K,
+    V4, V4_H, V4_J, V4_K,
+    V5, V5_H, V5_J, V5_K,
+    V6, V6_H, V6_J, V6_K,
+    V7, V7_H, V7_J, V7_K,
+    V8, V8_H, V8_J, V8_K,
+    V9, V9_H, V9_J, V9_K,
+    V10, V10_H, V10_J, V10_K,
+    V11, V11_H, V11_J, V11_K,
+    V12, V12_H, V12_J, V12_K,
+    V13, V13_H, V13_J, V13_K,
+    V14, V14_H, V14_J, V14_K,
+    V15, V15_H, V15_J, V15_K,
+    V16, V16_H, V16_J, V16_K,
+    V17, V17_H, V17_J, V17_K,
+    V18, V18_H, V18_J, V18_K,
+    V19, V19_H, V19_J, V19_K,
+    V20, V20_H, V20_J, V20_K,
+    V21, V21_H, V21_J, V21_K,
+    V22, V22_H, V22_J, V22_K,
+    V23, V23_H, V23_J, V23_K,
+    V24, V24_H, V24_J, V24_K,
+    V25, V25_H, V25_J, V25_K,
+    V26, V26_H, V26_J, V26_K,
+    V27, V27_H, V27_J, V27_K,
+    V28, V28_H, V28_J, V28_K,
+    V29, V29_H, V29_J, V29_K,
+    V30, V30_H, V30_J, V30_K,
+    V31, V31_H, V31_J, V31_K
+);
+
 // Class for 128 bit register v0
 reg_class v0_reg(
     V0, V0_H
@@ -1964,7 +2095,7 @@
   }
 
   // we have 32 float register * 2 halves
-  if (reg < 60 + 64) {
+  if (reg < 60 + 128) {
     return rc_float;
   }
 
@@ -2000,6 +2131,78 @@
     return 0;            // Self copy, no move.
   }
 
+  if (bottom_type()->isa_vect() != NULL) {
+    uint len = 4;
+    if (cbuf) {
+      MacroAssembler _masm(cbuf);
+      uint ireg = ideal_reg();
+      assert((src_lo_rc != rc_int && dst_lo_rc != rc_int), "sanity");
+      assert(ireg == Op_VecX, "sanity");
+      if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) {
+        // stack->stack
+        int src_offset = ra_->reg2offset(src_lo);
+        int dst_offset = ra_->reg2offset(dst_lo);
+        assert((src_offset & 7) && (dst_offset & 7), "unaligned stack offset");
+        len = 8;
+        if (src_offset < 512) {
+          __ ldp(rscratch1, rscratch2, Address(sp, src_offset));
+        } else {
+          __ ldr(rscratch1, Address(sp, src_offset));
+          __ ldr(rscratch2, Address(sp, src_offset+4));
+          len += 4;
+        }
+        if (dst_offset < 512) {
+          __ stp(rscratch1, rscratch2, Address(sp, dst_offset));
+        } else {
+          __ str(rscratch1, Address(sp, dst_offset));
+          __ str(rscratch2, Address(sp, dst_offset+4));
+          len += 4;
+        }
+      } else if (src_lo_rc == rc_float && dst_lo_rc == rc_float) {
+        __ orr(as_FloatRegister(Matcher::_regEncode[dst_lo]), __ T16B,
+               as_FloatRegister(Matcher::_regEncode[src_lo]),
+               as_FloatRegister(Matcher::_regEncode[src_lo]));
+      } else if (src_lo_rc == rc_float && dst_lo_rc == rc_stack) {
+        __ str(as_FloatRegister(Matcher::_regEncode[src_lo]), __ Q,
+               Address(sp, ra_->reg2offset(dst_lo)));
+      } else if (src_lo_rc == rc_stack && dst_lo_rc == rc_float) {
+        __ ldr(as_FloatRegister(Matcher::_regEncode[dst_lo]), __ Q,
+               Address(sp, ra_->reg2offset(src_lo)));
+      } else {
+        ShouldNotReachHere();
+      }
+    } else if (st) {
+      if (src_lo_rc == rc_stack && dst_lo_rc == rc_stack) {
+        // stack->stack
+        int src_offset = ra_->reg2offset(src_lo);
+        int dst_offset = ra_->reg2offset(dst_lo);
+        if (src_offset < 512) {
+          st->print("ldp  rscratch1, rscratch2, [sp, #%d]", src_offset);
+        } else {
+          st->print("ldr  rscratch1, [sp, #%d]", src_offset);
+          st->print("\nldr  rscratch2, [sp, #%d]", src_offset+4);
+        }
+        if (dst_offset < 512) {
+          st->print("\nstp  rscratch1, rscratch2, [sp, #%d]", dst_offset);
+        } else {
+          st->print("\nstr  rscratch1, [sp, #%d]", dst_offset);
+          st->print("\nstr  rscratch2, [sp, #%d]", dst_offset+4);
+        }
+        st->print("\t# vector spill, stack to stack");
+      } else if (src_lo_rc == rc_float && dst_lo_rc == rc_float) {
+        st->print("mov  %s, %s\t# vector spill, reg to reg",
+                   Matcher::regName[dst_lo], Matcher::regName[src_lo]);
+      } else if (src_lo_rc == rc_float && dst_lo_rc == rc_stack) {
+        st->print("str  %s, [sp, #%d]\t# vector spill, reg to stack",
+                   Matcher::regName[src_lo], ra_->reg2offset(dst_lo));
+      } else if (src_lo_rc == rc_stack && dst_lo_rc == rc_float) {
+        st->print("ldr  %s, [sp, #%d]\t# vector spill, stack to reg",
+                   Matcher::regName[dst_lo], ra_->reg2offset(src_lo));
+      }
+    }
+    return len;
+  }
+
   switch (src_lo_rc) {
   case rc_int:
     if (dst_lo_rc == rc_int) {  // gpr --> gpr copy
@@ -2422,8 +2625,12 @@
 
 // Vector width in bytes.
 const int Matcher::vector_width_in_bytes(BasicType bt) {
-  // TODO fixme
-  return 0;
+  int size = MIN2(16,(int)MaxVectorSize);
+  // Minimum 2 values in vector
+  if (size < 2*type2aelembytes(bt)) size = 0;
+  // But never < 4
+  if (size < 4) size = 0;
+  return size;
 }
 
 // Limits on vector size (number of elements) loaded into vector.
@@ -2431,22 +2638,19 @@
   return vector_width_in_bytes(bt)/type2aelembytes(bt);
 }
 const int Matcher::min_vector_size(const BasicType bt) {
-  int max_size = max_vector_size(bt);
-  // Min size which can be loaded into vector is 4 bytes.
-  int size = (type2aelembytes(bt) == 1) ? 4 : 2;
-  return MIN2(size,max_size);
+  //return (type2aelembytes(bt) == 1) ? 4 : 2;
+  // For the moment, only support 1 vector size, 128 bits
+  return max_vector_size(bt);
 }
 
 // Vector ideal reg.
 const int Matcher::vector_ideal_reg(int len) {
-  // TODO fixme
-  return Op_RegD;
+  return Op_VecX;
 }
 
 // Only lowest bits of xmm reg are used for vector shift count.
 const int Matcher::vector_shift_count_ideal_reg(int size) {
-  // TODO fixme
-  return Op_RegL;
+  return Op_VecX;
 }
 
 // AES support not yet implemented
@@ -2657,6 +2861,8 @@
 
 typedef void (MacroAssembler::* mem_insn)(Register Rt, const Address &adr);
 typedef void (MacroAssembler::* mem_float_insn)(FloatRegister Rt, const Address &adr);
+typedef void (MacroAssembler::* mem_vector_insn)(FloatRegister Rt,
+                                  MacroAssembler::SIMD_RegVariant T, const Address &adr);
 
   // Used for all non-volatile memory accesses.  The use of
   // $mem->opcode() to discover whether this pattern uses sign-extended
@@ -2724,6 +2930,18 @@
     }
   }
 
+  static void loadStore(MacroAssembler masm, mem_vector_insn insn,
+                         FloatRegister reg, MacroAssembler::SIMD_RegVariant T,
+                         int opcode, Register base, int index, int size, int disp)
+  {
+    if (index == -1) {
+      (masm.*insn)(reg, T, Address(base, disp));
+    } else {
+      assert(disp == 0, "unsupported address mode");
+      (masm.*insn)(reg, T, Address(base, as_Register(index), Address::lsl(size)));
+    }
+  }
+
 %}
 
 
@@ -2855,6 +3073,24 @@
                as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
   %}
 
+  enc_class aarch64_enc_ldrvS(vecX dst, memory mem) %{
+    FloatRegister dst_reg = as_FloatRegister($dst$$reg);
+    loadStore(MacroAssembler(&cbuf), &MacroAssembler::ldr, dst_reg, MacroAssembler::S,
+       $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
+  %}
+
+  enc_class aarch64_enc_ldrvD(vecX dst, memory mem) %{
+    FloatRegister dst_reg = as_FloatRegister($dst$$reg);
+    loadStore(MacroAssembler(&cbuf), &MacroAssembler::ldr, dst_reg, MacroAssembler::D,
+       $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
+  %}
+
+  enc_class aarch64_enc_ldrvQ(vecX dst, memory mem) %{
+    FloatRegister dst_reg = as_FloatRegister($dst$$reg);
+    loadStore(MacroAssembler(&cbuf), &MacroAssembler::ldr, dst_reg, MacroAssembler::Q,
+       $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
+  %}
+
   enc_class aarch64_enc_strb(iRegI src, memory mem) %{
     Register src_reg = as_Register($src$$reg);
     loadStore(MacroAssembler(&cbuf), &MacroAssembler::strb, src_reg, $mem->opcode(),
@@ -2923,6 +3159,24 @@
                as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
   %}
 
+  enc_class aarch64_enc_strvS(vecX src, memory mem) %{
+    FloatRegister src_reg = as_FloatRegister($src$$reg);
+    loadStore(MacroAssembler(&cbuf), &MacroAssembler::str, src_reg, MacroAssembler::S,
+       $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
+  %}
+
+  enc_class aarch64_enc_strvD(vecX src, memory mem) %{
+    FloatRegister src_reg = as_FloatRegister($src$$reg);
+    loadStore(MacroAssembler(&cbuf), &MacroAssembler::str, src_reg, MacroAssembler::D,
+       $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
+  %}
+
+  enc_class aarch64_enc_strvQ(vecX src, memory mem) %{
+    FloatRegister src_reg = as_FloatRegister($src$$reg);
+    loadStore(MacroAssembler(&cbuf), &MacroAssembler::str, src_reg, MacroAssembler::Q,
+       $mem->opcode(), as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
+  %}
+
   // END Non-volatile memory access
 
   // volatile loads and stores
@@ -4933,6 +5187,16 @@
   interface(REG_INTER);
 %}
 
+operand vecX()
+%{
+  constraint(ALLOC_IN_RC(vectorx_reg));
+  match(VecX);
+
+  op_cost(0);
+  format %{ %}
+  interface(REG_INTER);
+%}
+
 operand vRegD_V0()
 %{
   constraint(ALLOC_IN_RC(v0_reg));
@@ -5505,6 +5769,7 @@
   interface(REG_INTER)
 %}
 
+opclass vmem(indirect, indIndex, indOffI, indOffL);
 
 //----------OPERAND CLASSES----------------------------------------------------
 // Operand Classes are groups of operands that are used as to simplify
@@ -12926,7 +13191,919 @@
   ins_pipe(pipe_class_empty);
 %}
 
-
+// ====================VECTOR INSTRUCTIONS=====================================
+
+// Load vector (32 bits)
+instruct loadV4(vecX dst, vmem mem)
+%{
+  predicate(n->as_LoadVector()->memory_size() == 4);
+  match(Set dst (LoadVector mem));
+  ins_cost(4 * INSN_COST);
+  format %{ "ldrs   $dst,$mem\t# vector (32 bits)" %}
+  ins_encode( aarch64_enc_ldrvS(dst, mem) );
+  ins_pipe(pipe_class_memory);
+%}
+
+// Load vector (64 bits)
+instruct loadV8(vecX dst, vmem mem)
+%{
+  predicate(n->as_LoadVector()->memory_size() == 8);
+  match(Set dst (LoadVector mem));
+  ins_cost(4 * INSN_COST);
+  format %{ "ldrd   $dst,$mem\t# vector (64 bits)" %}
+  ins_encode( aarch64_enc_ldrvD(dst, mem) );
+  ins_pipe(pipe_class_memory);
+%}
+
+// Load Vector (128 bits)
+instruct loadV16(vecX dst, vmem mem)
+%{
+  predicate(n->as_LoadVector()->memory_size() == 16);
+  match(Set dst (LoadVector mem));
+  ins_cost(4 * INSN_COST);
+  format %{ "ldrq   $dst,$mem\t# vector (128 bits)" %}
+  ins_encode( aarch64_enc_ldrvQ(dst, mem) );
+  ins_pipe(pipe_class_memory);
+%}
+
+// Store Vector (32 bits)
+instruct storeV4(vecX src, vmem mem)
+%{
+  predicate(n->as_StoreVector()->memory_size() == 4);
+  match(Set mem (StoreVector mem src));
+  ins_cost(4 * INSN_COST);
+  format %{ "strs   $mem,$src\t# vector (32 bits)" %}
+  ins_encode( aarch64_enc_strvS(src, mem) );
+  ins_pipe(pipe_class_memory);
+%}
+
+// Store Vector (64 bits)
+instruct storeV8(vecX src, vmem mem)
+%{
+  predicate(n->as_StoreVector()->memory_size() == 8);
+  match(Set mem (StoreVector mem src));
+  ins_cost(4 * INSN_COST);
+  format %{ "strd   $mem,$src\t# vector (64 bits)" %}
+  ins_encode( aarch64_enc_strvD(src, mem) );
+  ins_pipe(pipe_class_memory);
+%}
+
+// Store Vector (128 bits)
+instruct storeV16(vecX src, vmem mem)
+%{
+  predicate(n->as_StoreVector()->memory_size() == 16);
+  match(Set mem (StoreVector mem src));
+  ins_cost(4 * INSN_COST);
+  format %{ "strq   $mem,$src\t# vector (128 bits)" %}
+  ins_encode( aarch64_enc_strvQ(src, mem) );
+  ins_pipe(pipe_class_memory);
+%}
+
+instruct replicate16B(vecX dst, iRegIorL2I src)
+%{
+  match(Set dst (ReplicateB src));
+  ins_cost(INSN_COST);
+  format %{ "dup  $dst, $src\t# vector (16B)" %}
+  ins_encode %{
+    __ dup(as_FloatRegister($dst$$reg), __ T16B, as_Register($src$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct replicate16B_imm(vecX dst, immI con)
+%{
+  match(Set dst (ReplicateB con));
+  ins_cost(INSN_COST);
+  format %{ "movi  $dst, $con\t# vector(16B)" %}
+  ins_encode %{
+    __ mov(as_FloatRegister($dst$$reg), __ T16B, $con$$constant);
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct replicate8S(vecX dst, iRegIorL2I src)
+%{
+  match(Set dst (ReplicateS src));
+  ins_cost(INSN_COST);
+  format %{ "dup  $dst, $src\t# vector (8S)" %}
+  ins_encode %{
+    __ dup(as_FloatRegister($dst$$reg), __ T8H, as_Register($src$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct replicate8S_imm(vecX dst, immI con)
+%{
+  match(Set dst (ReplicateS con));
+  ins_cost(INSN_COST);
+  format %{ "movi  $dst, $con\t# vector(8H)" %}
+  ins_encode %{
+    __ mov(as_FloatRegister($dst$$reg), __ T8H, $con$$constant);
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct replicate4I(vecX dst, iRegIorL2I src)
+%{
+  match(Set dst (ReplicateI src));
+  ins_cost(INSN_COST);
+  format %{ "dup  $dst, $src\t# vector (4I)" %}
+  ins_encode %{
+    __ dup(as_FloatRegister($dst$$reg), __ T4S, as_Register($src$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct replicate4I_imm(vecX dst, immI con)
+%{
+  match(Set dst (ReplicateI con));
+  ins_cost(INSN_COST);
+  format %{ "movi  $dst, $con\t# vector(4I)" %}
+  ins_encode %{
+    __ mov(as_FloatRegister($dst$$reg), __ T4S, $con$$constant);
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct replicate2L(vecX dst, iRegL src)
+%{
+  match(Set dst (ReplicateL src));
+  ins_cost(INSN_COST);
+  format %{ "dup  $dst, $src\t# vector (2L)" %}
+  ins_encode %{
+    __ dup(as_FloatRegister($dst$$reg), __ T2D, as_Register($src$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct replicate2L_zero(vecX dst, immI0 zero)
+%{
+  match(Set dst (ReplicateI zero));
+  ins_cost(INSN_COST);
+  format %{ "movi  $dst, $zero\t# vector(4I)" %}
+  ins_encode %{
+    __ eor(as_FloatRegister($dst$$reg), __ T16B,
+           as_FloatRegister($dst$$reg),
+           as_FloatRegister($dst$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct replicate4F(vecX dst, vRegF src)
+%{
+  match(Set dst (ReplicateF src));
+  ins_cost(INSN_COST);
+  format %{ "dup  $dst, $src\t# vector (4F)" %}
+  ins_encode %{
+    __ dup(as_FloatRegister($dst$$reg), __ T4S,
+           as_FloatRegister($src$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct replicate2D(vecX dst, vRegD src)
+%{
+  match(Set dst (ReplicateD src));
+  ins_cost(INSN_COST);
+  format %{ "dup  $dst, $src\t# vector (2D)" %}
+  ins_encode %{
+    __ dup(as_FloatRegister($dst$$reg), __ T2D,
+           as_FloatRegister($src$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+// ====================REDUCTION ARITHMETIC====================================
+
+instruct reduce_add4I(iRegINoSp dst, iRegIorL2I src1, vecX src2, vecX tmp, iRegI tmp2)
+%{
+  match(Set dst (AddReductionVI src1 src2));
+  ins_cost(INSN_COST);
+  effect(TEMP tmp, TEMP tmp2);
+  format %{ "addv  $tmp, T4S, $src2\n\t"
+            "umov  $tmp2, $tmp, S, 0\n\t"
+            "addw  $dst, $tmp2, $src1\t add reduction4i"
+  %}
+  ins_encode %{
+    __ addv(as_FloatRegister($tmp$$reg), __ T4S,
+            as_FloatRegister($src2$$reg));
+    __ umov($tmp2$$Register, as_FloatRegister($tmp$$reg), __ S, 0);
+    __ addw($dst$$Register, $tmp2$$Register, $src1$$Register);
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct reduce_mul4I(iRegINoSp dst, iRegIorL2I src1, vecX src2, vecX tmp, iRegI tmp2)
+%{
+  match(Set dst (MulReductionVI src1 src2));
+  ins_cost(INSN_COST);
+  effect(TEMP tmp, TEMP tmp2, TEMP dst);
+  format %{ "ins   $tmp, $src2, 0, 1\n\t"
+            "mul   $tmp, $tmp, $src2\n\t"
+            "umov  $tmp2, $tmp, S, 0\n\t"
+            "mul   $dst, $tmp2, $src1\n\t"
+            "umov  $tmp2, $tmp, S, 1\n\t"
+            "mul   $dst, $tmp2, $dst\t mul reduction4i\n\t"
+  %}
+  ins_encode %{
+    __ ins(as_FloatRegister($tmp$$reg), __ D,
+           as_FloatRegister($src2$$reg), 0, 1);
+    __ mulv(as_FloatRegister($tmp$$reg), __ T2S,
+           as_FloatRegister($tmp$$reg), as_FloatRegister($src2$$reg));
+    __ umov($tmp2$$Register, as_FloatRegister($tmp$$reg), __ S, 0);
+    __ mul($dst$$Register, $tmp2$$Register, $src1$$Register);
+    __ umov($tmp2$$Register, as_FloatRegister($tmp$$reg), __ S, 1);
+    __ mul($dst$$Register, $tmp2$$Register, $dst$$Register);
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct reduce_add4F(vRegF dst, vRegF src1, vecX src2, vecX tmp)
+%{
+  match(Set dst (AddReductionVF src1 src2));
+  ins_cost(INSN_COST);
+  effect(TEMP tmp, TEMP dst);
+  format %{ "fadds $dst, $src1, $src2\n\t"
+            "ins   $tmp, S, $src2, 0, 1\n\t"
+            "fadds $dst, $dst, $tmp\n\t"
+            "ins   $tmp, S, $src2, 0, 2\n\t"
+            "fadds $dst, $dst, $tmp\n\t"
+            "ins   $tmp, S, $src2, 0, 3\n\t"
+            "fadds $dst, $dst, $tmp\t add reduction4f"
+  %}
+  ins_encode %{
+    __ fadds(as_FloatRegister($dst$$reg),
+             as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg));
+    __ ins(as_FloatRegister($tmp$$reg), __ S,
+           as_FloatRegister($src2$$reg), 0, 1);
+    __ fadds(as_FloatRegister($dst$$reg),
+             as_FloatRegister($dst$$reg), as_FloatRegister($tmp$$reg));
+    __ ins(as_FloatRegister($tmp$$reg), __ S,
+           as_FloatRegister($src2$$reg), 0, 2);
+    __ fadds(as_FloatRegister($dst$$reg),
+             as_FloatRegister($dst$$reg), as_FloatRegister($tmp$$reg));
+    __ ins(as_FloatRegister($tmp$$reg), __ S,
+           as_FloatRegister($src2$$reg), 0, 3);
+    __ fadds(as_FloatRegister($dst$$reg),
+             as_FloatRegister($dst$$reg), as_FloatRegister($tmp$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct reduce_mul4F(vRegF dst, vRegF src1, vecX src2, vecX tmp)
+%{
+  match(Set dst (MulReductionVF src1 src2));
+  ins_cost(INSN_COST);
+  effect(TEMP tmp, TEMP dst);
+  format %{ "fmuls $dst, $src1, $src2\n\t"
+            "ins   $tmp, S, $src2, 0, 1\n\t"
+            "fmuls $dst, $dst, $tmp\n\t"
+            "ins   $tmp, S, $src2, 0, 2\n\t"
+            "fmuls $dst, $dst, $tmp\n\t"
+            "ins   $tmp, S, $src2, 0, 3\n\t"
+            "fmuls $dst, $dst, $tmp\t add reduction4f"
+  %}
+  ins_encode %{
+    __ fmuls(as_FloatRegister($dst$$reg),
+             as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg));
+    __ ins(as_FloatRegister($tmp$$reg), __ S,
+           as_FloatRegister($src2$$reg), 0, 1);
+    __ fmuls(as_FloatRegister($dst$$reg),
+             as_FloatRegister($dst$$reg), as_FloatRegister($tmp$$reg));
+    __ ins(as_FloatRegister($tmp$$reg), __ S,
+           as_FloatRegister($src2$$reg), 0, 2);
+    __ fmuls(as_FloatRegister($dst$$reg),
+             as_FloatRegister($dst$$reg), as_FloatRegister($tmp$$reg));
+    __ ins(as_FloatRegister($tmp$$reg), __ S,
+           as_FloatRegister($src2$$reg), 0, 3);
+    __ fmuls(as_FloatRegister($dst$$reg),
+             as_FloatRegister($dst$$reg), as_FloatRegister($tmp$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct reduce_add2D(vRegD dst, vRegD src1, vecX src2, vecX tmp)
+%{
+  match(Set dst (AddReductionVD src1 src2));
+  ins_cost(INSN_COST);
+  effect(TEMP tmp, TEMP dst);
+  format %{ "faddd $dst, $src1, $src2\n\t"
+            "ins   $tmp, D, $src2, 0, 1\n\t"
+            "faddd $dst, $dst, $tmp\t add reduction2d"
+  %}
+  ins_encode %{
+    __ faddd(as_FloatRegister($dst$$reg),
+             as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg));
+    __ ins(as_FloatRegister($tmp$$reg), __ D,
+           as_FloatRegister($src2$$reg), 0, 1);
+    __ faddd(as_FloatRegister($dst$$reg),
+             as_FloatRegister($dst$$reg), as_FloatRegister($tmp$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct reduce_mul2D(vRegD dst, vRegD src1, vecX src2, vecX tmp)
+%{
+  match(Set dst (MulReductionVD src1 src2));
+  ins_cost(INSN_COST);
+  effect(TEMP tmp, TEMP dst);
+  format %{ "fmuld $dst, $src1, $src2\n\t"
+            "ins   $tmp, D, $src2, 0, 1\n\t"
+            "fmuld $dst, $dst, $tmp\t add reduction2d"
+  %}
+  ins_encode %{
+    __ fmuld(as_FloatRegister($dst$$reg),
+             as_FloatRegister($src1$$reg), as_FloatRegister($src2$$reg));
+    __ ins(as_FloatRegister($tmp$$reg), __ D,
+           as_FloatRegister($src2$$reg), 0, 1);
+    __ fmuld(as_FloatRegister($dst$$reg),
+             as_FloatRegister($dst$$reg), as_FloatRegister($tmp$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+// ====================VECTOR ARITHMETIC=======================================
+
+// --------------------------------- ADD --------------------------------------
+
+instruct vadd16B(vecX dst, vecX src1, vecX src2)
+%{
+  match(Set dst (AddVB src1 src2));
+  ins_cost(INSN_COST);
+  format %{ "addv  $dst,$src1,$src2\t# vector (16B)" %}
+  ins_encode %{
+    __ addv(as_FloatRegister($dst$$reg), __ T16B,
+            as_FloatRegister($src1$$reg),
+            as_FloatRegister($src2$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vadd8S(vecX dst, vecX src1, vecX src2)
+%{
+  match(Set dst (AddVS src1 src2));
+  ins_cost(INSN_COST);
+  format %{ "addv  $dst,$src1,$src2\t# vector (8H)" %}
+  ins_encode %{
+    __ addv(as_FloatRegister($dst$$reg), __ T8H,
+            as_FloatRegister($src1$$reg),
+            as_FloatRegister($src2$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vadd4I(vecX dst, vecX src1, vecX src2)
+%{
+  match(Set dst (AddVI src1 src2));
+  ins_cost(INSN_COST);
+  format %{ "addv  $dst,$src1,$src2\t# vector (4S)" %}
+  ins_encode %{
+    __ addv(as_FloatRegister($dst$$reg), __ T4S,
+            as_FloatRegister($src1$$reg),
+            as_FloatRegister($src2$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vadd2L(vecX dst, vecX src1, vecX src2)
+%{
+  match(Set dst (AddVL src1 src2));
+  ins_cost(INSN_COST);
+  format %{ "addv  $dst,$src1,$src2\t# vector (2L)" %}
+  ins_encode %{
+    __ addv(as_FloatRegister($dst$$reg), __ T2D,
+            as_FloatRegister($src1$$reg),
+            as_FloatRegister($src2$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vadd4F(vecX dst, vecX src1, vecX src2)
+%{
+  match(Set dst (AddVF src1 src2));
+  ins_cost(INSN_COST);
+  format %{ "fadd  $dst,$src1,$src2\t# vector (4S)" %}
+  ins_encode %{
+    __ fadd(as_FloatRegister($dst$$reg), __ T4S,
+            as_FloatRegister($src1$$reg),
+            as_FloatRegister($src2$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vadd2D(vecX dst, vecX src1, vecX src2)
+%{
+  match(Set dst (AddVD src1 src2));
+  ins_cost(INSN_COST);
+  format %{ "fadd  $dst,$src1,$src2\t# vector (2D)" %}
+  ins_encode %{
+    __ fadd(as_FloatRegister($dst$$reg), __ T2D,
+            as_FloatRegister($src1$$reg),
+            as_FloatRegister($src2$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+// --------------------------------- SUB --------------------------------------
+
+instruct vsub16B(vecX dst, vecX src1, vecX src2)
+%{
+  match(Set dst (SubVB src1 src2));
+  ins_cost(INSN_COST);
+  format %{ "subv  $dst,$src1,$src2\t# vector (16B)" %}
+  ins_encode %{
+    __ subv(as_FloatRegister($dst$$reg), __ T16B,
+            as_FloatRegister($src1$$reg),
+            as_FloatRegister($src2$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vsub8S(vecX dst, vecX src1, vecX src2)
+%{
+  match(Set dst (SubVS src1 src2));
+  ins_cost(INSN_COST);
+  format %{ "subv  $dst,$src1,$src2\t# vector (8H)" %}
+  ins_encode %{
+    __ subv(as_FloatRegister($dst$$reg), __ T8H,
+            as_FloatRegister($src1$$reg),
+            as_FloatRegister($src2$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vsub4I(vecX dst, vecX src1, vecX src2)
+%{
+  match(Set dst (SubVI src1 src2));
+  ins_cost(INSN_COST);
+  format %{ "subv  $dst,$src1,$src2\t# vector (4S)" %}
+  ins_encode %{
+    __ subv(as_FloatRegister($dst$$reg), __ T4S,
+            as_FloatRegister($src1$$reg),
+            as_FloatRegister($src2$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vsub2L(vecX dst, vecX src1, vecX src2)
+%{
+  match(Set dst (SubVL src1 src2));
+  ins_cost(INSN_COST);
+  format %{ "subv  $dst,$src1,$src2\t# vector (2L)" %}
+  ins_encode %{
+    __ subv(as_FloatRegister($dst$$reg), __ T2D,
+            as_FloatRegister($src1$$reg),
+            as_FloatRegister($src2$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vsub4F(vecX dst, vecX src1, vecX src2)
+%{
+  match(Set dst (SubVF src1 src2));
+  ins_cost(INSN_COST);
+  format %{ "fsub  $dst,$src1,$src2\t# vector (4S)" %}
+  ins_encode %{
+    __ fsub(as_FloatRegister($dst$$reg), __ T4S,
+            as_FloatRegister($src1$$reg),
+            as_FloatRegister($src2$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vsub2D(vecX dst, vecX src1, vecX src2)
+%{
+  match(Set dst (SubVD src1 src2));
+  ins_cost(INSN_COST);
+  format %{ "fsub  $dst,$src1,$src2\t# vector (2D)" %}
+  ins_encode %{
+    __ fsub(as_FloatRegister($dst$$reg), __ T2D,
+            as_FloatRegister($src1$$reg),
+            as_FloatRegister($src2$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+// --------------------------------- MUL --------------------------------------
+
+instruct vmul8S(vecX dst, vecX src1, vecX src2)
+%{
+  match(Set dst (MulVS src1 src2));
+  ins_cost(INSN_COST);
+  format %{ "mulv  $dst,$src1,$src2\t# vector (8H)" %}
+  ins_encode %{
+    __ mulv(as_FloatRegister($dst$$reg), __ T8H,
+            as_FloatRegister($src1$$reg),
+            as_FloatRegister($src2$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vmul4I(vecX dst, vecX src1, vecX src2)
+%{
+  match(Set dst (MulVI src1 src2));
+  ins_cost(INSN_COST);
+  format %{ "mulv  $dst,$src1,$src2\t# vector (4S)" %}
+  ins_encode %{
+    __ mulv(as_FloatRegister($dst$$reg), __ T4S,
+            as_FloatRegister($src1$$reg),
+            as_FloatRegister($src2$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vmul4F(vecX dst, vecX src1, vecX src2)
+%{
+  match(Set dst (MulVF src1 src2));
+  ins_cost(INSN_COST);
+  format %{ "fmul  $dst,$src1,$src2\t# vector (4S)" %}
+  ins_encode %{
+    __ fmul(as_FloatRegister($dst$$reg), __ T4S,
+            as_FloatRegister($src1$$reg),
+            as_FloatRegister($src2$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vmul2D(vecX dst, vecX src1, vecX src2)
+%{
+  match(Set dst (MulVD src1 src2));
+  ins_cost(INSN_COST);
+  format %{ "fmul  $dst,$src1,$src2\t# vector (2D)" %}
+  ins_encode %{
+    __ fmul(as_FloatRegister($dst$$reg), __ T2D,
+            as_FloatRegister($src1$$reg),
+            as_FloatRegister($src2$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+// --------------------------------- DIV --------------------------------------
+
+instruct vdiv4F(vecX dst, vecX src1, vecX src2)
+%{
+  match(Set dst (DivVF src1 src2));
+  ins_cost(INSN_COST);
+  format %{ "fdiv  $dst,$src1,$src2\t# vector (4S)" %}
+  ins_encode %{
+    __ fdiv(as_FloatRegister($dst$$reg), __ T4S,
+            as_FloatRegister($src1$$reg),
+            as_FloatRegister($src2$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vdiv2D(vecX dst, vecX src1, vecX src2)
+%{
+  match(Set dst (DivVD src1 src2));
+  ins_cost(INSN_COST);
+  format %{ "fdiv  $dst,$src1,$src2\t# vector (2D)" %}
+  ins_encode %{
+    __ fdiv(as_FloatRegister($dst$$reg), __ T2D,
+            as_FloatRegister($src1$$reg),
+            as_FloatRegister($src2$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+// --------------------------------- AND --------------------------------------
+
+instruct vand16B(vecX dst, vecX src1, vecX src2)
+%{
+  match(Set dst (AndV src1 src2));
+  ins_cost(INSN_COST);
+  format %{ "and  $dst,$src1,$src2\t# vector (16B)" %}
+  ins_encode %{
+    __ andr(as_FloatRegister($dst$$reg), __ T16B,
+            as_FloatRegister($src1$$reg),
+            as_FloatRegister($src2$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+// --------------------------------- OR ---------------------------------------
+
+instruct vor16B(vecX dst, vecX src1, vecX src2)
+%{
+  match(Set dst (OrV src1 src2));
+  ins_cost(INSN_COST);
+  format %{ "orr  $dst,$src1,$src2\t# vector (16B)" %}
+  ins_encode %{
+    __ orr(as_FloatRegister($dst$$reg), __ T16B,
+            as_FloatRegister($src1$$reg),
+            as_FloatRegister($src2$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+// --------------------------------- XOR --------------------------------------
+
+instruct vxor16B(vecX dst, vecX src1, vecX src2)
+%{
+  match(Set dst (XorV src1 src2));
+  ins_cost(INSN_COST);
+  format %{ "xor  $dst,$src1,$src2\t# vector (16B)" %}
+  ins_encode %{
+    __ eor(as_FloatRegister($dst$$reg), __ T16B,
+            as_FloatRegister($src1$$reg),
+            as_FloatRegister($src2$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+// ------------------------------ Shift ---------------------------------------
+
+instruct vshiftcntL(vecX dst, iRegIorL2I cnt) %{
+  match(Set dst (LShiftCntV cnt));
+  format %{ "dup  $dst, $cnt\t# shift count (vecX)" %}
+  ins_encode %{
+    __ dup(as_FloatRegister($dst$$reg), __ T16B, as_Register($cnt$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+// Right shifts on aarch64 SIMD are implemented as left shift by -ve amount
+instruct vshiftcntR(vecX dst, iRegIorL2I cnt) %{
+  match(Set dst (RShiftCntV cnt));
+  format %{ "dup  $dst, $cnt\t# shift count (vecX)\n\tneg  $dst, $dst\t T16B" %}
+  ins_encode %{
+    __ dup(as_FloatRegister($dst$$reg), __ T16B, as_Register($cnt$$reg));
+    __ negr(as_FloatRegister($dst$$reg), __ T16B, as_FloatRegister($dst$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vsll16B(vecX dst, vecX src, vecX shift) %{
+  match(Set dst (LShiftVB src shift));
+  match(Set dst (RShiftVB src shift));
+  ins_cost(INSN_COST);
+  format %{ "sshl  $dst,$src,$shift\t# vector (16B)" %}
+  ins_encode %{
+    __ sshl(as_FloatRegister($dst$$reg), __ T16B,
+            as_FloatRegister($src$$reg),
+            as_FloatRegister($shift$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vsrl16B(vecX dst, vecX src, vecX shift) %{
+  match(Set dst (URShiftVB src shift));
+  ins_cost(INSN_COST);
+  format %{ "ushl  $dst,$src,$shift\t# vector (16B)" %}
+  ins_encode %{
+    __ ushl(as_FloatRegister($dst$$reg), __ T16B,
+            as_FloatRegister($src$$reg),
+            as_FloatRegister($shift$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vsll16B_imm(vecX dst, vecX src, immI shift) %{
+  match(Set dst (LShiftVB src shift));
+  ins_cost(INSN_COST);
+  format %{ "shl    $dst, $src, $shift\t# vector (16B)" %}
+  ins_encode %{
+    int sh = (int)$shift$$constant & 31;
+    if (sh >= 8) {
+      __ eor(as_FloatRegister($dst$$reg), __ T16B,
+             as_FloatRegister($src$$reg),
+             as_FloatRegister($src$$reg));
+    } else {
+      __ shl(as_FloatRegister($dst$$reg), __ T16B,
+             as_FloatRegister($src$$reg), sh);
+    }
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vsra16B_imm(vecX dst, vecX src, immI shift) %{
+  match(Set dst (RShiftVB src shift));
+  ins_cost(INSN_COST);
+  format %{ "sshr    $dst, $src, $shift\t# vector (16B)" %}
+  ins_encode %{
+    int sh = (int)$shift$$constant & 31;
+    if (sh >= 8) sh = 7;
+    sh = -sh & 7;
+    __ sshr(as_FloatRegister($dst$$reg), __ T16B,
+           as_FloatRegister($src$$reg), sh);
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vsrl16B_imm(vecX dst, vecX src, immI shift) %{
+  match(Set dst (URShiftVB src shift));
+  ins_cost(INSN_COST);
+  format %{ "ushr    $dst, $src, $shift\t# vector (16B)" %}
+  ins_encode %{
+    int sh = (int)$shift$$constant & 31;
+    if (sh >= 8) {
+      __ eor(as_FloatRegister($dst$$reg), __ T16B,
+             as_FloatRegister($src$$reg),
+             as_FloatRegister($src$$reg));
+    } else {
+      __ ushr(as_FloatRegister($dst$$reg), __ T16B,
+             as_FloatRegister($src$$reg), -sh & 7);
+    }
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vsll8S(vecX dst, vecX src, vecX shift) %{
+  match(Set dst (LShiftVS src shift));
+  match(Set dst (RShiftVS src shift));
+  ins_cost(INSN_COST);
+  format %{ "sshl  $dst,$src,$shift\t# vector (8H)" %}
+  ins_encode %{
+    __ sshl(as_FloatRegister($dst$$reg), __ T8H,
+            as_FloatRegister($src$$reg),
+            as_FloatRegister($shift$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vsrl8S(vecX dst, vecX src, vecX shift) %{
+  match(Set dst (URShiftVS src shift));
+  ins_cost(INSN_COST);
+  format %{ "ushl  $dst,$src,$shift\t# vector (8H)" %}
+  ins_encode %{
+    __ ushl(as_FloatRegister($dst$$reg), __ T8H,
+            as_FloatRegister($src$$reg),
+            as_FloatRegister($shift$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vsll8S_imm(vecX dst, vecX src, immI shift) %{
+  match(Set dst (LShiftVS src shift));
+  ins_cost(INSN_COST);
+  format %{ "shl    $dst, $src, $shift\t# vector (8H)" %}
+  ins_encode %{
+    int sh = (int)$shift$$constant & 31;
+    if (sh >= 16) {
+      __ eor(as_FloatRegister($dst$$reg), __ T16B,
+             as_FloatRegister($src$$reg),
+             as_FloatRegister($src$$reg));
+    } else {
+      __ shl(as_FloatRegister($dst$$reg), __ T8H,
+             as_FloatRegister($src$$reg), sh);
+    }
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vsra8S_imm(vecX dst, vecX src, immI shift) %{
+  match(Set dst (RShiftVS src shift));
+  ins_cost(INSN_COST);
+  format %{ "sshr    $dst, $src, $shift\t# vector (8H)" %}
+  ins_encode %{
+    int sh = (int)$shift$$constant & 31;
+    if (sh >= 16) sh = 15;
+    sh = -sh & 15;
+    __ sshr(as_FloatRegister($dst$$reg), __ T8H,
+           as_FloatRegister($src$$reg), sh);
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vsrl8S_imm(vecX dst, vecX src, immI shift) %{
+  match(Set dst (URShiftVS src shift));
+  ins_cost(INSN_COST);
+  format %{ "ushr    $dst, $src, $shift\t# vector (8H)" %}
+  ins_encode %{
+    int sh = (int)$shift$$constant & 31;
+    if (sh >= 16) {
+      __ eor(as_FloatRegister($dst$$reg), __ T16B,
+             as_FloatRegister($src$$reg),
+             as_FloatRegister($src$$reg));
+    } else {
+      __ ushr(as_FloatRegister($dst$$reg), __ T8H,
+             as_FloatRegister($src$$reg), -sh & 15);
+    }
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vsll4I(vecX dst, vecX src, vecX shift) %{
+  match(Set dst (LShiftVI src shift));
+  match(Set dst (RShiftVI src shift));
+  ins_cost(INSN_COST);
+  format %{ "sshl  $dst,$src,$shift\t# vector (4S)" %}
+  ins_encode %{
+    __ sshl(as_FloatRegister($dst$$reg), __ T4S,
+            as_FloatRegister($src$$reg),
+            as_FloatRegister($shift$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vsrl4I(vecX dst, vecX src, vecX shift) %{
+  match(Set dst (URShiftVI src shift));
+  ins_cost(INSN_COST);
+  format %{ "ushl  $dst,$src,$shift\t# vector (4S)" %}
+  ins_encode %{
+    __ ushl(as_FloatRegister($dst$$reg), __ T4S,
+            as_FloatRegister($src$$reg),
+            as_FloatRegister($shift$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vsll4I_imm(vecX dst, vecX src, immI shift) %{
+  match(Set dst (LShiftVI src shift));
+  ins_cost(INSN_COST);
+  format %{ "shl    $dst, $src, $shift\t# vector (4S)" %}
+  ins_encode %{
+    __ shl(as_FloatRegister($dst$$reg), __ T4S,
+           as_FloatRegister($src$$reg),
+           (int)$shift$$constant & 31);
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vsra4I_imm(vecX dst, vecX src, immI shift) %{
+  match(Set dst (RShiftVI src shift));
+  ins_cost(INSN_COST);
+  format %{ "sshr    $dst, $src, $shift\t# vector (4S)" %}
+  ins_encode %{
+    __ sshr(as_FloatRegister($dst$$reg), __ T4S,
+            as_FloatRegister($src$$reg),
+            -(int)$shift$$constant & 31);
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vsrl4I_imm(vecX dst, vecX src, immI shift) %{
+  match(Set dst (URShiftVI src shift));
+  ins_cost(INSN_COST);
+  format %{ "ushr    $dst, $src, $shift\t# vector (4S)" %}
+  ins_encode %{
+    __ ushr(as_FloatRegister($dst$$reg), __ T4S,
+            as_FloatRegister($src$$reg),
+            -(int)$shift$$constant & 31);
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vsll2L(vecX dst, vecX src, vecX shift) %{
+  match(Set dst (LShiftVL src shift));
+  match(Set dst (RShiftVL src shift));
+  ins_cost(INSN_COST);
+  format %{ "sshl  $dst,$src,$shift\t# vector (2D)" %}
+  ins_encode %{
+    __ sshl(as_FloatRegister($dst$$reg), __ T2D,
+            as_FloatRegister($src$$reg),
+            as_FloatRegister($shift$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vsrl2L(vecX dst, vecX src, vecX shift) %{
+  match(Set dst (URShiftVL src shift));
+  ins_cost(INSN_COST);
+  format %{ "ushl  $dst,$src,$shift\t# vector (2D)" %}
+  ins_encode %{
+    __ ushl(as_FloatRegister($dst$$reg), __ T2D,
+            as_FloatRegister($src$$reg),
+            as_FloatRegister($shift$$reg));
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vsll2L_imm(vecX dst, vecX src, immI shift) %{
+  match(Set dst (LShiftVL src shift));
+  ins_cost(INSN_COST);
+  format %{ "shl    $dst, $src, $shift\t# vector (2D)" %}
+  ins_encode %{
+    __ shl(as_FloatRegister($dst$$reg), __ T2D,
+           as_FloatRegister($src$$reg),
+           (int)$shift$$constant & 63);
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vsra2L_imm(vecX dst, vecX src, immI shift) %{
+  match(Set dst (RShiftVL src shift));
+  ins_cost(INSN_COST);
+  format %{ "sshr    $dst, $src, $shift\t# vector (2D)" %}
+  ins_encode %{
+    __ sshr(as_FloatRegister($dst$$reg), __ T2D,
+            as_FloatRegister($src$$reg),
+            -(int)$shift$$constant & 63);
+  %}
+  ins_pipe(pipe_class_default);
+%}
+
+instruct vsrl2L_imm(vecX dst, vecX src, immI shift) %{
+  match(Set dst (URShiftVL src shift));
+  ins_cost(INSN_COST);
+  format %{ "ushr    $dst, $src, $shift\t# vector (2D)" %}
+  ins_encode %{
+    __ ushr(as_FloatRegister($dst$$reg), __ T2D,
+            as_FloatRegister($src$$reg),
+            -(int)$shift$$constant & 63);
+  %}
+  ins_pipe(pipe_class_default);
+%}
 
 //----------PEEPHOLE RULES-----------------------------------------------------
 // These must follow all instruction definitions as they use the names
--- a/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -466,6 +466,11 @@
     case base_plus_offset:
       {
         unsigned size = i->get(31, 30);
+        if (i->get(26, 26) && i->get(23, 23)) {
+          // SIMD Q Type - Size = 128 bits
+          assert(size == 0, "bad size");
+          size = 0b100;
+        }
         unsigned mask = (1 << size) - 1;
         if (_offset < 0 || _offset & mask)
           {
@@ -1888,9 +1893,18 @@
   };
 
   enum SIMD_RegVariant {
-       S32, D64, Q128
+       B, H, S, D, Q
   };
 
+#define INSN(NAME, op)                                            \
+  void NAME(FloatRegister Rt, SIMD_RegVariant T, const Address &adr) {   \
+    ld_st2((Register)Rt, adr, (int)T & 3, op + ((T==Q) ? 0b10:0b00), 1); \
+  }                                                                      \
+
+  INSN(ldr, 1);
+  INSN(str, 0);
+
+#undef INSN
 
  private:
 
@@ -1997,27 +2011,87 @@
     rf(Vm, 16), f(0b000111, 15, 10), rf(Vn, 5), rf(Vd, 0);                              \
   }
 
-  INSN(eor, 0b101110001);
-  INSN(orr, 0b001110101);
+  INSN(eor,  0b101110001);
+  INSN(orr,  0b001110101);
   INSN(andr, 0b001110001);
-  INSN(bic, 0b001110011);
-  INSN(bif, 0b101110111);
-  INSN(bit, 0b101110101);
-  INSN(bsl, 0b101110011);
-  INSN(orn, 0b001110111);
+  INSN(bic,  0b001110011);
+  INSN(bif,  0b101110111);
+  INSN(bit,  0b101110101);
+  INSN(bsl,  0b101110011);
+  INSN(orn,  0b001110111);
+
+#undef INSN
+
+#define INSN(NAME, opc, opc2)                                                                 \
+  void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \
+    starti;                                                                             \
+    f(0, 31), f((int)T & 1, 30), f(opc, 29), f(0b01110, 28, 24);                        \
+    f((int)T >> 1, 23, 22), f(1, 21), rf(Vm, 16), f(opc2, 15, 10);                      \
+    rf(Vn, 5), rf(Vd, 0);                                                               \
+  }
+
+  INSN(addv, 0, 0b100001);
+  INSN(subv, 1, 0b100001);
+  INSN(mulv, 0, 0b100111);
+  INSN(sshl, 0, 0b010001);
+  INSN(ushl, 1, 0b010001);
 
 #undef INSN
 
-#define INSN(NAME, opc)                                                                 \
-  void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \
+#define INSN(NAME, opc, opc2) \
+  void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn) {                   \
     starti;                                                                             \
     f(0, 31), f((int)T & 1, 30), f(opc, 29), f(0b01110, 28, 24);                        \
-    f((int)T >> 1, 23, 22), f(1, 21), rf(Vm, 16), f(0b100001, 15, 10);                  \
+    f((int)T >> 1, 23, 22), f(opc2, 21, 10);                                            \
     rf(Vn, 5), rf(Vd, 0);                                                               \
   }
 
-  INSN(addv, 0);
-  INSN(subv, 1);
+  INSN(absr,  0, 0b100000101110);
+  INSN(negr,  1, 0b100000101110);
+  INSN(notr,  1, 0b100000010110);
+  INSN(addv,  0, 0b110001101110);
+
+#undef INSN
+
+#define INSN(NAME, op0, cmode0) \
+  void NAME(FloatRegister Vd, SIMD_Arrangement T, unsigned imm8, unsigned lsl = 0) {   \
+    unsigned cmode = cmode0;                                                           \
+    unsigned op = op0;                                                                 \
+    starti;                                                                            \
+    assert(lsl == 0 ||                                                                 \
+           ((T == T4H || T == T8H) && lsl == 8) ||                                     \
+           ((T == T2S || T == T4S) && ((lsl >> 3) < 4)), "invalid shift");             \
+    cmode |= lsl >> 2;                                                                 \
+    if (T == T4H || T == T8H) cmode |= 0b1000;                                         \
+    if (!(T == T4H || T == T8H || T == T2S || T == T4S)) {                             \
+      assert(op == 0 && cmode0 == 0, "must be MOVI");                                  \
+      cmode = 0b1110;                                                                  \
+      if (T == T1D || T == T2D) op = 1;                                                \
+    }                                                                                  \
+    f(0, 31), f((int)T & 1, 30), f(op, 29), f(0b0111100000, 28, 19);                   \
+    f(imm8 >> 5, 18, 16), f(cmode, 15, 12), f(0x01, 11, 10), f(imm8 & 0b11111, 9, 5);  \
+    rf(Vd, 0);                                                                         \
+  }
+
+  INSN(movi, 0, 0);
+  INSN(orri, 0, 1);
+  INSN(mvni, 1, 0);
+  INSN(bici, 1, 1);
+
+#undef INSN
+
+#define INSN(NAME, op1, op2, op3) \
+  void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \
+    starti;                                                                             \
+    assert(T == T2S || T == T4S || T == T2D, "invalid arrangement");                    \
+    f(0, 31), f((int)T & 1, 30), f(op1, 29), f(0b01110, 28, 24), f(op2, 23);            \
+    f(T==T2D ? 1:0, 22); f(1, 21), rf(Vm, 16), f(op3, 15, 10), rf(Vn, 5), rf(Vd, 0);    \
+  }
+
+  INSN(fadd, 0, 0, 0b110101);
+  INSN(fdiv, 1, 0, 0b111111);
+  INSN(fmul, 1, 0, 0b110111);
+  INSN(fsub, 0, 1, 0b110101);
 
 #undef INSN
 
@@ -2064,19 +2138,40 @@
 
 #undef INSN
 
-  void shl(FloatRegister Vd, FloatRegister Vn, SIMD_Arrangement T, int shift){
+  void ins(FloatRegister Vd, SIMD_RegVariant T, FloatRegister Vn, int didx, int sidx) {
+    starti;
+    assert(T != Q, "invalid register variant");
+    f(0b01101110000, 31, 21), f(((didx<<1)|1)<<(int)T, 20, 16), f(0, 15);
+    f(sidx<<(int)T, 14, 11), f(1, 10), rf(Vn, 5), rf(Vd, 0);
+  }
+
+  void umov(Register Rd, FloatRegister Vn, SIMD_RegVariant T, int idx) {
     starti;
-    /* The encodings for the immh:immb fields (bits 22:16) are
-     *   0001 xxx       8B/16B, shift = xxx
-     *   001x xxx       4H/8H,  shift = xxxx
-     *   01xx xxx       2S/4S,  shift = xxxxx
-     *   1xxx xxx       1D/2D,  shift = xxxxxx (1D is RESERVED)
-     */
-    assert((1 << ((T>>1)+3)) > shift, "Invalid Shift value");
-    f(0, 31), f(T & 1, 30), f(0b0011110, 29, 23), f((1 << ((T>>1)+3))|shift, 22, 16);
-    f(0b010101, 15, 10), rf(Vn, 5), rf(Vd, 0);
+    f(0, 31), f(T==D ? 1:0, 30), f(0b001110000, 29, 21);
+    f(((idx<<1)|1)<<(int)T, 20, 16), f(0b001111, 15, 10);
+    rf(Vn, 5), rf(Rd, 0);
   }
 
+#define INSN(NAME, opc, opc2) \
+  void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, int shift){         \
+    starti;                                                                             \
+    /* The encodings for the immh:immb fields (bits 22:16) are                          \
+     *   0001 xxx       8B/16B, shift = xxx                                             \
+     *   001x xxx       4H/8H,  shift = xxxx                                            \
+     *   01xx xxx       2S/4S,  shift = xxxxx                                           \
+     *   1xxx xxx       1D/2D,  shift = xxxxxx (1D is RESERVED)                         \
+     */                                                                                 \
+    assert((1 << ((T>>1)+3)) > shift, "Invalid Shift value");                           \
+    f(0, 31), f(T & 1, 30), f(opc, 29), f(0b011110, 28, 23),                            \
+    f((1 << ((T>>1)+3))|shift, 22, 16); f(opc2, 15, 10), rf(Vn, 5), rf(Vd, 0);          \
+  }
+
+  INSN(shl,  0, 0b010101);
+  INSN(sshr, 0, 0b000001);
+  INSN(ushr, 1, 0b000001);
+
+#undef INSN
+
   void ushll(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb, int shift) {
     starti;
     /* The encodings for the immh:immb fields (bits 22:16) are
@@ -2149,6 +2244,23 @@
     rf(Vn, 5), rf(Vd, 0);
   }
 
+  void dup(FloatRegister Vd, SIMD_Arrangement T, Register Xs)
+  {
+    starti;
+    assert(T != T1D, "reserved encoding");
+    f(0,31), f((int)T & 1, 30), f(0b001110000, 29, 21);
+    f((1 << (T >> 1)), 20, 16), f(0b000011, 15, 10), rf(Xs, 5), rf(Vd, 0);
+  }
+
+  void dup(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, int index = 0)
+  {
+    starti;
+    assert(T != T1D, "reserved encoding");
+    f(0, 31), f((int)T & 1, 30), f(0b001110000, 29, 21);
+    f(((1 << (T >> 1)) | (index << ((T >> 1) + 1))), 20, 16);
+    f(0b000001, 15, 10), rf(Vn, 5), rf(Vd, 0);
+  }
+
   // CRC32 instructions
 #define INSN(NAME, sf, sz)                                                \
   void NAME(Register Rd, Register Rn, Register Rm) {                      \
--- a/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -64,7 +64,7 @@
 define_pd_global(intx, PreInflateSpin,           10);
 
 define_pd_global(bool, RewriteBytecodes,     true);
-define_pd_global(bool, RewriteFrequentPairs, false);
+define_pd_global(bool, RewriteFrequentPairs, true);
 
 define_pd_global(bool, UseMembar,            true);
 
--- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -2802,8 +2802,8 @@
       uzp2(v21, v20, v16, T2D);
       eor(v20, T16B, v17, v21);
 
-      shl(v16, v28, T2D, 1);
-      shl(v17, v20, T2D, 1);
+      shl(v16, T2D, v28, 1);
+      shl(v17, T2D, v20, 1);
 
       eor(v0, T16B, v0, v16);
       eor(v1, T16B, v1, v17);
--- a/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -37,6 +37,7 @@
   friend class LIR_Assembler;
 
   using Assembler::mov;
+  using Assembler::movi;
 
  protected:
 
@@ -464,6 +465,45 @@
 
   void movptr(Register r, uintptr_t imm64);
 
+  // Macro to mov replicated immediate to vector register.
+  // Where imm32 == hex abcdefgh, Vd will get the following values
+  // for different arrangements in T
+  //   T8B:  Vd = ghghghghghghghgh
+  //   T16B: Vd = ghghghghghghghghghghghghghghghgh
+  //   T4H:  Vd = efghefghefghefgh
+  //   T8H:  Vd = efghefghefghefghefghefghefghefgh
+  //   T2S:  Vd = abcdefghabcdefgh
+  //   T4S:  Vd = abcdefghabcdefghabcdefghabcdefgh
+  //   T1D/T2D: invalid
+  void mov(FloatRegister Vd, SIMD_Arrangement T, u_int32_t imm32) {
+    assert(T != T1D && T != T2D, "invalid arrangement");
+    u_int32_t nimm32 = ~imm32;
+    if (T == T8B || T == T16B) { imm32 &= 0xff; nimm32 &= 0xff; }
+    if (T == T4H || T == T8H) { imm32 &= 0xffff; nimm32 &= 0xffff; }
+    u_int32_t x = imm32;
+    int movi_cnt = 0;
+    int movn_cnt = 0;
+    while (x) { if (x & 0xff) movi_cnt++; x >>= 8; }
+    x = nimm32;
+    while (x) { if (x & 0xff) movn_cnt++; x >>= 8; }
+    if (movn_cnt < movi_cnt) imm32 = nimm32;
+    unsigned lsl = 0;
+    while (imm32 && (imm32 & 0xff) == 0) { lsl += 8; imm32 >>= 8; }
+    if (movn_cnt < movi_cnt)
+      mvni(Vd, T, imm32 & 0xff, lsl);
+    else
+      movi(Vd, T, imm32 & 0xff, lsl);
+    imm32 >>= 8; lsl += 8;
+    while (imm32) {
+      while ((imm32 & 0xff) == 0) { lsl += 8; imm32 >>= 8; }
+      if (movn_cnt < movi_cnt)
+        bici(Vd, T, imm32 & 0xff, lsl);
+      else
+        orri(Vd, T, imm32 & 0xff, lsl);
+      lsl += 8; imm32 >>= 8;
+    }
+  }
+
   // macro instructions for accessing and updating floating point
   // status register
   //
--- a/hotspot/src/cpu/aarch64/vm/register_aarch64.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/cpu/aarch64/vm/register_aarch64.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -186,7 +186,7 @@
   // it's optoregs.
 
     number_of_registers = (2 * RegisterImpl::number_of_registers +
-                           2 * FloatRegisterImpl::number_of_registers +
+                           4 * FloatRegisterImpl::number_of_registers +
                            1) // flags
   };
 
--- a/hotspot/src/cpu/aarch64/vm/templateTable_aarch64.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/cpu/aarch64/vm/templateTable_aarch64.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -513,23 +513,61 @@
 void TemplateTable::iload_internal(RewriteControl rc) {
   transition(vtos, itos);
   if (RewriteFrequentPairs && rc == may_rewrite) {
-    // TODO : check x86 code for what to do here
-    __ call_Unimplemented();
-  } else {
-    locals_index(r1);
-    __ ldr(r0, iaddress(r1));
+    Label rewrite, done;
+    Register bc = r4;
+
+    // get next bytecode
+    __ load_unsigned_byte(r1, at_bcp(Bytecodes::length_for(Bytecodes::_iload)));
+
+    // if _iload, wait to rewrite to iload2.  We only want to rewrite the
+    // last two iloads in a pair.  Comparing against fast_iload means that
+    // the next bytecode is neither an iload or a caload, and therefore
+    // an iload pair.
+    __ cmpw(r1, Bytecodes::_iload);
+    __ br(Assembler::EQ, done);
+
+    // if _fast_iload rewrite to _fast_iload2
+    __ cmpw(r1, Bytecodes::_fast_iload);
+    __ movw(bc, Bytecodes::_fast_iload2);
+    __ br(Assembler::EQ, rewrite);
+
+    // if _caload rewrite to _fast_icaload
+    __ cmpw(r1, Bytecodes::_caload);
+    __ movw(bc, Bytecodes::_fast_icaload);
+    __ br(Assembler::EQ, rewrite);
+
+    // else rewrite to _fast_iload
+    __ movw(bc, Bytecodes::_fast_iload);
+
+    // rewrite
+    // bc: new bytecode
+    __ bind(rewrite);
+    patch_bytecode(Bytecodes::_iload, bc, r1, false);
+    __ bind(done);
+
   }
 
+  // do iload, get the local value into tos
+  locals_index(r1);
+  __ ldr(r0, iaddress(r1));
+
 }
 
 void TemplateTable::fast_iload2()
 {
-  __ call_Unimplemented();
+  transition(vtos, itos);
+  locals_index(r1);
+  __ ldr(r0, iaddress(r1));
+  __ push(itos);
+  locals_index(r1, 3);
+  __ ldr(r0, iaddress(r1));
 }
 
 void TemplateTable::fast_iload()
 {
-  __ call_Unimplemented();
+  transition(vtos, itos);
+  locals_index(r1);
+  __ ldr(r0, iaddress(r1));
 }
 
 void TemplateTable::lload()
@@ -721,7 +759,18 @@
 // iload followed by caload frequent pair
 void TemplateTable::fast_icaload()
 {
-  __ call_Unimplemented();
+  transition(vtos, itos);
+  // load index out of locals
+  locals_index(r2);
+  __ ldr(r1, iaddress(r2));
+
+  __ pop_ptr(r0);
+
+  // r0: array
+  // r1: index
+  index_check(r0, r1); // leaves index in r1, kills rscratch1
+  __ lea(r1,  Address(r0, r1, Address::uxtw(1)));
+  __ load_unsigned_short(r0, Address(r1,  arrayOopDesc::base_offset_in_bytes(T_CHAR)));
 }
 
 void TemplateTable::saload()
@@ -797,7 +846,47 @@
   // These bytecodes with a small amount of code are most profitable
   // to rewrite
   if (RewriteFrequentPairs && rc == may_rewrite) {
-    __ call_Unimplemented();
+    Label rewrite, done;
+    const Register bc = r4;
+
+    // get next bytecode
+    __ load_unsigned_byte(r1, at_bcp(Bytecodes::length_for(Bytecodes::_aload_0)));
+
+    // do actual aload_0
+    aload(0);
+
+    // if _getfield then wait with rewrite
+    __ cmpw(r1, Bytecodes::Bytecodes::_getfield);
+    __ br(Assembler::EQ, done);
+
+    // if _igetfield then reqrite to _fast_iaccess_0
+    assert(Bytecodes::java_code(Bytecodes::_fast_iaccess_0) == Bytecodes::_aload_0, "fix bytecode definition");
+    __ cmpw(r1, Bytecodes::_fast_igetfield);
+    __ movw(bc, Bytecodes::_fast_iaccess_0);
+    __ br(Assembler::EQ, rewrite);
+
+    // if _agetfield then reqrite to _fast_aaccess_0
+    assert(Bytecodes::java_code(Bytecodes::_fast_aaccess_0) == Bytecodes::_aload_0, "fix bytecode definition");
+    __ cmpw(r1, Bytecodes::_fast_agetfield);
+    __ movw(bc, Bytecodes::_fast_aaccess_0);
+    __ br(Assembler::EQ, rewrite);
+
+    // if _fgetfield then reqrite to _fast_faccess_0
+    assert(Bytecodes::java_code(Bytecodes::_fast_faccess_0) == Bytecodes::_aload_0, "fix bytecode definition");
+    __ cmpw(r1, Bytecodes::_fast_fgetfield);
+    __ movw(bc, Bytecodes::_fast_faccess_0);
+    __ br(Assembler::EQ, rewrite);
+
+    // else rewrite to _fast_aload0
+    assert(Bytecodes::java_code(Bytecodes::_fast_aload_0) == Bytecodes::_aload_0, "fix bytecode definition");
+    __ movw(bc, Bytecodes::Bytecodes::_fast_aload_0);
+
+    // rewrite
+    // bc: new bytecode
+    __ bind(rewrite);
+    patch_bytecode(Bytecodes::_aload_0, bc, r1, false);
+
+    __ bind(done);
   } else {
     aload(0);
   }
--- a/hotspot/src/os/windows/vm/os_windows.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/os/windows/vm/os_windows.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -3768,7 +3768,7 @@
   return NULL;
 }
 
-#define EXIT_TIMEOUT     PRODUCT_ONLY(1000) NOT_PRODUCT(4000) /* 1 sec in product, 4 sec in debug */
+#define EXIT_TIMEOUT 300000 /* 5 minutes */
 
 static BOOL CALLBACK init_crit_sect_call(PINIT_ONCE, PVOID pcrit_sect, PVOID*) {
   InitializeCriticalSection((CRITICAL_SECTION*)pcrit_sect);
--- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -1469,7 +1469,9 @@
   } else {
     guarantee(in_bytes(PtrQueue::byte_width_of_active()) == 1,
               "Assumption");
-    flag_type = T_BYTE;
+    // Use unsigned type T_BOOLEAN here rather than signed T_BYTE since some platforms, eg. ARM,
+    // need to use unsigned instructions to use the large offset to load the satb_mark_queue.
+    flag_type = T_BOOLEAN;
   }
   LIR_Opr thrd = getThreadPointer();
   LIR_Address* mark_active_flag_addr =
--- a/hotspot/src/share/vm/gc/cms/cmsOopClosures.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/cms/cmsOopClosures.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -26,6 +26,7 @@
 #define SHARE_VM_GC_CMS_CMSOOPCLOSURES_HPP
 
 #include "gc/shared/genOopClosures.hpp"
+#include "gc/shared/taskqueue.hpp"
 #include "memory/iterator.hpp"
 
 /////////////////////////////////////////////////////////////////
--- a/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -641,6 +641,7 @@
 class FreeListSpace_DCTOC : public Filtering_DCTOC {
   CompactibleFreeListSpace* _cfls;
   CMSCollector* _collector;
+  bool _parallel;
 protected:
   // Override.
 #define walk_mem_region_with_cl_DECL(ClosureType)                       \
@@ -661,9 +662,10 @@
                       CMSCollector* collector,
                       ExtendedOopClosure* cl,
                       CardTableModRefBS::PrecisionStyle precision,
-                      HeapWord* boundary) :
+                      HeapWord* boundary,
+                      bool parallel) :
     Filtering_DCTOC(sp, cl, precision, boundary),
-    _cfls(sp), _collector(collector) {}
+    _cfls(sp), _collector(collector), _parallel(parallel) {}
 };
 
 // We de-virtualize the block-related calls below, since we know that our
@@ -674,10 +676,7 @@
                                                  HeapWord* bottom,              \
                                                  HeapWord* top,                 \
                                                  ClosureType* cl) {             \
-   bool is_par = GenCollectedHeap::heap()->n_par_threads() > 0;                 \
-   if (is_par) {                                                                \
-     assert(GenCollectedHeap::heap()->n_par_threads() ==                        \
-            GenCollectedHeap::heap()->workers()->active_workers(), "Mismatch"); \
+   if (_parallel) {                                                             \
      walk_mem_region_with_cl_par(mr, bottom, top, cl);                          \
    } else {                                                                     \
      walk_mem_region_with_cl_nopar(mr, bottom, top, cl);                        \
@@ -747,8 +746,9 @@
 DirtyCardToOopClosure*
 CompactibleFreeListSpace::new_dcto_cl(ExtendedOopClosure* cl,
                                       CardTableModRefBS::PrecisionStyle precision,
-                                      HeapWord* boundary) {
-  return new FreeListSpace_DCTOC(this, _collector, cl, precision, boundary);
+                                      HeapWord* boundary,
+                                      bool parallel) {
+  return new FreeListSpace_DCTOC(this, _collector, cl, precision, boundary, parallel);
 }
 
 
@@ -1897,11 +1897,9 @@
   assert(chunk->is_free() && ffc->is_free(), "Error");
   _bt.split_block((HeapWord*)chunk, chunk->size(), new_size);
   if (rem_sz < SmallForDictionary) {
-    bool is_par = (GenCollectedHeap::heap()->n_par_threads() > 0);
+    // The freeList lock is held, but multiple GC task threads might be executing in parallel.
+    bool is_par = Thread::current()->is_GC_task_thread();
     if (is_par) _indexedFreeListParLocks[rem_sz]->lock();
-    assert(!is_par ||
-           (GenCollectedHeap::heap()->n_par_threads() ==
-            GenCollectedHeap::heap()->workers()->active_workers()), "Mismatch");
     returnChunkToFreeList(ffc);
     split(size, rem_sz);
     if (is_par) _indexedFreeListParLocks[rem_sz]->unlock();
@@ -1972,8 +1970,6 @@
 
 bool CompactibleFreeListSpace::no_allocs_since_save_marks() {
   assert(_promoInfo.tracking(), "No preceding save_marks?");
-  assert(GenCollectedHeap::heap()->n_par_threads() == 0,
-         "Shouldn't be called if using parallel gc.");
   return _promoInfo.noPromotions();
 }
 
@@ -1981,8 +1977,6 @@
                                                                             \
 void CompactibleFreeListSpace::                                             \
 oop_since_save_marks_iterate##nv_suffix(OopClosureType* blk) {              \
-  assert(GenCollectedHeap::heap()->n_par_threads() == 0,                    \
-         "Shouldn't be called (yet) during parallel part of gc.");          \
   _promoInfo.promoted_oops_iterate##nv_suffix(blk);                         \
   /*                                                                        \
    * This also restores any displaced headers and removes the elements from \
--- a/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -438,7 +438,8 @@
   // Override: provides a DCTO_CL specific to this kind of space.
   DirtyCardToOopClosure* new_dcto_cl(ExtendedOopClosure* cl,
                                      CardTableModRefBS::PrecisionStyle precision,
-                                     HeapWord* boundary);
+                                     HeapWord* boundary,
+                                     bool parallel);
 
   void blk_iterate(BlkClosure* cl);
   void blk_iterate_careful(BlkClosureCareful* cl);
--- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -2428,14 +2428,18 @@
   MarkRefsIntoClosure notOlder(_span, verification_mark_bm());
   gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel.
 
-  gch->gen_process_roots(_cmsGen->level(),
-                         true,   // younger gens are roots
-                         true,   // activate StrongRootsScope
-                         GenCollectedHeap::ScanningOption(roots_scanning_options()),
-                         should_unload_classes(),
-                         &notOlder,
-                         NULL,
-                         NULL);  // SSS: Provide correct closure
+  {
+    StrongRootsScope srs(1);
+
+    gch->gen_process_roots(&srs,
+                           _cmsGen->level(),
+                           true,   // younger gens are roots
+                           GenCollectedHeap::ScanningOption(roots_scanning_options()),
+                           should_unload_classes(),
+                           &notOlder,
+                           NULL,
+                           NULL);
+  }
 
   // Now mark from the roots
   MarkFromRootsClosure markFromRootsClosure(this, _span,
@@ -2496,14 +2500,18 @@
 
   gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel.
 
-  gch->gen_process_roots(_cmsGen->level(),
-                         true,   // younger gens are roots
-                         true,   // activate StrongRootsScope
-                         GenCollectedHeap::ScanningOption(roots_scanning_options()),
-                         should_unload_classes(),
-                         &notOlder,
-                         NULL,
-                         &cld_closure);
+  {
+    StrongRootsScope srs(1);
+
+    gch->gen_process_roots(&srs,
+                           _cmsGen->level(),
+                           true,   // younger gens are roots
+                           GenCollectedHeap::ScanningOption(roots_scanning_options()),
+                           should_unload_classes(),
+                           &notOlder,
+                           NULL,
+                           &cld_closure);
+  }
 
   // Now mark from the roots
   MarkFromRootsVerifyClosure markFromRootsClosure(this, _span,
@@ -2913,10 +2921,11 @@
 
 // Parallel initial mark task
 class CMSParInitialMarkTask: public CMSParMarkTask {
+  StrongRootsScope* _strong_roots_scope;
  public:
-  CMSParInitialMarkTask(CMSCollector* collector, uint n_workers) :
-      CMSParMarkTask("Scan roots and young gen for initial mark in parallel",
-                     collector, n_workers) {}
+  CMSParInitialMarkTask(CMSCollector* collector, StrongRootsScope* strong_roots_scope, uint n_workers) :
+      CMSParMarkTask("Scan roots and young gen for initial mark in parallel", collector, n_workers),
+      _strong_roots_scope(strong_roots_scope) {}
   void work(uint worker_id);
 };
 
@@ -3004,24 +3013,26 @@
       FlexibleWorkGang* workers = gch->workers();
       assert(workers != NULL, "Need parallel worker threads.");
       uint n_workers = workers->active_workers();
-      CMSParInitialMarkTask tsk(this, n_workers);
-      gch->set_par_threads(n_workers);
+
+      StrongRootsScope srs(n_workers);
+
+      CMSParInitialMarkTask tsk(this, &srs, n_workers);
       initialize_sequential_subtasks_for_young_gen_rescan(n_workers);
       if (n_workers > 1) {
-        StrongRootsScope srs;
         workers->run_task(&tsk);
       } else {
-        StrongRootsScope srs;
         tsk.work(0);
       }
-      gch->set_par_threads(0);
     } else {
       // The serial version.
       CLDToOopClosure cld_closure(&notOlder, true);
       gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel.
-      gch->gen_process_roots(_cmsGen->level(),
+
+      StrongRootsScope srs(1);
+
+      gch->gen_process_roots(&srs,
+                             _cmsGen->level(),
                              true,   // younger gens are roots
-                             true,   // activate StrongRootsScope
                              GenCollectedHeap::ScanningOption(roots_scanning_options()),
                              should_unload_classes(),
                              &notOlder,
@@ -4452,9 +4463,9 @@
 
   CLDToOopClosure cld_closure(&par_mri_cl, true);
 
-  gch->gen_process_roots(_collector->_cmsGen->level(),
+  gch->gen_process_roots(_strong_roots_scope,
+                         _collector->_cmsGen->level(),
                          false,     // yg was scanned above
-                         false,     // this is parallel code
                          GenCollectedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()),
                          _collector->should_unload_classes(),
                          &par_mri_cl,
@@ -4478,6 +4489,7 @@
   // The per-thread work queues, available here for stealing.
   OopTaskQueueSet*       _task_queues;
   ParallelTaskTerminator _term;
+  StrongRootsScope*      _strong_roots_scope;
 
  public:
   // A value of 0 passed to n_workers will cause the number of
@@ -4485,12 +4497,14 @@
   CMSParRemarkTask(CMSCollector* collector,
                    CompactibleFreeListSpace* cms_space,
                    uint n_workers, FlexibleWorkGang* workers,
-                   OopTaskQueueSet* task_queues):
+                   OopTaskQueueSet* task_queues,
+                   StrongRootsScope* strong_roots_scope):
     CMSParMarkTask("Rescan roots and grey objects in parallel",
                    collector, n_workers),
     _cms_space(cms_space),
     _task_queues(task_queues),
-    _term(n_workers, task_queues) { }
+    _term(n_workers, task_queues),
+    _strong_roots_scope(strong_roots_scope) { }
 
   OopTaskQueueSet* task_queues() { return _task_queues; }
 
@@ -4588,9 +4602,9 @@
   // ---------- remaining roots --------------
   _timer.reset();
   _timer.start();
-  gch->gen_process_roots(_collector->_cmsGen->level(),
+  gch->gen_process_roots(_strong_roots_scope,
+                         _collector->_cmsGen->level(),
                          false,     // yg was scanned above
-                         false,     // this is parallel code
                          GenCollectedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()),
                          _collector->should_unload_classes(),
                          &par_mrias_cl,
@@ -5058,22 +5072,15 @@
   FlexibleWorkGang* workers = gch->workers();
   assert(workers != NULL, "Need parallel worker threads.");
   // Choose to use the number of GC workers most recently set
-  // into "active_workers".  If active_workers is not set, set it
-  // to ParallelGCThreads.
+  // into "active_workers".
   uint n_workers = workers->active_workers();
-  if (n_workers == 0) {
-    assert(n_workers > 0, "Should have been set during scavenge");
-    n_workers = ParallelGCThreads;
-    workers->set_active_workers(n_workers);
-  }
+
   CompactibleFreeListSpace* cms_space  = _cmsGen->cmsSpace();
 
-  CMSParRemarkTask tsk(this,
-    cms_space,
-    n_workers, workers, task_queues());
-
-  // Set up for parallel process_roots work.
-  gch->set_par_threads(n_workers);
+  StrongRootsScope srs(n_workers);
+
+  CMSParRemarkTask tsk(this, cms_space, n_workers, workers, task_queues(), &srs);
+
   // We won't be iterating over the cards in the card table updating
   // the younger_gen cards, so we shouldn't call the following else
   // the verification code as well as subsequent younger_refs_iterate
@@ -5105,15 +5112,12 @@
     // necessarily be so, since it's possible that we are doing
     // ST marking.
     ReferenceProcessorMTDiscoveryMutator mt(ref_processor(), true);
-    StrongRootsScope srs;
     workers->run_task(&tsk);
   } else {
     ReferenceProcessorMTDiscoveryMutator mt(ref_processor(), false);
-    StrongRootsScope srs;
     tsk.work(0);
   }
 
-  gch->set_par_threads(0);  // 0 ==> non-parallel.
   // restore, single-threaded for now, any preserved marks
   // as a result of work_q overflow
   restore_preserved_marks_if_any();
@@ -5177,11 +5181,11 @@
     verify_work_stacks_empty();
 
     gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel.
-    StrongRootsScope srs;
-
-    gch->gen_process_roots(_cmsGen->level(),
+    StrongRootsScope srs(1);
+
+    gch->gen_process_roots(&srs,
+                           _cmsGen->level(),
                            true,  // younger gens as roots
-                           false, // use the local StrongRootsScope
                            GenCollectedHeap::ScanningOption(roots_scanning_options()),
                            should_unload_classes(),
                            &mrias_cl,
@@ -5254,18 +5258,14 @@
                       CMSBitMap*       mark_bit_map,
                       AbstractWorkGang* workers,
                       OopTaskQueueSet* task_queues):
-    // XXX Should superclass AGTWOQ also know about AWG since it knows
-    // about the task_queues used by the AWG? Then it could initialize
-    // the terminator() object. See 6984287. The set_for_termination()
-    // below is a temporary band-aid for the regression in 6984287.
     AbstractGangTaskWOopQueues("Process referents by policy in parallel",
-      task_queues),
+      task_queues,
+      workers->active_workers()),
     _task(task),
     _collector(collector), _span(span), _mark_bit_map(mark_bit_map)
   {
     assert(_collector->_span.equals(_span) && !_span.is_empty(),
            "Inconsistency in _span");
-    set_for_termination(workers->active_workers());
   }
 
   OopTaskQueueSet* task_queues() { return queues(); }
--- a/hotspot/src/share/vm/gc/cms/parCardTableModRefBS.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/cms/parCardTableModRefBS.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -39,16 +39,11 @@
 void CardTableModRefBS::non_clean_card_iterate_parallel_work(Space* sp, MemRegion mr,
                                                              OopsInGenClosure* cl,
                                                              CardTableRS* ct,
-                                                             int n_threads) {
-  assert(n_threads > 0, "Error: expected n_threads > 0");
-  assert((n_threads == 1 && ParallelGCThreads == 0) ||
-         n_threads <= (int)ParallelGCThreads,
-         "# worker threads != # requested!");
-  assert(!Thread::current()->is_VM_thread() || (n_threads == 1), "There is only 1 VM thread");
-  assert(UseDynamicNumberOfGCThreads ||
-         !FLAG_IS_DEFAULT(ParallelGCThreads) ||
-         n_threads == (int)ParallelGCThreads,
-         "# worker threads != # requested!");
+                                                             uint n_threads) {
+  assert(n_threads > 0, "expected n_threads > 0");
+  assert(n_threads <= ParallelGCThreads,
+         err_msg("n_threads: %u > ParallelGCThreads: " UINTX_FORMAT, n_threads, ParallelGCThreads));
+
   // Make sure the LNC array is valid for the space.
   jbyte**   lowest_non_clean;
   uintptr_t lowest_non_clean_base_chunk_index;
@@ -66,7 +61,8 @@
 
   uint stride = 0;
   while (!pst->is_task_claimed(/* reference */ stride)) {
-    process_stride(sp, mr, stride, n_strides, cl, ct,
+    process_stride(sp, mr, stride, n_strides,
+                   cl, ct,
                    lowest_non_clean,
                    lowest_non_clean_base_chunk_index,
                    lowest_non_clean_chunk_size);
@@ -132,9 +128,13 @@
     assert(chunk_mr.word_size() > 0, "[chunk_card_start > used_end)");
     assert(used.contains(chunk_mr), "chunk_mr should be subset of used");
 
+    // This function is used by the parallel card table iteration.
+    const bool parallel = true;
+
     DirtyCardToOopClosure* dcto_cl = sp->new_dcto_cl(cl, precision(),
-                                                     cl->gen_boundary());
-    ClearNoncleanCardWrapper clear_cl(dcto_cl, ct);
+                                                     cl->gen_boundary(),
+                                                     parallel);
+    ClearNoncleanCardWrapper clear_cl(dcto_cl, ct, parallel);
 
 
     // Process the chunk.
--- a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -567,23 +567,15 @@
 }
 
 ParNewGenTask::ParNewGenTask(ParNewGeneration* gen, Generation* old_gen,
-                             HeapWord* young_old_boundary, ParScanThreadStateSet* state_set) :
+                             HeapWord* young_old_boundary, ParScanThreadStateSet* state_set,
+                             StrongRootsScope* strong_roots_scope) :
     AbstractGangTask("ParNewGeneration collection"),
     _gen(gen), _old_gen(old_gen),
     _young_old_boundary(young_old_boundary),
-    _state_set(state_set)
+    _state_set(state_set),
+    _strong_roots_scope(strong_roots_scope)
   {}
 
-// Reset the terminator for the given number of
-// active threads.
-void ParNewGenTask::set_for_termination(uint active_workers) {
-  _state_set->reset(active_workers, _gen->promotion_failed());
-  // Should the heap be passed in?  There's only 1 for now so
-  // grab it instead.
-  GenCollectedHeap* gch = GenCollectedHeap::heap();
-  gch->set_n_termination(active_workers);
-}
-
 void ParNewGenTask::work(uint worker_id) {
   GenCollectedHeap* gch = GenCollectedHeap::heap();
   // Since this is being done in a separate thread, need new resource
@@ -603,10 +595,10 @@
                                            false);
 
   par_scan_state.start_strong_roots();
-  gch->gen_process_roots(_gen->level(),
+  gch->gen_process_roots(_strong_roots_scope,
+                         _gen->level(),
                          true,  // Process younger gens, if any,
                                 // as strong roots.
-                         false, // no scope; this is parallel code
                          GenCollectedHeap::SO_ScavengeCodeCache,
                          GenCollectedHeap::StrongAndWeakRoots,
                          &par_scan_state.to_space_root_closure(),
@@ -759,9 +751,6 @@
 
 private:
   virtual void work(uint worker_id);
-  virtual void set_for_termination(uint active_workers) {
-    _state_set.terminator()->reset_for_reuse(active_workers);
-  }
 private:
   ParNewGeneration&      _gen;
   ProcessTask&           _task;
@@ -838,7 +827,6 @@
 {
   _state_set.flush();
   GenCollectedHeap* gch = GenCollectedHeap::heap();
-  gch->set_par_threads(0);  // 0 ==> non-parallel.
   gch->save_marks();
 }
 
@@ -939,33 +927,35 @@
   to()->clear(SpaceDecorator::Mangle);
 
   gch->save_marks();
-  assert(workers != NULL, "Need parallel worker threads.");
-  uint n_workers = active_workers;
 
   // Set the correct parallelism (number of queues) in the reference processor
-  ref_processor()->set_active_mt_degree(n_workers);
+  ref_processor()->set_active_mt_degree(active_workers);
 
   // Always set the terminator for the active number of workers
   // because only those workers go through the termination protocol.
-  ParallelTaskTerminator _term(n_workers, task_queues());
-  ParScanThreadStateSet thread_state_set(workers->active_workers(),
+  ParallelTaskTerminator _term(active_workers, task_queues());
+  ParScanThreadStateSet thread_state_set(active_workers,
                                          *to(), *this, *_old_gen, *task_queues(),
                                          _overflow_stacks, desired_plab_sz(), _term);
 
-  ParNewGenTask tsk(this, _old_gen, reserved().end(), &thread_state_set);
-  gch->set_par_threads(n_workers);
-  gch->rem_set()->prepare_for_younger_refs_iterate(true);
-  // It turns out that even when we're using 1 thread, doing the work in a
-  // separate thread causes wide variance in run times.  We can't help this
-  // in the multi-threaded case, but we special-case n=1 here to get
-  // repeatable measurements of the 1-thread overhead of the parallel code.
-  if (n_workers > 1) {
-    StrongRootsScope srs;
-    workers->run_task(&tsk);
-  } else {
-    StrongRootsScope srs;
-    tsk.work(0);
+  thread_state_set.reset(active_workers, promotion_failed());
+
+  {
+    StrongRootsScope srs(active_workers);
+
+    ParNewGenTask tsk(this, _old_gen, reserved().end(), &thread_state_set, &srs);
+    gch->rem_set()->prepare_for_younger_refs_iterate(true);
+    // It turns out that even when we're using 1 thread, doing the work in a
+    // separate thread causes wide variance in run times.  We can't help this
+    // in the multi-threaded case, but we special-case n=1 here to get
+    // repeatable measurements of the 1-thread overhead of the parallel code.
+    if (active_workers > 1) {
+      workers->run_task(&tsk);
+    } else {
+      tsk.work(0);
+    }
   }
+
   thread_state_set.reset(0 /* Bad value in debug if not reset */,
                          promotion_failed());
 
@@ -995,7 +985,6 @@
                                               _gc_timer, _gc_tracer.gc_id());
   } else {
     thread_state_set.flush();
-    gch->set_par_threads(0);  // 0 ==> non-parallel.
     gch->save_marks();
     stats = rp->process_discovered_references(&is_alive, &keep_alive,
                                               &evacuate_followers, NULL,
@@ -1033,7 +1022,7 @@
   to()->set_concurrent_iteration_safe_limit(to()->top());
 
   if (ResizePLAB) {
-    plab_stats()->adjust_desired_plab_sz(n_workers);
+    plab_stats()->adjust_desired_plab_sz(active_workers);
   }
 
   if (PrintGC && !PrintGCDetails) {
@@ -1477,9 +1466,9 @@
     _ref_processor =
       new ReferenceProcessor(_reserved,                  // span
                              ParallelRefProcEnabled && (ParallelGCThreads > 1), // mt processing
-                             (int) ParallelGCThreads,    // mt processing degree
+                             (uint) ParallelGCThreads,   // mt processing degree
                              refs_discovery_is_mt(),     // mt discovery
-                             (int) ParallelGCThreads,    // mt discovery degree
+                             (uint) ParallelGCThreads,   // mt discovery degree
                              refs_discovery_is_atomic(), // atomic_discovery
                              NULL);                      // is_alive_non_header
   }
--- a/hotspot/src/share/vm/gc/cms/parNewGeneration.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -39,6 +39,7 @@
 class ParRootScanWithoutBarrierClosure;
 class ParRootScanWithBarrierTwoGensClosure;
 class ParEvacuateFollowersClosure;
+class StrongRootsScope;
 
 // It would be better if these types could be kept local to the .cpp file,
 // but they must be here to allow ParScanClosure::do_oop_work to be defined
@@ -237,20 +238,18 @@
   Generation*                  _old_gen;
   HeapWord*                    _young_old_boundary;
   class ParScanThreadStateSet* _state_set;
+  StrongRootsScope*            _strong_roots_scope;
 
 public:
   ParNewGenTask(ParNewGeneration*      gen,
                 Generation*            old_gen,
                 HeapWord*              young_old_boundary,
-                ParScanThreadStateSet* state_set);
+                ParScanThreadStateSet* state_set,
+                StrongRootsScope*      strong_roots_scope);
 
   HeapWord* young_old_boundary() { return _young_old_boundary; }
 
   void work(uint worker_id);
-
-  // Reset the terminator in ParScanThreadStateSet for
-  // "active_workers" threads.
-  virtual void set_for_termination(uint active_workers);
 };
 
 class KeepAliveClosure: public DefNewGeneration::KeepAliveClosure {
--- a/hotspot/src/share/vm/gc/cms/parOopClosures.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/cms/parOopClosures.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -26,6 +26,7 @@
 #define SHARE_VM_GC_CMS_PAROOPCLOSURES_HPP
 
 #include "gc/shared/genOopClosures.hpp"
+#include "gc/shared/taskqueue.hpp"
 #include "memory/padded.hpp"
 
 // Closures for ParNewGeneration
--- a/hotspot/src/share/vm/gc/cms/yieldingWorkgroup.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/cms/yieldingWorkgroup.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -147,6 +147,13 @@
   bool completed() const { return _status == COMPLETED; }
   bool aborted()   const { return _status == ABORTED; }
   bool active()    const { return _status == ACTIVE; }
+
+  // This method configures the task for proper termination.
+  // Some tasks do not have any requirements on termination
+  // and may inherit this method that does nothing.  Some
+  // tasks do some coordination on termination and override
+  // this method to implement that coordination.
+  virtual void set_for_termination(uint active_workers) {}
 };
 // Class YieldingWorkGang: A subclass of WorkGang.
 // In particular, a YieldingWorkGang is made up of
--- a/hotspot/src/share/vm/gc/g1/collectionSetChooser.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/g1/collectionSetChooser.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -158,20 +158,10 @@
   hr->calc_gc_efficiency();
 }
 
-void CollectionSetChooser::prepare_for_par_region_addition(uint n_regions,
+void CollectionSetChooser::prepare_for_par_region_addition(uint n_threads,
+                                                           uint n_regions,
                                                            uint chunk_size) {
   _first_par_unreserved_idx = 0;
-  uint n_threads = (uint) ParallelGCThreads;
-  if (UseDynamicNumberOfGCThreads) {
-    assert(G1CollectedHeap::heap()->workers()->active_workers() > 0,
-      "Should have been set earlier");
-    // This is defensive code. As the assertion above says, the number
-    // of active threads should be > 0, but in case there is some path
-    // or some improperly initialized variable with leads to no
-    // active threads, protect against that in a product build.
-    n_threads = MAX2(G1CollectedHeap::heap()->workers()->active_workers(),
-                     1U);
-  }
   uint max_waste = n_threads * chunk_size;
   // it should be aligned with respect to chunk_size
   uint aligned_n_regions = (n_regions + chunk_size - 1) / chunk_size * chunk_size;
--- a/hotspot/src/share/vm/gc/g1/collectionSetChooser.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/g1/collectionSetChooser.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -121,7 +121,7 @@
 
   // Must be called before calls to claim_array_chunk().
   // n_regions is the number of regions, chunk_size the chunk size.
-  void prepare_for_par_region_addition(uint n_regions, uint chunk_size);
+  void prepare_for_par_region_addition(uint n_threads, uint n_regions, uint chunk_size);
   // Returns the first index in a contiguous chunk of chunk_size indexes
   // that the calling thread has reserved.  These must be set by the
   // calling thread using set_region() (to NULL if necessary).
--- a/hotspot/src/share/vm/gc/g1/concurrentG1Refine.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/g1/concurrentG1Refine.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -35,7 +35,7 @@
 {
   // Ergonomically select initial concurrent refinement parameters
   if (FLAG_IS_DEFAULT(G1ConcRefinementGreenZone)) {
-    FLAG_SET_DEFAULT(G1ConcRefinementGreenZone, MAX2<int>(ParallelGCThreads, 1));
+    FLAG_SET_DEFAULT(G1ConcRefinementGreenZone, (intx)ParallelGCThreads);
   }
   set_green_zone(G1ConcRefinementGreenZone);
 
--- a/hotspot/src/share/vm/gc/g1/concurrentMark.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/g1/concurrentMark.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -518,7 +518,7 @@
   _markStack(this),
   // _finger set in set_non_marking_state
 
-  _max_worker_id(MAX2((uint)ParallelGCThreads, 1U)),
+  _max_worker_id((uint)ParallelGCThreads),
   // _active_tasks set in set_non_marking_state
   // _tasks set inside the constructor
   _task_queues(new CMTaskQueueSet((int) _max_worker_id)),
@@ -1218,15 +1218,13 @@
     "Maximum number of marking threads exceeded");
 
   uint active_workers = MAX2(1U, parallel_marking_threads());
+  assert(active_workers > 0, "Should have been set");
 
   // Parallel task terminator is set in "set_concurrency_and_phase()"
   set_concurrency_and_phase(active_workers, true /* concurrent */);
 
   CMConcurrentMarkingTask markingTask(this, cmThread());
   _parallel_workers->set_active_workers(active_workers);
-  // Don't set _n_par_threads because it affects MT in process_roots()
-  // and the decisions on that MT processing is made elsewhere.
-  assert(_parallel_workers->active_workers() > 0, "Should have been set");
   _parallel_workers->run_task(&markingTask);
   print_stats();
 }
@@ -1761,28 +1759,20 @@
   }
 };
 
-class G1ParNoteEndTask;
-
 class G1NoteEndOfConcMarkClosure : public HeapRegionClosure {
   G1CollectedHeap* _g1;
-  size_t _max_live_bytes;
-  uint _regions_claimed;
   size_t _freed_bytes;
   FreeRegionList* _local_cleanup_list;
   HeapRegionSetCount _old_regions_removed;
   HeapRegionSetCount _humongous_regions_removed;
   HRRSCleanupTask* _hrrs_cleanup_task;
-  double _claimed_region_time;
-  double _max_region_time;
 
 public:
   G1NoteEndOfConcMarkClosure(G1CollectedHeap* g1,
                              FreeRegionList* local_cleanup_list,
                              HRRSCleanupTask* hrrs_cleanup_task) :
     _g1(g1),
-    _max_live_bytes(0), _regions_claimed(0),
     _freed_bytes(0),
-    _claimed_region_time(0.0), _max_region_time(0.0),
     _local_cleanup_list(local_cleanup_list),
     _old_regions_removed(),
     _humongous_regions_removed(),
@@ -1799,10 +1789,7 @@
     // We use a claim value of zero here because all regions
     // were claimed with value 1 in the FinalCount task.
     _g1->reset_gc_time_stamps(hr);
-    double start = os::elapsedTime();
-    _regions_claimed++;
     hr->note_end_of_marking();
-    _max_live_bytes += hr->max_live_bytes();
 
     if (hr->used() > 0 && hr->max_live_bytes() == 0 && !hr->is_young()) {
       _freed_bytes += hr->used();
@@ -1819,18 +1806,8 @@
       hr->rem_set()->do_cleanup_work(_hrrs_cleanup_task);
     }
 
-    double region_time = (os::elapsedTime() - start);
-    _claimed_region_time += region_time;
-    if (region_time > _max_region_time) {
-      _max_region_time = region_time;
-    }
     return false;
   }
-
-  size_t max_live_bytes() { return _max_live_bytes; }
-  uint regions_claimed() { return _regions_claimed; }
-  double claimed_region_time_sec() { return _claimed_region_time; }
-  double max_region_time_sec() { return _max_region_time; }
 };
 
 class G1ParNoteEndTask: public AbstractGangTask {
@@ -1838,14 +1815,12 @@
 
 protected:
   G1CollectedHeap* _g1h;
-  size_t _max_live_bytes;
-  size_t _freed_bytes;
   FreeRegionList* _cleanup_list;
   HeapRegionClaimer _hrclaimer;
 
 public:
   G1ParNoteEndTask(G1CollectedHeap* g1h, FreeRegionList* cleanup_list, uint n_workers) :
-      AbstractGangTask("G1 note end"), _g1h(g1h), _max_live_bytes(0), _freed_bytes(0), _cleanup_list(cleanup_list), _hrclaimer(n_workers) {
+      AbstractGangTask("G1 note end"), _g1h(g1h), _cleanup_list(cleanup_list), _hrclaimer(n_workers) {
   }
 
   void work(uint worker_id) {
@@ -1861,8 +1836,6 @@
     {
       MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag);
       _g1h->decrement_summary_bytes(g1_note_end.freed_bytes());
-      _max_live_bytes += g1_note_end.max_live_bytes();
-      _freed_bytes += g1_note_end.freed_bytes();
 
       // If we iterate over the global cleanup list at the end of
       // cleanup to do this printing we will not guarantee to only
@@ -1887,8 +1860,6 @@
       HeapRegionRemSet::finish_cleanup_task(&hrrs_cleanup_task);
     }
   }
-  size_t max_live_bytes() { return _max_live_bytes; }
-  size_t freed_bytes() { return _freed_bytes; }
 };
 
 class G1ParScrubRemSetTask: public AbstractGangTask {
@@ -1938,18 +1909,10 @@
 
   HeapRegionRemSet::reset_for_cleanup_tasks();
 
-  uint n_workers;
-
   // Do counting once more with the world stopped for good measure.
   G1ParFinalCountTask g1_par_count_task(g1h, &_region_bm, &_card_bm);
 
-  g1h->set_par_threads();
-  n_workers = g1h->n_par_threads();
-  assert(g1h->n_par_threads() == n_workers,
-         "Should not have been reset");
   g1h->workers()->run_task(&g1_par_count_task);
-  // Done with the parallel phase so reset to 0.
-  g1h->set_par_threads(0);
 
   if (VerifyDuringGC) {
     // Verify that the counting data accumulated during marking matches
@@ -1965,10 +1928,7 @@
                                                  &expected_region_bm,
                                                  &expected_card_bm);
 
-    g1h->set_par_threads((int)n_workers);
     g1h->workers()->run_task(&g1_par_verify_task);
-    // Done with the parallel phase so reset to 0.
-    g1h->set_par_threads(0);
 
     guarantee(g1_par_verify_task.failures() == 0, "Unexpected accounting failures");
   }
@@ -1990,11 +1950,11 @@
 
   g1h->reset_gc_time_stamp();
 
+  uint n_workers = _g1h->workers()->active_workers();
+
   // Note end of marking in all heap regions.
   G1ParNoteEndTask g1_par_note_end_task(g1h, &_cleanup_list, n_workers);
-  g1h->set_par_threads((int)n_workers);
   g1h->workers()->run_task(&g1_par_note_end_task);
-  g1h->set_par_threads(0);
   g1h->check_gc_time_stamps();
 
   if (!cleanup_list_is_empty()) {
@@ -2009,9 +1969,7 @@
   if (G1ScrubRemSets) {
     double rs_scrub_start = os::elapsedTime();
     G1ParScrubRemSetTask g1_par_scrub_rs_task(g1h, &_region_bm, &_card_bm, n_workers);
-    g1h->set_par_threads((int)n_workers);
     g1h->workers()->run_task(&g1_par_scrub_rs_task);
-    g1h->set_par_threads(0);
 
     double rs_scrub_end = os::elapsedTime();
     double this_rs_scrub_time = (rs_scrub_end - rs_scrub_start);
@@ -2020,7 +1978,7 @@
 
   // this will also free any regions totally full of garbage objects,
   // and sort the regions.
-  g1h->g1_policy()->record_concurrent_mark_cleanup_end((int)n_workers);
+  g1h->g1_policy()->record_concurrent_mark_cleanup_end();
 
   // Statistics.
   double end = os::elapsedTime();
@@ -2312,9 +2270,7 @@
   // and overflow handling in CMTask::do_marking_step() knows
   // how many workers to wait for.
   _cm->set_concurrency(_active_workers);
-  _g1h->set_par_threads(_active_workers);
   _workers->run_task(&proc_task_proxy);
-  _g1h->set_par_threads(0);
 }
 
 class G1CMRefEnqueueTaskProxy: public AbstractGangTask {
@@ -2344,9 +2300,7 @@
   // and overflow handling in CMTask::do_marking_step() knows
   // how many workers to wait for.
   _cm->set_concurrency(_active_workers);
-  _g1h->set_par_threads(_active_workers);
   _workers->run_task(&enq_task_proxy);
-  _g1h->set_par_threads(0);
 }
 
 void ConcurrentMark::weakRefsWorkParallelPart(BoolObjectClosure* is_alive, bool purged_classes) {
@@ -2608,27 +2562,23 @@
 
   g1h->ensure_parsability(false);
 
-  StrongRootsScope srs;
   // this is remark, so we'll use up all active threads
   uint active_workers = g1h->workers()->active_workers();
-  if (active_workers == 0) {
-    assert(active_workers > 0, "Should have been set earlier");
-    active_workers = (uint) ParallelGCThreads;
-    g1h->workers()->set_active_workers(active_workers);
-  }
   set_concurrency_and_phase(active_workers, false /* concurrent */);
   // Leave _parallel_marking_threads at it's
   // value originally calculated in the ConcurrentMark
   // constructor and pass values of the active workers
   // through the gang in the task.
 
-  CMRemarkTask remarkTask(this, active_workers);
-  // We will start all available threads, even if we decide that the
-  // active_workers will be fewer. The extra ones will just bail out
-  // immediately.
-  g1h->set_par_threads(active_workers);
-  g1h->workers()->run_task(&remarkTask);
-  g1h->set_par_threads(0);
+  {
+    StrongRootsScope srs(active_workers);
+
+    CMRemarkTask remarkTask(this, active_workers);
+    // We will start all available threads, even if we decide that the
+    // active_workers will be fewer. The extra ones will just bail out
+    // immediately.
+    g1h->workers()->run_task(&remarkTask);
+  }
 
   SATBMarkQueueSet& satb_mq_set = JavaThread::satb_mark_queue_set();
   guarantee(has_overflown() ||
@@ -3001,9 +2951,7 @@
   G1AggregateCountDataTask g1_par_agg_task(_g1h, this, &_card_bm,
                                            _max_worker_id, n_workers);
 
-  _g1h->set_par_threads(n_workers);
   _g1h->workers()->run_task(&g1_par_agg_task);
-  _g1h->set_par_threads(0);
 }
 
 // Clear the per-worker arrays used to store the per-region counting data
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -1326,27 +1326,10 @@
         AdaptiveSizePolicy::calc_active_workers(workers()->total_workers(),
                                                 workers()->active_workers(),
                                                 Threads::number_of_non_daemon_threads());
-      assert(UseDynamicNumberOfGCThreads ||
-             n_workers == workers()->total_workers(),
-             "If not dynamic should be using all the  workers");
       workers()->set_active_workers(n_workers);
-      // Set parallel threads in the heap (_n_par_threads) only
-      // before a parallel phase and always reset it to 0 after
-      // the phase so that the number of parallel threads does
-      // no get carried forward to a serial phase where there
-      // may be code that is "possibly_parallel".
-      set_par_threads(n_workers);
 
       ParRebuildRSTask rebuild_rs_task(this);
-      assert(UseDynamicNumberOfGCThreads ||
-             workers()->active_workers() == workers()->total_workers(),
-             "Unless dynamic should use total workers");
-      // Use the most recent number of  active workers
-      assert(workers()->active_workers() > 0,
-             "Active workers not properly set");
-      set_par_threads(workers()->active_workers());
       workers()->run_task(&rebuild_rs_task);
-      set_par_threads(0);
 
       // Rebuild the strong code root lists for each region
       rebuild_strong_code_roots();
@@ -1769,7 +1752,7 @@
   _allocator = G1Allocator::create_allocator(this);
   _humongous_object_threshold_in_words = HeapRegion::GrainWords / 2;
 
-  int n_queues = MAX2((int)ParallelGCThreads, 1);
+  int n_queues = (int)ParallelGCThreads;
   _task_queues = new RefToScanQueueSet(n_queues);
 
   uint n_rem_sets = HeapRegionRemSet::num_par_rem_sets();
@@ -2081,11 +2064,11 @@
     new ReferenceProcessor(mr,    // span
                            ParallelRefProcEnabled && (ParallelGCThreads > 1),
                                 // mt processing
-                           (int) ParallelGCThreads,
+                           (uint) ParallelGCThreads,
                                 // degree of mt processing
                            (ParallelGCThreads > 1) || (ConcGCThreads > 1),
                                 // mt discovery
-                           (int) MAX2(ParallelGCThreads, ConcGCThreads),
+                           (uint) MAX2(ParallelGCThreads, ConcGCThreads),
                                 // degree of mt discovery
                            false,
                                 // Reference discovery is not atomic
@@ -2098,11 +2081,11 @@
     new ReferenceProcessor(mr,    // span
                            ParallelRefProcEnabled && (ParallelGCThreads > 1),
                                 // mt processing
-                           MAX2((int)ParallelGCThreads, 1),
+                           (uint) ParallelGCThreads,
                                 // degree of mt processing
                            (ParallelGCThreads > 1),
                                 // mt discovery
-                           MAX2((int)ParallelGCThreads, 1),
+                           (uint) ParallelGCThreads,
                                 // degree of mt discovery
                            true,
                                 // Reference discovery is atomic
@@ -2502,8 +2485,7 @@
   assert(_worker_cset_start_region != NULL, "sanity");
   assert(_worker_cset_start_region_time_stamp != NULL, "sanity");
 
-  int n_queues = MAX2((int)ParallelGCThreads, 1);
-  for (int i = 0; i < n_queues; i++) {
+  for (uint i = 0; i < ParallelGCThreads; i++) {
     _worker_cset_start_region[i] = NULL;
     _worker_cset_start_region_time_stamp[i] = 0;
   }
@@ -2541,9 +2523,6 @@
   result = g1_policy()->collection_set();
   uint cs_size = g1_policy()->cset_region_length();
   uint active_workers = workers()->active_workers();
-  assert(UseDynamicNumberOfGCThreads ||
-           active_workers == workers()->total_workers(),
-           "Unless dynamic should use total workers");
 
   uint end_ind   = (cs_size * worker_i) / active_workers;
   uint start_ind = 0;
@@ -3021,7 +3000,7 @@
     G1VerifyCodeRootBlobClosure blobsCl(&codeRootsCl);
 
     {
-      G1RootProcessor root_processor(this);
+      G1RootProcessor root_processor(this, 1);
       root_processor.process_all_roots(&rootsCl,
                                        &cldCl,
                                        &blobsCl);
@@ -3042,13 +3021,7 @@
     if (GCParallelVerificationEnabled && ParallelGCThreads > 1) {
 
       G1ParVerifyTask task(this, vo);
-      assert(UseDynamicNumberOfGCThreads ||
-        workers()->active_workers() == workers()->total_workers(),
-        "If not dynamic should be using all the workers");
-      uint n_workers = workers()->active_workers();
-      set_par_threads(n_workers);
       workers()->run_task(&task);
-      set_par_threads(0);
       if (task.failures()) {
         failures = true;
       }
@@ -3572,6 +3545,10 @@
 };
 #endif // ASSERT
 
+uint G1CollectedHeap::num_task_queues() const {
+  return _task_queues->size();
+}
+
 #if TASKQUEUE_STATS
 void G1CollectedHeap::print_taskqueue_stats_hdr(outputStream* const st) {
   st->print_raw_cr("GC Task Stats");
@@ -3583,7 +3560,7 @@
   print_taskqueue_stats_hdr(st);
 
   TaskQueueStats totals;
-  const uint n = workers()->total_workers();
+  const uint n = num_task_queues();
   for (uint i = 0; i < n; ++i) {
     st->print("%3u ", i); task_queue(i)->stats.print(st); st->cr();
     totals += task_queue(i)->stats;
@@ -3594,7 +3571,7 @@
 }
 
 void G1CollectedHeap::reset_taskqueue_stats() {
-  const uint n = workers()->total_workers();
+  const uint n = num_task_queues();
   for (uint i = 0; i < n; ++i) {
     task_queue(i)->stats.reset();
   }
@@ -3696,9 +3673,6 @@
     uint active_workers = AdaptiveSizePolicy::calc_active_workers(workers()->total_workers(),
                                                                   workers()->active_workers(),
                                                                   Threads::number_of_non_daemon_threads());
-    assert(UseDynamicNumberOfGCThreads ||
-           active_workers == workers()->total_workers(),
-           "If not dynamic should be using all the  workers");
     workers()->set_active_workers(active_workers);
 
     double pause_start_sec = os::elapsedTime();
@@ -3873,8 +3847,7 @@
 
         if (evacuation_failed()) {
           _allocator->set_used(recalculate_used());
-          uint n_queues = MAX2((int)ParallelGCThreads, 1);
-          for (uint i = 0; i < n_queues; i++) {
+          for (uint i = 0; i < ParallelGCThreads; i++) {
             if (_evacuation_failed_info_array[i].has_failed()) {
               _gc_tracer_stw->report_evacuation_failed(_evacuation_failed_info_array[i]);
             }
@@ -4041,10 +4014,8 @@
 void G1CollectedHeap::remove_self_forwarding_pointers() {
   double remove_self_forwards_start = os::elapsedTime();
 
-  set_par_threads();
   G1ParRemoveSelfForwardPtrsTask rsfp_task(this);
   workers()->run_task(&rsfp_task);
-  set_par_threads(0);
 
   // Now restore saved marks, if any.
   assert(_objs_with_preserved_marks.size() ==
@@ -4308,12 +4279,13 @@
   Mutex* stats_lock() { return &_stats_lock; }
 
 public:
-  G1ParTask(G1CollectedHeap* g1h, RefToScanQueueSet *task_queues, G1RootProcessor* root_processor)
+  G1ParTask(G1CollectedHeap* g1h, RefToScanQueueSet *task_queues, G1RootProcessor* root_processor, uint n_workers)
     : AbstractGangTask("G1 collection"),
       _g1h(g1h),
       _queues(task_queues),
       _root_processor(root_processor),
-      _terminator(0, _queues),
+      _terminator(n_workers, _queues),
+      _n_workers(n_workers),
       _stats_lock(Mutex::leaf, "parallel G1 stats lock", true)
   {}
 
@@ -4325,12 +4297,6 @@
 
   ParallelTaskTerminator* terminator() { return &_terminator; }
 
-  virtual void set_for_termination(uint active_workers) {
-    _root_processor->set_num_workers(active_workers);
-    terminator()->reset_for_reuse(active_workers);
-    _n_workers = active_workers;
-  }
-
   // Helps out with CLD processing.
   //
   // During InitialMark we need to:
@@ -4811,19 +4777,14 @@
 
   G1ParallelCleaningTask g1_unlink_task(is_alive, process_strings, process_symbols,
                                         n_workers, class_unloading_occurred);
-  set_par_threads(n_workers);
   workers()->run_task(&g1_unlink_task);
-  set_par_threads(0);
 }
 
 void G1CollectedHeap::unlink_string_and_symbol_table(BoolObjectClosure* is_alive,
                                                      bool process_strings, bool process_symbols) {
   {
-    uint n_workers = workers()->active_workers();
     G1StringSymbolTableUnlinkTask g1_unlink_task(is_alive, process_strings, process_symbols);
-    set_par_threads(n_workers);
     workers()->run_task(&g1_unlink_task);
-    set_par_threads(0);
   }
 
   if (G1StringDedup::is_enabled()) {
@@ -4851,13 +4812,9 @@
 void G1CollectedHeap::redirty_logged_cards() {
   double redirty_logged_cards_start = os::elapsedTime();
 
-  uint n_workers = workers()->active_workers();
-
   G1RedirtyLoggedCardsTask redirty_task(&dirty_card_queue_set());
   dirty_card_queue_set().reset_for_par_iteration();
-  set_par_threads(n_workers);
   workers()->run_task(&redirty_task);
-  set_par_threads(0);
 
   DirtyCardQueueSet& dcq = JavaThread::dirty_card_queue_set();
   dcq.merge_bufferlists(&dirty_card_queue_set());
@@ -5093,9 +5050,7 @@
   ParallelTaskTerminator terminator(_active_workers, _queues);
   G1STWRefProcTaskProxy proc_task_proxy(proc_task, _g1h, _queues, &terminator);
 
-  _g1h->set_par_threads(_active_workers);
   _workers->run_task(&proc_task_proxy);
-  _g1h->set_par_threads(0);
 }
 
 // Gang task for parallel reference enqueueing.
@@ -5124,9 +5079,7 @@
 
   G1STWRefEnqueueTaskProxy enq_task_proxy(enq_task);
 
-  _g1h->set_par_threads(_active_workers);
   _workers->run_task(&enq_task_proxy);
-  _g1h->set_par_threads(0);
 }
 
 // End of weak reference support closures
@@ -5219,7 +5172,7 @@
 };
 
 // Weak Reference processing during an evacuation pause (part 1).
-void G1CollectedHeap::process_discovered_references(uint no_of_gc_workers) {
+void G1CollectedHeap::process_discovered_references() {
   double ref_proc_start = os::elapsedTime();
 
   ReferenceProcessor* rp = _ref_processor_stw;
@@ -5246,17 +5199,14 @@
   // referents points to another object which is also referenced by an
   // object discovered by the STW ref processor.
 
-  assert(no_of_gc_workers == workers()->active_workers(), "Need to reset active GC workers");
-
-  set_par_threads(no_of_gc_workers);
+  uint no_of_gc_workers = workers()->active_workers();
+
   G1ParPreserveCMReferentsTask keep_cm_referents(this,
                                                  no_of_gc_workers,
                                                  _task_queues);
 
   workers()->run_task(&keep_cm_referents);
 
-  set_par_threads(0);
-
   // Closure to test whether a referent is alive.
   G1STWIsAliveClosure is_alive(this);
 
@@ -5330,7 +5280,7 @@
 }
 
 // Weak Reference processing during an evacuation pause (part 2).
-void G1CollectedHeap::enqueue_discovered_references(uint no_of_gc_workers) {
+void G1CollectedHeap::enqueue_discovered_references() {
   double ref_enq_start = os::elapsedTime();
 
   ReferenceProcessor* rp = _ref_processor_stw;
@@ -5344,12 +5294,12 @@
   } else {
     // Parallel reference enqueueing
 
-    assert(no_of_gc_workers == workers()->active_workers(),
-           "Need to reset active workers");
-    assert(rp->num_q() == no_of_gc_workers, "sanity");
-    assert(no_of_gc_workers <= rp->max_num_q(), "sanity");
-
-    G1STWRefProcTaskExecutor par_task_executor(this, workers(), _task_queues, no_of_gc_workers);
+    uint n_workers = workers()->active_workers();
+
+    assert(rp->num_q() == n_workers, "sanity");
+    assert(n_workers <= rp->max_num_q(), "sanity");
+
+    G1STWRefProcTaskExecutor par_task_executor(this, workers(), _task_queues, n_workers);
     rp->enqueue_discovered_references(&par_task_executor);
   }
 
@@ -5380,11 +5330,6 @@
   hot_card_cache->set_use_cache(false);
 
   const uint n_workers = workers()->active_workers();
-  assert(UseDynamicNumberOfGCThreads ||
-         n_workers == workers()->total_workers(),
-         "If not dynamic should be using all the  workers");
-  set_par_threads(n_workers);
-
 
   init_for_evac_failure(NULL);
 
@@ -5393,19 +5338,16 @@
   double end_par_time_sec;
 
   {
-    G1RootProcessor root_processor(this);
-    G1ParTask g1_par_task(this, _task_queues, &root_processor);
+    G1RootProcessor root_processor(this, n_workers);
+    G1ParTask g1_par_task(this, _task_queues, &root_processor, n_workers);
     // InitialMark needs claim bits to keep track of the marked-through CLDs.
     if (g1_policy()->during_initial_mark_pause()) {
       ClassLoaderDataGraph::clear_claimed_marks();
     }
 
-     // The individual threads will set their evac-failure closures.
-     if (PrintTerminationStats) G1ParScanThreadState::print_termination_stats_hdr();
-     // These tasks use ShareHeap::_process_strong_tasks
-     assert(UseDynamicNumberOfGCThreads ||
-            workers()->active_workers() == workers()->total_workers(),
-            "If not dynamic should be using all the  workers");
+    // The individual threads will set their evac-failure closures.
+    if (PrintTerminationStats) G1ParScanThreadState::print_termination_stats_hdr();
+
     workers()->run_task(&g1_par_task);
     end_par_time_sec = os::elapsedTime();
 
@@ -5425,14 +5367,12 @@
         (os::elapsedTime() - end_par_time_sec) * 1000.0;
   phase_times->record_code_root_fixup_time(code_root_fixup_time_ms);
 
-  set_par_threads(0);
-
   // Process any discovered reference objects - we have
   // to do this _before_ we retire the GC alloc regions
   // as we may have to copy some 'reachable' referent
   // objects (and their reachable sub-graphs) that were
   // not copied during the pause.
-  process_discovered_references(n_workers);
+  process_discovered_references();
 
   if (G1StringDedup::is_enabled()) {
     double fixup_start = os::elapsedTime();
@@ -5474,7 +5414,7 @@
   // will log these updates (and dirty their associated
   // cards). We need these updates logged to update any
   // RSets.
-  enqueue_discovered_references(n_workers);
+  enqueue_discovered_references();
 
   redirty_logged_cards();
   COMPILER2_PRESENT(DerivedPointerTable::update_pointers());
@@ -5779,9 +5719,7 @@
     // Iterate over the dirty cards region list.
     G1ParCleanupCTTask cleanup_task(ct_bs, this);
 
-    set_par_threads();
     workers()->run_task(&cleanup_task);
-    set_par_threads(0);
 #ifndef PRODUCT
     if (G1VerifyCTCleanup || VerifyAfterGC) {
       G1VerifyCardTableCleanup cleanup_verifier(this, ct_bs);
@@ -6314,21 +6252,6 @@
   g1mm()->update_eden_size();
 }
 
-void G1CollectedHeap::set_par_threads() {
-  // Don't change the number of workers.  Use the value previously set
-  // in the workgroup.
-  uint n_workers = workers()->active_workers();
-  assert(UseDynamicNumberOfGCThreads ||
-           n_workers == workers()->total_workers(),
-      "Otherwise should be using the total number of workers");
-  if (n_workers == 0) {
-    assert(false, "Should have been set in prior evacuation pause.");
-    n_workers = ParallelGCThreads;
-    workers()->set_active_workers(n_workers);
-  }
-  set_par_threads(n_workers);
-}
-
 // Methods for the GC alloc regions
 
 HeapRegion* G1CollectedHeap::new_gc_alloc_region(size_t word_size,
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -606,11 +606,11 @@
 
   // Process any reference objects discovered during
   // an incremental evacuation pause.
-  void process_discovered_references(uint no_of_gc_workers);
+  void process_discovered_references();
 
   // Enqueue any remaining discovered references
   // after processing.
-  void enqueue_discovered_references(uint no_of_gc_workers);
+  void enqueue_discovered_references();
 
 public:
   FlexibleWorkGang* workers() const { return _workers; }
@@ -981,6 +981,8 @@
 
   RefToScanQueue *task_queue(uint i) const;
 
+  uint num_task_queues() const;
+
   // A set of cards where updates happened during the GC
   DirtyCardQueueSet& dirty_card_queue_set() { return _dirty_card_queue_set; }
 
@@ -1012,11 +1014,6 @@
   // Initialize weak reference processing.
   void ref_processing_init();
 
-  // Explicitly import set_par_threads into this scope
-  using CollectedHeap::set_par_threads;
-  // Set _n_par_threads according to a policy TBD.
-  void set_par_threads();
-
   virtual Name kind() const {
     return CollectedHeap::G1CollectedHeap;
   }
--- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -1587,14 +1587,17 @@
 }
 
 void
-G1CollectorPolicy::record_concurrent_mark_cleanup_end(uint n_workers) {
+G1CollectorPolicy::record_concurrent_mark_cleanup_end() {
   _collectionSetChooser->clear();
 
+  FlexibleWorkGang* workers = _g1->workers();
+  uint n_workers = workers->active_workers();
+
   uint n_regions = _g1->num_regions();
   uint chunk_size = calculate_parallel_work_chunk_size(n_workers, n_regions);
-  _collectionSetChooser->prepare_for_par_region_addition(n_regions, chunk_size);
+  _collectionSetChooser->prepare_for_par_region_addition(n_workers, n_regions, chunk_size);
   ParKnownGarbageTask par_known_garbage_task(_collectionSetChooser, chunk_size, n_workers);
-  _g1->workers()->run_task(&par_known_garbage_task);
+  workers->run_task(&par_known_garbage_task);
 
   _collectionSetChooser->sort_regions();
 
--- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -692,7 +692,7 @@
 
   // Record start, end, and completion of cleanup.
   void record_concurrent_mark_cleanup_start();
-  void record_concurrent_mark_cleanup_end(uint n_workers);
+  void record_concurrent_mark_cleanup_end();
   void record_concurrent_mark_cleanup_completed();
 
   // Records the information about the heap size for reporting in
--- a/hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -127,7 +127,7 @@
 
   MarkingCodeBlobClosure follow_code_closure(&GenMarkSweep::follow_root_closure, !CodeBlobToOopClosure::FixRelocations);
   {
-    G1RootProcessor root_processor(g1h);
+    G1RootProcessor root_processor(g1h, 1);
     root_processor.process_strong_roots(&GenMarkSweep::follow_root_closure,
                                         &GenMarkSweep::follow_cld_closure,
                                         &follow_code_closure);
@@ -237,7 +237,7 @@
 
   CodeBlobToOopClosure adjust_code_closure(&GenMarkSweep::adjust_pointer_closure, CodeBlobToOopClosure::FixRelocations);
   {
-    G1RootProcessor root_processor(g1h);
+    G1RootProcessor root_processor(g1h, 1);
     root_processor.process_all_roots(&GenMarkSweep::adjust_pointer_closure,
                                      &GenMarkSweep::adjust_cld_closure,
                                      &adjust_code_closure);
--- a/hotspot/src/share/vm/gc/g1/g1OopClosures.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -50,8 +50,8 @@
   _par_scan_state = par_scan_state;
   _worker_id = par_scan_state->queue_num();
 
-  assert(_worker_id < MAX2((uint)ParallelGCThreads, 1u),
-         err_msg("The given worker id %u must be less than the number of threads %u", _worker_id, MAX2((uint)ParallelGCThreads, 1u)));
+  assert(_worker_id < ParallelGCThreads,
+         err_msg("The given worker id %u must be less than the number of threads " UINTX_FORMAT, _worker_id, ParallelGCThreads));
 }
 
 // Generate G1 specialized oop_oop_iterate functions.
--- a/hotspot/src/share/vm/gc/g1/g1RootProcessor.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1RootProcessor.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -90,11 +90,10 @@
 
 
 void G1RootProcessor::worker_has_discovered_all_strong_classes() {
-  uint n_workers = _g1h->n_par_threads();
   assert(ClassUnloadingWithConcurrentMark, "Currently only needed when doing G1 Class Unloading");
 
   uint new_value = (uint)Atomic::add(1, &_n_workers_discovered_strong_classes);
-  if (new_value == n_workers) {
+  if (new_value == n_workers()) {
     // This thread is last. Notify the others.
     MonitorLockerEx ml(&_lock, Mutex::_no_safepoint_check_flag);
     _lock.notify_all();
@@ -102,21 +101,20 @@
 }
 
 void G1RootProcessor::wait_until_all_strong_classes_discovered() {
-  uint n_workers = _g1h->n_par_threads();
   assert(ClassUnloadingWithConcurrentMark, "Currently only needed when doing G1 Class Unloading");
 
-  if ((uint)_n_workers_discovered_strong_classes != n_workers) {
+  if ((uint)_n_workers_discovered_strong_classes != n_workers()) {
     MonitorLockerEx ml(&_lock, Mutex::_no_safepoint_check_flag);
-    while ((uint)_n_workers_discovered_strong_classes != n_workers) {
+    while ((uint)_n_workers_discovered_strong_classes != n_workers()) {
       _lock.wait(Mutex::_no_safepoint_check_flag, 0, false);
     }
   }
 }
 
-G1RootProcessor::G1RootProcessor(G1CollectedHeap* g1h) :
+G1RootProcessor::G1RootProcessor(G1CollectedHeap* g1h, uint n_workers) :
     _g1h(g1h),
     _process_strong_tasks(new SubTasksDone(G1RP_PS_NumElements)),
-    _srs(),
+    _srs(n_workers),
     _lock(Mutex::leaf, "G1 Root Scanning barrier lock", false, Monitor::_safepoint_check_never),
     _n_workers_discovered_strong_classes(0) {}
 
@@ -206,7 +204,7 @@
     }
   }
 
-  _process_strong_tasks->all_tasks_completed();
+  _process_strong_tasks->all_tasks_completed(n_workers());
 }
 
 void G1RootProcessor::process_strong_roots(OopClosure* oops,
@@ -216,7 +214,7 @@
   process_java_roots(oops, clds, clds, NULL, blobs, NULL, 0);
   process_vm_roots(oops, NULL, NULL, 0);
 
-  _process_strong_tasks->all_tasks_completed();
+  _process_strong_tasks->all_tasks_completed(n_workers());
 }
 
 void G1RootProcessor::process_all_roots(OopClosure* oops,
@@ -230,7 +228,7 @@
     CodeCache::blobs_do(blobs);
   }
 
-  _process_strong_tasks->all_tasks_completed();
+  _process_strong_tasks->all_tasks_completed(n_workers());
 }
 
 void G1RootProcessor::process_java_roots(OopClosure* strong_roots,
@@ -253,7 +251,7 @@
 
   {
     G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::ThreadRoots, worker_i);
-    bool is_par = _g1h->n_par_threads() > 0;
+    bool is_par = n_workers() > 1;
     Threads::possibly_parallel_oops_do(is_par, strong_roots, thread_stack_clds, strong_code);
   }
 }
@@ -329,6 +327,6 @@
   _g1h->g1_rem_set()->oops_into_collection_set_do(scan_rs, &scavenge_cs_nmethods, worker_i);
 }
 
-void G1RootProcessor::set_num_workers(uint active_workers) {
-  _process_strong_tasks->set_n_threads(active_workers);
+uint G1RootProcessor::n_workers() const {
+  return _srs.n_threads();
 }
--- a/hotspot/src/share/vm/gc/g1/g1RootProcessor.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1RootProcessor.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -85,7 +85,7 @@
                         uint worker_i);
 
 public:
-  G1RootProcessor(G1CollectedHeap* g1h);
+  G1RootProcessor(G1CollectedHeap* g1h, uint n_workers);
 
   // Apply closures to the strongly and weakly reachable roots in the system
   // in a single pass.
@@ -114,8 +114,8 @@
                             OopClosure* scan_non_heap_weak_roots,
                             uint worker_i);
 
-  // Inform the root processor about the number of worker threads
-  void set_num_workers(uint active_workers);
+  // Number of worker threads used by the root processor.
+  uint n_workers() const;
 };
 
 #endif // SHARE_VM_GC_G1_G1ROOTPROCESSOR_HPP
--- a/hotspot/src/share/vm/gc/g1/g1StringDedup.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1StringDedup.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -153,9 +153,7 @@
 
   G1StringDedupUnlinkOrOopsDoTask task(is_alive, keep_alive, allow_resize_and_rehash, phase_times);
   G1CollectedHeap* g1h = G1CollectedHeap::heap();
-  g1h->set_par_threads();
   g1h->workers()->run_task(&task);
-  g1h->set_par_threads(0);
 }
 
 void G1StringDedup::threads_do(ThreadClosure* tc) {
--- a/hotspot/src/share/vm/gc/g1/g1StringDedupQueue.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1StringDedupQueue.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -42,7 +42,7 @@
   _cancel(false),
   _empty(true),
   _dropped(0) {
-  _nqueues = MAX2(ParallelGCThreads, (size_t)1);
+  _nqueues = ParallelGCThreads;
   _queues = NEW_C_HEAP_ARRAY(G1StringDedupWorkerQueue, _nqueues, mtGC);
   for (size_t i = 0; i < _nqueues; i++) {
     new (_queues + i) G1StringDedupWorkerQueue(G1StringDedupWorkerQueue::default_segment_size(), _max_cache_size, _max_size);
--- a/hotspot/src/share/vm/gc/g1/g1StringDedupTable.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1StringDedupTable.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -112,7 +112,7 @@
 };
 
 G1StringDedupEntryCache::G1StringDedupEntryCache() {
-  _nlists = MAX2(ParallelGCThreads, (size_t)1);
+  _nlists = ParallelGCThreads;
   _lists = PaddedArray<G1StringDedupEntryFreeList, mtGC>::create_unfreeable((uint)_nlists);
 }
 
--- a/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -832,9 +832,9 @@
   _ref_processor =
     new ReferenceProcessor(mr,            // span
                            ParallelRefProcEnabled && (ParallelGCThreads > 1), // mt processing
-                           (int) ParallelGCThreads, // mt processing degree
+                           (uint) ParallelGCThreads, // mt processing degree
                            true,          // mt discovery
-                           (int) ParallelGCThreads, // mt discovery degree
+                           (uint) ParallelGCThreads, // mt discovery degree
                            true,          // atomic_discovery
                            &_is_alive_closure); // non-header is alive closure
   _counters = new CollectorCounters("PSParallelCompact", 1);
@@ -2029,7 +2029,6 @@
     // Set the number of GC threads to be used in this collection
     gc_task_manager()->set_active_gang();
     gc_task_manager()->task_idle_workers();
-    heap->set_par_threads(gc_task_manager()->active_workers());
 
     TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
     GCTraceTime t1(GCCauseString("Full GC", gc_cause), PrintGC, !PrintGCDetails, NULL, _gc_tracer.gc_id());
--- a/hotspot/src/share/vm/gc/parallel/psScavenge.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/parallel/psScavenge.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -382,7 +382,6 @@
     // Get the active number of workers here and use that value
     // throughout the methods.
     uint active_workers = gc_task_manager()->active_workers();
-    heap->set_par_threads(active_workers);
 
     PSPromotionManager::pre_scavenge();
 
@@ -846,9 +845,9 @@
   _ref_processor =
     new ReferenceProcessor(mr,                         // span
                            ParallelRefProcEnabled && (ParallelGCThreads > 1), // mt processing
-                           (int) ParallelGCThreads,    // mt processing degree
+                           (uint) ParallelGCThreads,   // mt processing degree
                            true,                       // mt discovery
-                           (int) ParallelGCThreads,    // mt discovery degree
+                           (uint) ParallelGCThreads,   // mt discovery degree
                            true,                       // atomic_discovery
                            NULL);                      // header provides liveness info
 
--- a/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -38,6 +38,7 @@
 #include "gc/shared/referencePolicy.hpp"
 #include "gc/shared/space.inline.hpp"
 #include "gc/shared/spaceDecorator.hpp"
+#include "gc/shared/strongRootsScope.hpp"
 #include "memory/iterator.hpp"
 #include "oops/instanceRefKlass.hpp"
 #include "oops/oop.inline.hpp"
@@ -454,7 +455,7 @@
   }
 }
 
-void DefNewGeneration::younger_refs_iterate(OopsInGenClosure* cl) {
+void DefNewGeneration::younger_refs_iterate(OopsInGenClosure* cl, uint n_threads) {
   assert(false, "NYI -- are you sure you want to call this?");
 }
 
@@ -625,15 +626,22 @@
   assert(gch->no_allocs_since_save_marks(0),
          "save marks have not been newly set.");
 
-  gch->gen_process_roots(_level,
-                         true,  // Process younger gens, if any,
-                                // as strong roots.
-                         true,  // activate StrongRootsScope
-                         GenCollectedHeap::SO_ScavengeCodeCache,
-                         GenCollectedHeap::StrongAndWeakRoots,
-                         &fsc_with_no_gc_barrier,
-                         &fsc_with_gc_barrier,
-                         &cld_scan_closure);
+  {
+    // DefNew needs to run with n_threads == 0, to make sure the serial
+    // version of the card table scanning code is used.
+    // See: CardTableModRefBS::non_clean_card_iterate_possibly_parallel.
+    StrongRootsScope srs(0);
+
+    gch->gen_process_roots(&srs,
+                           _level,
+                           true,  // Process younger gens, if any,
+                                  // as strong roots.
+                           GenCollectedHeap::SO_ScavengeCodeCache,
+                           GenCollectedHeap::StrongAndWeakRoots,
+                           &fsc_with_no_gc_barrier,
+                           &fsc_with_gc_barrier,
+                           &cld_scan_closure);
+  }
 
   // "evacuate followers".
   evacuate_followers.do_void();
--- a/hotspot/src/share/vm/gc/serial/defNewGeneration.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/serial/defNewGeneration.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -255,7 +255,7 @@
   // Iteration
   void object_iterate(ObjectClosure* blk);
 
-  void younger_refs_iterate(OopsInGenClosure* cl);
+  void younger_refs_iterate(OopsInGenClosure* cl, uint n_threads);
 
   void space_iterate(SpaceClosure* blk, bool usedOnly = false);
 
--- a/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -40,6 +40,7 @@
 #include "gc/shared/modRefBarrierSet.hpp"
 #include "gc/shared/referencePolicy.hpp"
 #include "gc/shared/space.hpp"
+#include "gc/shared/strongRootsScope.hpp"
 #include "oops/instanceRefKlass.hpp"
 #include "oops/oop.inline.hpp"
 #include "prims/jvmtiExport.hpp"
@@ -200,14 +201,18 @@
   // Need new claim bits before marking starts.
   ClassLoaderDataGraph::clear_claimed_marks();
 
-  gch->gen_process_roots(level,
-                         false, // Younger gens are not roots.
-                         true,  // activate StrongRootsScope
-                         GenCollectedHeap::SO_None,
-                         GenCollectedHeap::StrongRootsOnly,
-                         &follow_root_closure,
-                         &follow_root_closure,
-                         &follow_cld_closure);
+  {
+    StrongRootsScope srs(1);
+
+    gch->gen_process_roots(&srs,
+                           level,
+                           false, // Younger gens are not roots.
+                           GenCollectedHeap::SO_None,
+                           GenCollectedHeap::StrongRootsOnly,
+                           &follow_root_closure,
+                           &follow_root_closure,
+                           &follow_cld_closure);
+  }
 
   // Process reference objects found during marking
   {
@@ -284,14 +289,18 @@
   assert(level == 1, "We don't use mark-sweep on young generations.");
   adjust_pointer_closure.set_orig_generation(gch->old_gen());
 
-  gch->gen_process_roots(level,
-                         false, // Younger gens are not roots.
-                         true,  // activate StrongRootsScope
-                         GenCollectedHeap::SO_AllCodeCache,
-                         GenCollectedHeap::StrongAndWeakRoots,
-                         &adjust_pointer_closure,
-                         &adjust_pointer_closure,
-                         &adjust_cld_closure);
+  {
+    StrongRootsScope srs(1);
+
+    gch->gen_process_roots(&srs,
+                           level,
+                           false, // Younger gens are not roots.
+                           GenCollectedHeap::SO_AllCodeCache,
+                           GenCollectedHeap::StrongAndWeakRoots,
+                           &adjust_pointer_closure,
+                           &adjust_pointer_closure,
+                           &adjust_cld_closure);
+  }
 
   gch->gen_process_weak_roots(&adjust_pointer_closure);
 
--- a/hotspot/src/share/vm/gc/shared/adaptiveSizePolicy.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/adaptiveSizePolicy.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -161,7 +161,7 @@
       }
       _debug_perturbation = !_debug_perturbation;
     }
-    assert((new_active_workers <= (uintx) ParallelGCThreads) &&
+    assert((new_active_workers <= ParallelGCThreads) &&
            (new_active_workers >= min_workers),
       "Jiggled active workers too much");
   }
--- a/hotspot/src/share/vm/gc/shared/cardGeneration.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/cardGeneration.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -353,8 +353,8 @@
   blk->do_space(space());
 }
 
-void CardGeneration::younger_refs_iterate(OopsInGenClosure* blk) {
+void CardGeneration::younger_refs_iterate(OopsInGenClosure* blk, uint n_threads) {
   blk->set_generation(this);
-  younger_refs_in_space_iterate(space(), blk);
+  younger_refs_in_space_iterate(space(), blk, n_threads);
   blk->reset_generation();
 }
--- a/hotspot/src/share/vm/gc/shared/cardGeneration.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/cardGeneration.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -89,7 +89,7 @@
 
   void space_iterate(SpaceClosure* blk, bool usedOnly = false);
 
-  void younger_refs_iterate(OopsInGenClosure* blk);
+  void younger_refs_iterate(OopsInGenClosure* blk, uint n_threads);
 
   bool is_in(const void* p) const;
 
--- a/hotspot/src/share/vm/gc/shared/cardTableModRefBS.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/cardTableModRefBS.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -440,31 +440,11 @@
 void CardTableModRefBS::non_clean_card_iterate_possibly_parallel(Space* sp,
                                                                  MemRegion mr,
                                                                  OopsInGenClosure* cl,
-                                                                 CardTableRS* ct) {
+                                                                 CardTableRS* ct,
+                                                                 uint n_threads) {
   if (!mr.is_empty()) {
-    // Caller (process_roots()) claims that all GC threads
-    // execute this call.  With UseDynamicNumberOfGCThreads now all
-    // active GC threads execute this call.  The number of active GC
-    // threads needs to be passed to par_non_clean_card_iterate_work()
-    // to get proper partitioning and termination.
-    //
-    // This is an example of where n_par_threads() is used instead
-    // of workers()->active_workers().  n_par_threads can be set to 0 to
-    // turn off parallelism.  For example when this code is called as
-    // part of verification during root processing then n_par_threads()
-    // may have been set to 0. active_workers is not overloaded with
-    // the meaning that it is a switch to disable parallelism and so keeps
-    // the meaning of the number of active gc workers. If parallelism has
-    // not been shut off by setting n_par_threads to 0, then n_par_threads
-    // should be equal to active_workers.  When a different mechanism for
-    // shutting off parallelism is used, then active_workers can be used in
-    // place of n_par_threads.
-    int n_threads =  GenCollectedHeap::heap()->n_par_threads();
-    bool is_par = n_threads > 0;
-    if (is_par) {
+    if (n_threads > 0) {
 #if INCLUDE_ALL_GCS
-      assert(GenCollectedHeap::heap()->n_par_threads() ==
-             GenCollectedHeap::heap()->workers()->active_workers(), "Mismatch");
       non_clean_card_iterate_parallel_work(sp, mr, cl, ct, n_threads);
 #else  // INCLUDE_ALL_GCS
       fatal("Parallel gc not supported here.");
@@ -472,8 +452,11 @@
     } else {
       // clear_cl finds contiguous dirty ranges of cards to process and clear.
 
-      DirtyCardToOopClosure* dcto_cl = sp->new_dcto_cl(cl, precision(), cl->gen_boundary());
-      ClearNoncleanCardWrapper clear_cl(dcto_cl, ct);
+      // This is the single-threaded version used by DefNew.
+      const bool parallel = false;
+
+      DirtyCardToOopClosure* dcto_cl = sp->new_dcto_cl(cl, precision(), cl->gen_boundary(), parallel);
+      ClearNoncleanCardWrapper clear_cl(dcto_cl, ct, parallel);
 
       clear_cl.do_MemRegion(mr);
     }
--- a/hotspot/src/share/vm/gc/shared/cardTableModRefBS.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/cardTableModRefBS.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -178,14 +178,15 @@
   // region mr in the given space and apply cl to any dirty sub-regions
   // of mr. Clears the dirty cards as they are processed.
   void non_clean_card_iterate_possibly_parallel(Space* sp, MemRegion mr,
-                                                OopsInGenClosure* cl, CardTableRS* ct);
+                                                OopsInGenClosure* cl, CardTableRS* ct,
+                                                uint n_threads);
 
  private:
   // Work method used to implement non_clean_card_iterate_possibly_parallel()
   // above in the parallel case.
   void non_clean_card_iterate_parallel_work(Space* sp, MemRegion mr,
                                             OopsInGenClosure* cl, CardTableRS* ct,
-                                            int n_threads);
+                                            uint n_threads);
 
  protected:
   // Dirty the bytes corresponding to "mr" (not all of which must be
--- a/hotspot/src/share/vm/gc/shared/cardTableRS.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/cardTableRS.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -102,9 +102,10 @@
 }
 
 void CardTableRS::younger_refs_iterate(Generation* g,
-                                       OopsInGenClosure* blk) {
+                                       OopsInGenClosure* blk,
+                                       uint n_threads) {
   _last_cur_val_in_gen[g->level()+1] = cur_youngergen_card_val();
-  g->younger_refs_iterate(blk);
+  g->younger_refs_iterate(blk, n_threads);
 }
 
 inline bool ClearNoncleanCardWrapper::clear_card(jbyte* entry) {
@@ -164,15 +165,8 @@
 }
 
 ClearNoncleanCardWrapper::ClearNoncleanCardWrapper(
-  DirtyCardToOopClosure* dirty_card_closure, CardTableRS* ct) :
-    _dirty_card_closure(dirty_card_closure), _ct(ct) {
-    // Cannot yet substitute active_workers for n_par_threads
-    // in the case where parallelism is being turned off by
-    // setting n_par_threads to 0.
-    _is_par = (GenCollectedHeap::heap()->n_par_threads() > 0);
-    assert(!_is_par ||
-           (GenCollectedHeap::heap()->n_par_threads() ==
-            GenCollectedHeap::heap()->workers()->active_workers()), "Mismatch");
+  DirtyCardToOopClosure* dirty_card_closure, CardTableRS* ct, bool is_par) :
+    _dirty_card_closure(dirty_card_closure), _ct(ct), _is_par(is_par) {
 }
 
 bool ClearNoncleanCardWrapper::is_word_aligned(jbyte* entry) {
@@ -272,7 +266,8 @@
 }
 
 void CardTableRS::younger_refs_in_space_iterate(Space* sp,
-                                                OopsInGenClosure* cl) {
+                                                OopsInGenClosure* cl,
+                                                uint n_threads) {
   const MemRegion urasm = sp->used_region_at_save_marks();
 #ifdef ASSERT
   // Convert the assertion check to a warning if we are running
@@ -301,7 +296,7 @@
     ShouldNotReachHere();
   }
 #endif
-  _ct_bs->non_clean_card_iterate_possibly_parallel(sp, urasm, cl, this);
+  _ct_bs->non_clean_card_iterate_possibly_parallel(sp, urasm, cl, this, n_threads);
 }
 
 void CardTableRS::clear_into_younger(Generation* old_gen) {
--- a/hotspot/src/share/vm/gc/shared/cardTableRS.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/cardTableRS.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -56,7 +56,7 @@
 
   CardTableModRefBSForCTRS* _ct_bs;
 
-  virtual void younger_refs_in_space_iterate(Space* sp, OopsInGenClosure* cl);
+  virtual void younger_refs_in_space_iterate(Space* sp, OopsInGenClosure* cl, uint n_threads);
 
   void verify_space(Space* s, HeapWord* gen_start);
 
@@ -116,7 +116,7 @@
   // Card table entries are cleared before application; "blk" is
   // responsible for dirtying if the oop is still older-to-younger after
   // closure application.
-  void younger_refs_iterate(Generation* g, OopsInGenClosure* blk);
+  void younger_refs_iterate(Generation* g, OopsInGenClosure* blk, uint n_threads);
 
   void inline_write_ref_field_gc(void* field, oop new_val) {
     jbyte* byte = _ct_bs->byte_for(field);
@@ -183,7 +183,7 @@
   bool is_word_aligned(jbyte* entry);
 
 public:
-  ClearNoncleanCardWrapper(DirtyCardToOopClosure* dirty_card_closure, CardTableRS* ct);
+  ClearNoncleanCardWrapper(DirtyCardToOopClosure* dirty_card_closure, CardTableRS* ct, bool is_par);
   void do_MemRegion(MemRegion mr);
 };
 
--- a/hotspot/src/share/vm/gc/shared/collectedHeap.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -160,8 +160,7 @@
 // Memory state functions.
 
 
-CollectedHeap::CollectedHeap() : _n_par_threads(0)
-{
+CollectedHeap::CollectedHeap() {
   const size_t max_len = size_t(arrayOopDesc::max_array_length(T_INT));
   const size_t elements_per_word = HeapWordSize / sizeof(jint);
   _filler_array_max_size = align_object_size(filler_array_hdr_size() +
--- a/hotspot/src/share/vm/gc/shared/collectedHeap.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/collectedHeap.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -101,7 +101,6 @@
  protected:
   BarrierSet* _barrier_set;
   bool _is_gc_active;
-  uint _n_par_threads;
 
   unsigned int _total_collections;          // ... started
   unsigned int _total_full_collections;     // ... started
@@ -291,12 +290,6 @@
   }
   GCCause::Cause gc_cause() { return _gc_cause; }
 
-  // Number of threads currently working on GC tasks.
-  uint n_par_threads() { return _n_par_threads; }
-
-  // May be overridden to set additional parallelism.
-  virtual void set_par_threads(uint t) { _n_par_threads = t; };
-
   // General obj/array allocation facilities.
   inline static oop obj_allocate(KlassHandle klass, int size, TRAPS);
   inline static oop array_allocate(KlassHandle klass, int size, int length, TRAPS);
--- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -561,16 +561,6 @@
   return collector_policy()->satisfy_failed_allocation(size, is_tlab);
 }
 
-void GenCollectedHeap::set_par_threads(uint t) {
-  assert(t == 0 || !UseSerialGC, "Cannot have parallel threads");
-  CollectedHeap::set_par_threads(t);
-  set_n_termination(t);
-}
-
-void GenCollectedHeap::set_n_termination(uint t) {
-  _process_strong_tasks->set_n_threads(t);
-}
-
 #ifdef ASSERT
 class AssertNonScavengableClosure: public OopClosure {
 public:
@@ -582,15 +572,13 @@
 static AssertNonScavengableClosure assert_is_non_scavengable_closure;
 #endif
 
-void GenCollectedHeap::process_roots(bool activate_scope,
+void GenCollectedHeap::process_roots(StrongRootsScope* scope,
                                      ScanningOption so,
                                      OopClosure* strong_roots,
                                      OopClosure* weak_roots,
                                      CLDClosure* strong_cld_closure,
                                      CLDClosure* weak_cld_closure,
                                      CodeBlobClosure* code_roots) {
-  StrongRootsScope srs(activate_scope);
-
   // General roots.
   assert(Threads::thread_claim_parity() != 0, "must have called prologue code");
   assert(code_roots != NULL, "code root closure should always be set");
@@ -609,7 +597,7 @@
   // Only process code roots from thread stacks if we aren't visiting the entire CodeCache anyway
   CodeBlobClosure* roots_from_code_p = (so & SO_AllCodeCache) ? NULL : code_roots;
 
-  bool is_par = n_par_threads() > 0;
+  bool is_par = scope->n_threads() > 1;
   Threads::possibly_parallel_oops_do(is_par, strong_roots, roots_from_clds_p, roots_from_code_p);
 
   if (!_process_strong_tasks->is_task_claimed(GCH_PS_Universe_oops_do)) {
@@ -669,9 +657,9 @@
 
 }
 
-void GenCollectedHeap::gen_process_roots(int level,
+void GenCollectedHeap::gen_process_roots(StrongRootsScope* scope,
+                                         int level,
                                          bool younger_gens_as_roots,
-                                         bool activate_scope,
                                          ScanningOption so,
                                          bool only_strong_roots,
                                          OopsInGenClosure* not_older_gens,
@@ -689,7 +677,7 @@
   OopsInGenClosure* weak_roots = only_strong_roots ? NULL : not_older_gens;
   CLDClosure* weak_cld_closure = only_strong_roots ? NULL : cld_closure;
 
-  process_roots(activate_scope, so,
+  process_roots(scope, so,
                 not_older_gens, weak_roots,
                 cld_closure, weak_cld_closure,
                 &mark_code_closure);
@@ -707,11 +695,11 @@
   // older-gen scanning.
   if (level == 0) {
     older_gens->set_generation(_old_gen);
-    rem_set()->younger_refs_iterate(_old_gen, older_gens);
+    rem_set()->younger_refs_iterate(_old_gen, older_gens, scope->n_threads());
     older_gens->reset_generation();
   }
 
-  _process_strong_tasks->all_tasks_completed();
+  _process_strong_tasks->all_tasks_completed(scope->n_threads());
 }
 
 
--- a/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -30,8 +30,9 @@
 #include "gc/shared/collectorPolicy.hpp"
 #include "gc/shared/generation.hpp"
 
+class FlexibleWorkGang;
+class StrongRootsScope;
 class SubTasksDone;
-class FlexibleWorkGang;
 
 // A "GenCollectedHeap" is a CollectedHeap that uses generational
 // collection.  It has two generations, young and old.
@@ -363,9 +364,6 @@
   // asserted to be this type.
   static GenCollectedHeap* heap();
 
-  void set_par_threads(uint t);
-  void set_n_termination(uint t);
-
   // Invoke the "do_oop" method of one of the closures "not_older_gens"
   // or "older_gens" on root locations for the generation at
   // "level".  (The "older_gens" closure is used for scanning references
@@ -385,7 +383,7 @@
   };
 
  private:
-  void process_roots(bool activate_scope,
+  void process_roots(StrongRootsScope* scope,
                      ScanningOption so,
                      OopClosure* strong_roots,
                      OopClosure* weak_roots,
@@ -393,24 +391,13 @@
                      CLDClosure* weak_cld_closure,
                      CodeBlobClosure* code_roots);
 
-  void gen_process_roots(int level,
-                         bool younger_gens_as_roots,
-                         bool activate_scope,
-                         ScanningOption so,
-                         OopsInGenClosure* not_older_gens,
-                         OopsInGenClosure* weak_roots,
-                         OopsInGenClosure* older_gens,
-                         CLDClosure* cld_closure,
-                         CLDClosure* weak_cld_closure,
-                         CodeBlobClosure* code_closure);
-
  public:
   static const bool StrongAndWeakRoots = false;
   static const bool StrongRootsOnly    = true;
 
-  void gen_process_roots(int level,
+  void gen_process_roots(StrongRootsScope* scope,
+                         int level,
                          bool younger_gens_as_roots,
-                         bool activate_scope,
                          ScanningOption so,
                          bool only_strong_roots,
                          OopsInGenClosure* not_older_gens,
--- a/hotspot/src/share/vm/gc/shared/genOopClosures.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/genOopClosures.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -35,11 +35,6 @@
 class DefNewGeneration;
 class KlassRemSet;
 
-template<class E, MEMFLAGS F, unsigned int N> class GenericTaskQueue;
-typedef GenericTaskQueue<oop, mtGC, TASKQUEUE_SIZE> OopTaskQueue;
-template<class T, MEMFLAGS F> class GenericTaskQueueSet;
-typedef GenericTaskQueueSet<OopTaskQueue, mtGC> OopTaskQueueSet;
-
 // Closure for iterating roots from a particular generation
 // Note: all classes deriving from this MUST call this do_barrier
 // method at the end of their own do_oop method!
--- a/hotspot/src/share/vm/gc/shared/genRemSet.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/genRemSet.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -77,10 +77,11 @@
   //  1) that are in objects allocated in "g" at the time of the last call
   //     to "save_Marks", and
   //  2) that point to objects in younger generations.
-  virtual void younger_refs_iterate(Generation* g, OopsInGenClosure* blk) = 0;
+  virtual void younger_refs_iterate(Generation* g, OopsInGenClosure* blk, uint n_threads) = 0;
 
   virtual void younger_refs_in_space_iterate(Space* sp,
-                                             OopsInGenClosure* cl) = 0;
+                                             OopsInGenClosure* cl,
+                                             uint n_threads) = 0;
 
   // This method is used to notify the remembered set that "new_val" has
   // been written into "field" by the garbage collector.
--- a/hotspot/src/share/vm/gc/shared/generation.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/generation.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -293,9 +293,10 @@
 }
 
 void Generation::younger_refs_in_space_iterate(Space* sp,
-                                               OopsInGenClosure* cl) {
+                                               OopsInGenClosure* cl,
+                                               uint n_threads) {
   GenRemSet* rs = GenCollectedHeap::heap()->rem_set();
-  rs->younger_refs_in_space_iterate(sp, cl);
+  rs->younger_refs_in_space_iterate(sp, cl, n_threads);
 }
 
 class GenerationObjIterateClosure : public SpaceClosure {
--- a/hotspot/src/share/vm/gc/shared/generation.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/generation.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -122,7 +122,7 @@
   // The iteration is only over objects allocated at the start of the
   // iterations; objects allocated as a result of applying the closure are
   // not included.
-  void younger_refs_in_space_iterate(Space* sp, OopsInGenClosure* cl);
+  void younger_refs_in_space_iterate(Space* sp, OopsInGenClosure* cl, uint n_threads);
 
  public:
   // The set of possible generation kinds.
@@ -526,7 +526,7 @@
   // in the current generation that contain pointers to objects in younger
   // generations. Objects allocated since the last "save_marks" call are
   // excluded.
-  virtual void younger_refs_iterate(OopsInGenClosure* cl) = 0;
+  virtual void younger_refs_iterate(OopsInGenClosure* cl, uint n_threads) = 0;
 
   // Inform a generation that it longer contains references to objects
   // in any younger generation.    [e.g. Because younger gens are empty,
--- a/hotspot/src/share/vm/gc/shared/space.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/space.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -181,7 +181,8 @@
 
 DirtyCardToOopClosure* Space::new_dcto_cl(ExtendedOopClosure* cl,
                                           CardTableModRefBS::PrecisionStyle precision,
-                                          HeapWord* boundary) {
+                                          HeapWord* boundary,
+                                          bool parallel) {
   return new DirtyCardToOopClosure(this, cl, precision, boundary);
 }
 
@@ -260,7 +261,8 @@
 DirtyCardToOopClosure*
 ContiguousSpace::new_dcto_cl(ExtendedOopClosure* cl,
                              CardTableModRefBS::PrecisionStyle precision,
-                             HeapWord* boundary) {
+                             HeapWord* boundary,
+                             bool parallel) {
   return new ContiguousSpaceDCTOC(this, cl, precision, boundary);
 }
 
--- a/hotspot/src/share/vm/gc/shared/space.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/space.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -183,7 +183,8 @@
   // operate. ResourceArea allocated.
   virtual DirtyCardToOopClosure* new_dcto_cl(ExtendedOopClosure* cl,
                                              CardTableModRefBS::PrecisionStyle precision,
-                                             HeapWord* boundary = NULL);
+                                             HeapWord* boundary,
+                                             bool parallel);
 
   // If "p" is in the space, returns the address of the start of the
   // "block" that contains "p".  We say "block" instead of "object" since
@@ -629,7 +630,8 @@
   // Override.
   DirtyCardToOopClosure* new_dcto_cl(ExtendedOopClosure* cl,
                                      CardTableModRefBS::PrecisionStyle precision,
-                                     HeapWord* boundary = NULL);
+                                     HeapWord* boundary,
+                                     bool parallel);
 
   // Apply "blk->do_oop" to the addresses of all reference fields in objects
   // starting with the _saved_mark_word, which was noted during a generation's
--- a/hotspot/src/share/vm/gc/shared/strongRootsScope.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/strongRootsScope.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -28,24 +28,18 @@
 #include "gc/shared/strongRootsScope.hpp"
 #include "runtime/thread.hpp"
 
-MarkScope::MarkScope(bool activate) : _active(activate) {
-  if (_active) {
-    nmethod::oops_do_marking_prologue();
-  }
+MarkScope::MarkScope() {
+  nmethod::oops_do_marking_prologue();
 }
 
 MarkScope::~MarkScope() {
-  if (_active) {
-    nmethod::oops_do_marking_epilogue();
-  }
+  nmethod::oops_do_marking_epilogue();
 }
 
-StrongRootsScope::StrongRootsScope(bool activate) : MarkScope(activate) {
-  if (_active) {
-    Threads::change_thread_claim_parity();
-    // Zero the claimed high water mark in the StringTable
-    StringTable::clear_parallel_claimed_index();
-  }
+StrongRootsScope::StrongRootsScope(uint n_threads) : _n_threads(n_threads) {
+  Threads::change_thread_claim_parity();
+  // Zero the claimed high water mark in the StringTable
+  StringTable::clear_parallel_claimed_index();
 }
 
 StrongRootsScope::~StrongRootsScope() {
--- a/hotspot/src/share/vm/gc/shared/strongRootsScope.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/strongRootsScope.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -29,18 +29,21 @@
 
 class MarkScope : public StackObj {
  protected:
-  bool _active;
- public:
-  MarkScope(bool activate = true);
+  MarkScope();
   ~MarkScope();
 };
 
 // Sets up and tears down the required state for parallel root processing.
 
 class StrongRootsScope : public MarkScope {
+  // Number of threads participating in the roots processing.
+  const uint _n_threads;
+
  public:
-  StrongRootsScope(bool activate = true);
+  StrongRootsScope(uint n_threads);
   ~StrongRootsScope();
+
+  uint n_threads() const { return _n_threads; }
 };
 
 #endif // SHARE_VM_GC_SHARED_STRONGROOTSSCOPE_HPP
--- a/hotspot/src/share/vm/gc/shared/taskqueue.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/taskqueue.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -382,6 +382,8 @@
   bool steal(uint queue_num, int* seed, E& t);
 
   bool peek();
+
+  uint size() const { return _n; }
 };
 
 template<class T, MEMFLAGS F> void
--- a/hotspot/src/share/vm/gc/shared/workgroup.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/workgroup.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -133,8 +133,6 @@
 }
 
 void WorkGang::run_task(AbstractGangTask* task, uint no_of_parallel_workers) {
-  task->set_for_termination(no_of_parallel_workers);
-
   // This thread is executed by the VM thread which does not block
   // on ordinary MutexLocker's.
   MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
@@ -434,7 +432,7 @@
 // SubTasksDone functions.
 
 SubTasksDone::SubTasksDone(uint n) :
-  _n_tasks(n), _n_threads(1), _tasks(NULL) {
+  _n_tasks(n), _tasks(NULL) {
   _tasks = NEW_C_HEAP_ARRAY(uint, n, mtInternal);
   guarantee(_tasks != NULL, "alloc failure");
   clear();
@@ -444,12 +442,6 @@
   return _tasks != NULL;
 }
 
-void SubTasksDone::set_n_threads(uint t) {
-  assert(_claimed == 0 || _threads_completed == _n_threads,
-         "should not be called while tasks are being processed!");
-  _n_threads = (t == 0 ? 1 : t);
-}
-
 void SubTasksDone::clear() {
   for (uint i = 0; i < _n_tasks; i++) {
     _tasks[i] = 0;
@@ -477,7 +469,7 @@
   return res;
 }
 
-void SubTasksDone::all_tasks_completed() {
+void SubTasksDone::all_tasks_completed(uint n_threads) {
   jint observed = _threads_completed;
   jint old;
   do {
@@ -485,7 +477,10 @@
     observed = Atomic::cmpxchg(old+1, &_threads_completed, old);
   } while (observed != old);
   // If this was the last thread checking in, clear the tasks.
-  if (observed+1 == (jint)_n_threads) clear();
+  uint adjusted_thread_count = (n_threads == 0 ? 1 : n_threads);
+  if (observed + 1 == (jint)adjusted_thread_count) {
+    clear();
+  }
 }
 
 
--- a/hotspot/src/share/vm/gc/shared/workgroup.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/gc/shared/workgroup.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -59,13 +59,6 @@
   // The argument tells you which member of the gang you are.
   virtual void work(uint worker_id) = 0;
 
-  // This method configures the task for proper termination.
-  // Some tasks do not have any requirements on termination
-  // and may inherit this method that does nothing.  Some
-  // tasks do some coordination on termination and override
-  // this method to implement that coordination.
-  virtual void set_for_termination(uint active_workers) {};
-
   // Debugging accessor for the name.
   const char* name() const PRODUCT_RETURN_(return NULL;);
   int counter() { return _counter; }
@@ -99,12 +92,9 @@
   OopTaskQueueSet*       _queues;
   ParallelTaskTerminator _terminator;
  public:
-  AbstractGangTaskWOopQueues(const char* name, OopTaskQueueSet* queues) :
-    AbstractGangTask(name), _queues(queues), _terminator(0, _queues) {}
+  AbstractGangTaskWOopQueues(const char* name, OopTaskQueueSet* queues, uint n_threads) :
+    AbstractGangTask(name), _queues(queues), _terminator(n_threads, _queues) {}
   ParallelTaskTerminator* terminator() { return &_terminator; }
-  virtual void set_for_termination(uint active_workers) {
-    terminator()->reset_for_reuse(active_workers);
-  }
   OopTaskQueueSet* queues() { return _queues; }
 };
 
@@ -315,16 +305,20 @@
   uint _active_workers;
  public:
   // Constructor and destructor.
-  // Initialize active_workers to a minimum value.  Setting it to
-  // the parameter "workers" will initialize it to a maximum
-  // value which is not desirable.
   FlexibleWorkGang(const char* name, uint workers,
                    bool are_GC_task_threads,
                    bool  are_ConcurrentGC_threads) :
     WorkGang(name, workers, are_GC_task_threads, are_ConcurrentGC_threads),
-    _active_workers(UseDynamicNumberOfGCThreads ? 1U : ParallelGCThreads) {}
-  // Accessors for fields
-  virtual uint active_workers() const { return _active_workers; }
+    _active_workers(UseDynamicNumberOfGCThreads ? 1U : workers) {}
+
+  // Accessors for fields.
+  virtual uint active_workers() const {
+    assert(_active_workers <= _total_workers,
+           err_msg("_active_workers: %u > _total_workers: %u", _active_workers, _total_workers));
+    assert(UseDynamicNumberOfGCThreads || _active_workers == _total_workers,
+           "Unless dynamic should use total workers");
+    return _active_workers;
+  }
   void set_active_workers(uint v) {
     assert(v <= _total_workers,
            "Trying to set more workers active than there are");
@@ -390,12 +384,6 @@
 class SubTasksDone: public CHeapObj<mtInternal> {
   uint* _tasks;
   uint _n_tasks;
-  // _n_threads is used to determine when a sub task is done.
-  // It does not control how many threads will execute the subtask
-  // but must be initialized to the number that do execute the task
-  // in order to correctly decide when the subtask is done (all the
-  // threads working on the task have finished).
-  uint _n_threads;
   uint _threads_completed;
 #ifdef ASSERT
   volatile uint _claimed;
@@ -413,11 +401,6 @@
   // True iff the object is in a valid state.
   bool valid();
 
-  // Get/set the number of parallel threads doing the tasks to "t".  Can only
-  // be called before tasks start or after they are complete.
-  uint n_threads() { return _n_threads; }
-  void set_n_threads(uint t);
-
   // Returns "false" if the task "t" is unclaimed, and ensures that task is
   // claimed.  The task "t" is required to be within the range of "this".
   bool is_task_claimed(uint t);
@@ -426,7 +409,9 @@
   // tasks that it will try to claim.  Every thread in the parallel task
   // must execute this.  (When the last thread does so, the task array is
   // cleared.)
-  void all_tasks_completed();
+  //
+  // n_threads - Number of threads executing the sub-tasks.
+  void all_tasks_completed(uint n_threads);
 
   // Destructor.
   ~SubTasksDone();
--- a/hotspot/src/share/vm/memory/iterator.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/memory/iterator.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -381,9 +381,4 @@
   template <class OopClosureType>             static bool do_metadata(OopClosureType* closure);
 };
 
-// Helper to convert the oop iterate macro suffixes into bool values that can be used by template functions.
-#define nvs_nv_to_bool true
-#define nvs_v_to_bool  false
-#define nvs_to_bool(nv_suffix) nvs##nv_suffix##_to_bool
-
 #endif // SHARE_VM_MEMORY_ITERATOR_HPP
--- a/hotspot/src/share/vm/oops/arrayKlass.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/oops/arrayKlass.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -144,4 +144,36 @@
   void oop_verify_on(oop obj, outputStream* st);
 };
 
+// Array oop iteration macros for declarations.
+// Used to generate the declarations in the *ArrayKlass header files.
+
+#define OOP_OOP_ITERATE_DECL_RANGE(OopClosureType, nv_suffix)                                  \
+  int oop_oop_iterate_range##nv_suffix(oop obj, OopClosureType* closure, int start, int end);
+
+#if INCLUDE_ALL_GCS
+// Named NO_BACKWARDS because the definition used by *ArrayKlass isn't reversed, see below.
+#define OOP_OOP_ITERATE_DECL_NO_BACKWARDS(OopClosureType, nv_suffix)           \
+  int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure);
+#endif // INCLUDE_ALL_GCS
+
+
+// Array oop iteration macros for definitions.
+// Used to generate the definitions in the *ArrayKlass.inline.hpp files.
+
+#define OOP_OOP_ITERATE_DEFN_RANGE(KlassType, OopClosureType, nv_suffix)                                 \
+                                                                                                         \
+int KlassType::oop_oop_iterate_range##nv_suffix(oop obj, OopClosureType* closure, int start, int end) {  \
+  return oop_oop_iterate_range<nvs_to_bool(nv_suffix)>(obj, closure, start, end);                        \
+}
+
+#if INCLUDE_ALL_GCS
+#define OOP_OOP_ITERATE_DEFN_NO_BACKWARDS(KlassType, OopClosureType, nv_suffix)          \
+int KlassType::oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) {  \
+  /* No reverse implementation ATM. */                                                   \
+  return oop_oop_iterate<nvs_to_bool(nv_suffix)>(obj, closure);                          \
+}
+#else
+#define OOP_OOP_ITERATE_DEFN_NO_BACKWARDS(KlassType, OopClosureType, nv_suffix)
+#endif
+
 #endif // SHARE_VM_OOPS_ARRAYKLASS_HPP
--- a/hotspot/src/share/vm/oops/instanceClassLoaderKlass.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/oops/instanceClassLoaderKlass.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -87,19 +87,12 @@
 
  public:
 
-#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix)   \
-  int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* blk);                    \
-  int oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* blk, MemRegion mr);
-
-  ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceClassLoaderKlass_OOP_OOP_ITERATE_DECL)
-  ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceClassLoaderKlass_OOP_OOP_ITERATE_DECL)
+  ALL_OOP_OOP_ITERATE_CLOSURES_1(OOP_OOP_ITERATE_DECL)
+  ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_OOP_ITERATE_DECL)
 
 #if INCLUDE_ALL_GCS
-#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix)  \
-  int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* blk);
-
-  ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DECL)
-  ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DECL)
+  ALL_OOP_OOP_ITERATE_CLOSURES_1(OOP_OOP_ITERATE_DECL_BACKWARDS)
+  ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_OOP_ITERATE_DECL_BACKWARDS)
 #endif // INCLUDE_ALL_GCS
 
 };
--- a/hotspot/src/share/vm/oops/instanceClassLoaderKlass.inline.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/oops/instanceClassLoaderKlass.inline.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -78,33 +78,9 @@
   return size;
 }
 
-
-#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix)              \
-                                                                                              \
-int InstanceClassLoaderKlass::oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) {  \
-  return oop_oop_iterate<nvs_to_bool(nv_suffix)>(obj, closure);                               \
-}
-
-#if INCLUDE_ALL_GCS
-#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix)              \
-                                                                                                        \
-int InstanceClassLoaderKlass::oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) {  \
-  return oop_oop_iterate_reverse<nvs_to_bool(nv_suffix)>(obj, closure);                                 \
-}
-#else
-#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix)
-#endif
-
-
-#define InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix)                              \
-                                                                                                                \
-int InstanceClassLoaderKlass::oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, MemRegion mr) {  \
-  return oop_oop_iterate_bounded<nvs_to_bool(nv_suffix)>(obj, closure, mr);                                     \
-}
-
 #define ALL_INSTANCE_CLASS_LOADER_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix)  \
-  InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN(          OopClosureType, nv_suffix)     \
-  InstanceClassLoaderKlass_OOP_OOP_ITERATE_DEFN_m(        OopClosureType, nv_suffix)     \
-  InstanceClassLoaderKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix)
+  OOP_OOP_ITERATE_DEFN(          InstanceClassLoaderKlass, OopClosureType, nv_suffix)    \
+  OOP_OOP_ITERATE_DEFN_BOUNDED(  InstanceClassLoaderKlass, OopClosureType, nv_suffix)    \
+  OOP_OOP_ITERATE_DEFN_BACKWARDS(InstanceClassLoaderKlass, OopClosureType, nv_suffix)
 
 #endif // SHARE_VM_OOPS_INSTANCECLASSLOADERKLASS_INLINE_HPP
--- a/hotspot/src/share/vm/oops/instanceKlass.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/oops/instanceKlass.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -1084,19 +1084,12 @@
 
  public:
 
-#define InstanceKlass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix)                   \
-  int  oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure);                    \
-  int  oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, MemRegion mr);
-
-  ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceKlass_OOP_OOP_ITERATE_DECL)
-  ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceKlass_OOP_OOP_ITERATE_DECL)
+  ALL_OOP_OOP_ITERATE_CLOSURES_1(OOP_OOP_ITERATE_DECL)
+  ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_OOP_ITERATE_DECL)
 
 #if INCLUDE_ALL_GCS
-#define InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix)  \
-  int  oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure);
-
-  ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DECL)
-  ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DECL)
+  ALL_OOP_OOP_ITERATE_CLOSURES_1(OOP_OOP_ITERATE_DECL_BACKWARDS)
+  ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_OOP_ITERATE_DECL_BACKWARDS)
 #endif // INCLUDE_ALL_GCS
 
   u2 idnum_allocated_count() const      { return _idnum_allocated_count; }
--- a/hotspot/src/share/vm/oops/instanceKlass.inline.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/oops/instanceKlass.inline.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -27,6 +27,7 @@
 
 #include "memory/iterator.hpp"
 #include "oops/instanceKlass.hpp"
+#include "oops/klass.hpp"
 #include "oops/oop.inline.hpp"
 #include "utilities/debug.hpp"
 #include "utilities/globalDefinitions.hpp"
@@ -187,29 +188,9 @@
 
 #undef INLINE
 
-
-#define InstanceKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix)              \
-int InstanceKlass::oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) {  \
-  return oop_oop_iterate<nvs_to_bool(nv_suffix)>(obj, closure);                    \
-}
-
-#if INCLUDE_ALL_GCS
-#define InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix)              \
-int InstanceKlass::oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) {  \
-  return oop_oop_iterate_reverse<nvs_to_bool(nv_suffix)>(obj, closure);                      \
-}
-#else
-#define InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix)
-#endif
-
-#define InstanceKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix)                              \
-int InstanceKlass::oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, MemRegion mr) {  \
-  return oop_oop_iterate_bounded<nvs_to_bool(nv_suffix)>(obj, closure, mr);                          \
-}
-
 #define ALL_INSTANCE_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix)  \
-  InstanceKlass_OOP_OOP_ITERATE_DEFN(          OopClosureType, nv_suffix)   \
-  InstanceKlass_OOP_OOP_ITERATE_DEFN_m(        OopClosureType, nv_suffix)   \
-  InstanceKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix)
+  OOP_OOP_ITERATE_DEFN(          InstanceKlass, OopClosureType, nv_suffix)  \
+  OOP_OOP_ITERATE_DEFN_BOUNDED(  InstanceKlass, OopClosureType, nv_suffix)  \
+  OOP_OOP_ITERATE_DEFN_BACKWARDS(InstanceKlass, OopClosureType, nv_suffix)
 
 #endif // SHARE_VM_OOPS_INSTANCEKLASS_INLINE_HPP
--- a/hotspot/src/share/vm/oops/instanceMirrorKlass.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/oops/instanceMirrorKlass.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -149,19 +149,12 @@
 
  public:
 
-#define InstanceMirrorKlass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix)           \
-  int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* blk);                       \
-  int oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* blk, MemRegion mr);
-
-  ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceMirrorKlass_OOP_OOP_ITERATE_DECL)
-  ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceMirrorKlass_OOP_OOP_ITERATE_DECL)
+  ALL_OOP_OOP_ITERATE_CLOSURES_1(OOP_OOP_ITERATE_DECL)
+  ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_OOP_ITERATE_DECL)
 
 #if INCLUDE_ALL_GCS
-#define InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \
-  int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* blk);
-
-  ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DECL)
-  ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DECL)
+  ALL_OOP_OOP_ITERATE_CLOSURES_1(OOP_OOP_ITERATE_DECL_BACKWARDS)
+  ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_OOP_ITERATE_DECL_BACKWARDS)
 #endif // INCLUDE_ALL_GCS
 };
 
--- a/hotspot/src/share/vm/oops/instanceMirrorKlass.inline.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/oops/instanceMirrorKlass.inline.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -27,6 +27,7 @@
 #include "classfile/javaClasses.hpp"
 #include "oops/instanceKlass.inline.hpp"
 #include "oops/instanceMirrorKlass.hpp"
+#include "oops/klass.hpp"
 #include "oops/oop.inline.hpp"
 #include "utilities/debug.hpp"
 #include "utilities/globalDefinitions.hpp"
@@ -132,33 +133,9 @@
   return oop_size(obj);
 }
 
-
-#define InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix)              \
-                                                                                         \
-int InstanceMirrorKlass::oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) {  \
-  return oop_oop_iterate<nvs_to_bool(nv_suffix)>(obj, closure);                          \
-}
-
-#if INCLUDE_ALL_GCS
-#define InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix)              \
-                                                                                                   \
-int InstanceMirrorKlass::oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) {  \
-  return oop_oop_iterate_reverse<nvs_to_bool(nv_suffix)>(obj, closure);                            \
-}
-#else
-#define InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix)
-#endif
-
-
-#define InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix)                              \
-                                                                                                           \
-int InstanceMirrorKlass::oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, MemRegion mr) {  \
-  return oop_oop_iterate_bounded<nvs_to_bool(nv_suffix)>(obj, closure, mr);                                \
-}
-
 #define ALL_INSTANCE_MIRROR_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix)  \
-  InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN(          OopClosureType, nv_suffix)    \
-  InstanceMirrorKlass_OOP_OOP_ITERATE_DEFN_m(        OopClosureType, nv_suffix)    \
-  InstanceMirrorKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix)
+  OOP_OOP_ITERATE_DEFN(          InstanceMirrorKlass, OopClosureType, nv_suffix)   \
+  OOP_OOP_ITERATE_DEFN_BOUNDED(  InstanceMirrorKlass, OopClosureType, nv_suffix)   \
+  OOP_OOP_ITERATE_DEFN_BACKWARDS(InstanceMirrorKlass, OopClosureType, nv_suffix)
 
 #endif // SHARE_VM_OOPS_INSTANCEMIRRORKLASS_INLINE_HPP
--- a/hotspot/src/share/vm/oops/instanceRefKlass.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/oops/instanceRefKlass.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -119,19 +119,12 @@
 
  public:
 
-#define InstanceRefKlass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix)               \
-  int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure);                    \
-  int oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, MemRegion mr);
-
-  ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceRefKlass_OOP_OOP_ITERATE_DECL)
-  ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceRefKlass_OOP_OOP_ITERATE_DECL)
+  ALL_OOP_OOP_ITERATE_CLOSURES_1(OOP_OOP_ITERATE_DECL)
+  ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_OOP_ITERATE_DECL)
 
 #if INCLUDE_ALL_GCS
-#define InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix)     \
-  int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure);
-
-  ALL_OOP_OOP_ITERATE_CLOSURES_1(InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DECL)
-  ALL_OOP_OOP_ITERATE_CLOSURES_2(InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DECL)
+  ALL_OOP_OOP_ITERATE_CLOSURES_1(OOP_OOP_ITERATE_DECL_BACKWARDS)
+  ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_OOP_ITERATE_DECL_BACKWARDS)
 #endif // INCLUDE_ALL_GCS
 
   static void release_and_notify_pending_list_lock(BasicLock *pending_list_basic_lock);
--- a/hotspot/src/share/vm/oops/instanceRefKlass.inline.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/oops/instanceRefKlass.inline.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -141,34 +141,9 @@
 
 // Macro to define InstanceRefKlass::oop_oop_iterate for virtual/nonvirtual for
 // all closures.  Macros calling macros above for each oop size.
-
-#define InstanceRefKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix)              \
-                                                                                      \
-int InstanceRefKlass::oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) {  \
-  return oop_oop_iterate<nvs_to_bool(nv_suffix)>(obj, closure);                       \
-}
-
-#if INCLUDE_ALL_GCS
-#define InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix)              \
-                                                                                                \
-int InstanceRefKlass::oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) {  \
-  return oop_oop_iterate_reverse<nvs_to_bool(nv_suffix)>(obj, closure);                         \
-}
-#else
-#define InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix)
-#endif
-
-
-#define InstanceRefKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix)                              \
-                                                                                                        \
-int InstanceRefKlass::oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, MemRegion mr) {  \
-  return oop_oop_iterate_bounded<nvs_to_bool(nv_suffix)>(obj, closure, mr);                             \
-}
-
 #define ALL_INSTANCE_REF_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix)  \
-  InstanceRefKlass_OOP_OOP_ITERATE_DEFN(          OopClosureType, nv_suffix)    \
-  InstanceRefKlass_OOP_OOP_ITERATE_DEFN_m(        OopClosureType, nv_suffix)    \
-  InstanceRefKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix)
-
+  OOP_OOP_ITERATE_DEFN(          InstanceRefKlass, OopClosureType, nv_suffix)   \
+  OOP_OOP_ITERATE_DEFN_BOUNDED(  InstanceRefKlass, OopClosureType, nv_suffix)   \
+  OOP_OOP_ITERATE_DEFN_BACKWARDS(InstanceRefKlass, OopClosureType, nv_suffix)
 
 #endif // SHARE_VM_OOPS_INSTANCEREFKLASS_INLINE_HPP
--- a/hotspot/src/share/vm/oops/klass.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/oops/klass.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -583,20 +583,20 @@
 
   // Iterators specialized to particular subtypes
   // of ExtendedOopClosure, to avoid closure virtual calls.
-#define Klass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix)                                      \
-  virtual int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) = 0;                    \
-  /* Iterates "closure" over all the oops in "obj" (of type "this") within "mr". */                \
-  virtual int oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, MemRegion mr) = 0;
+#define Klass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix)                                          \
+  virtual int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) = 0;                        \
+  /* Iterates "closure" over all the oops in "obj" (of type "this") within "mr". */                    \
+  virtual int oop_oop_iterate_bounded##nv_suffix(oop obj, OopClosureType* closure, MemRegion mr) = 0;
 
   ALL_OOP_OOP_ITERATE_CLOSURES_1(Klass_OOP_OOP_ITERATE_DECL)
   ALL_OOP_OOP_ITERATE_CLOSURES_2(Klass_OOP_OOP_ITERATE_DECL)
 
 #if INCLUDE_ALL_GCS
-#define Klass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix)                    \
+#define Klass_OOP_OOP_ITERATE_DECL_BACKWARDS(OopClosureType, nv_suffix)                    \
   virtual int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) = 0;
 
-  ALL_OOP_OOP_ITERATE_CLOSURES_1(Klass_OOP_OOP_ITERATE_BACKWARDS_DECL)
-  ALL_OOP_OOP_ITERATE_CLOSURES_2(Klass_OOP_OOP_ITERATE_BACKWARDS_DECL)
+  ALL_OOP_OOP_ITERATE_CLOSURES_1(Klass_OOP_OOP_ITERATE_DECL_BACKWARDS)
+  ALL_OOP_OOP_ITERATE_CLOSURES_2(Klass_OOP_OOP_ITERATE_DECL_BACKWARDS)
 #endif // INCLUDE_ALL_GCS
 
   virtual void array_klasses_do(void f(Klass* k)) {}
@@ -651,4 +651,44 @@
   void klass_update_barrier_set_pre(oop* p, oop v);
 };
 
+// Helper to convert the oop iterate macro suffixes into bool values that can be used by template functions.
+#define nvs_nv_to_bool true
+#define nvs_v_to_bool  false
+#define nvs_to_bool(nv_suffix) nvs##nv_suffix##_to_bool
+
+// Oop iteration macros for declarations.
+// Used to generate declarations in the *Klass header files.
+
+#define OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix)                                    \
+  int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure);                        \
+  int oop_oop_iterate_bounded##nv_suffix(oop obj, OopClosureType* closure, MemRegion mr);
+
+#if INCLUDE_ALL_GCS
+#define OOP_OOP_ITERATE_DECL_BACKWARDS(OopClosureType, nv_suffix)              \
+  int oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure);
+#endif // INCLUDE_ALL_GCS
+
+
+// Oop iteration macros for definitions.
+// Used to generate definitions in the *Klass.inline.hpp files.
+
+#define OOP_OOP_ITERATE_DEFN(KlassType, OopClosureType, nv_suffix)             \
+int KlassType::oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) {  \
+  return oop_oop_iterate<nvs_to_bool(nv_suffix)>(obj, closure);                \
+}
+
+#if INCLUDE_ALL_GCS
+#define OOP_OOP_ITERATE_DEFN_BACKWARDS(KlassType, OopClosureType, nv_suffix)             \
+int KlassType::oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) {  \
+  return oop_oop_iterate_reverse<nvs_to_bool(nv_suffix)>(obj, closure);                  \
+}
+#else
+#define OOP_OOP_ITERATE_DEFN_BACKWARDS(KlassType, OopClosureType, nv_suffix)
+#endif
+
+#define OOP_OOP_ITERATE_DEFN_BOUNDED(KlassType, OopClosureType, nv_suffix)                           \
+int KlassType::oop_oop_iterate_bounded##nv_suffix(oop obj, OopClosureType* closure, MemRegion mr) {  \
+  return oop_oop_iterate_bounded<nvs_to_bool(nv_suffix)>(obj, closure, mr);                          \
+}
+
 #endif // SHARE_VM_OOPS_KLASS_HPP
--- a/hotspot/src/share/vm/oops/objArrayKlass.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/oops/objArrayKlass.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -163,22 +163,14 @@
 
  public:
 
-#define ObjArrayKlass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix)   \
-  int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* blk);         \
-  int oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* blk,      \
-                                     MemRegion mr);                     \
-  int oop_oop_iterate_range##nv_suffix(oop obj, OopClosureType* blk,    \
-                                     int start, int end);
-
-  ALL_OOP_OOP_ITERATE_CLOSURES_1(ObjArrayKlass_OOP_OOP_ITERATE_DECL)
-  ALL_OOP_OOP_ITERATE_CLOSURES_2(ObjArrayKlass_OOP_OOP_ITERATE_DECL)
+  ALL_OOP_OOP_ITERATE_CLOSURES_1(OOP_OOP_ITERATE_DECL)
+  ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_OOP_ITERATE_DECL)
+  ALL_OOP_OOP_ITERATE_CLOSURES_1(OOP_OOP_ITERATE_DECL_RANGE)
+  ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_OOP_ITERATE_DECL_RANGE)
 
 #if INCLUDE_ALL_GCS
-#define ObjArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix) \
-  int  oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* blk);
-
-  ALL_OOP_OOP_ITERATE_CLOSURES_1(ObjArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DECL)
-  ALL_OOP_OOP_ITERATE_CLOSURES_2(ObjArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DECL)
+  ALL_OOP_OOP_ITERATE_CLOSURES_1(OOP_OOP_ITERATE_DECL_NO_BACKWARDS)
+  ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_OOP_ITERATE_DECL_NO_BACKWARDS)
 #endif // INCLUDE_ALL_GCS
 
   // JVM support
--- a/hotspot/src/share/vm/oops/objArrayKlass.inline.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/oops/objArrayKlass.inline.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -27,6 +27,8 @@
 
 #include "memory/memRegion.hpp"
 #include "memory/iterator.inline.hpp"
+#include "oops/arrayKlass.hpp"
+#include "oops/klass.hpp"
 #include "oops/objArrayKlass.hpp"
 #include "oops/objArrayOop.inline.hpp"
 #include "oops/oop.inline.hpp"
@@ -149,41 +151,10 @@
   return size;
 }
 
-
-#define ObjArrayKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix)              \
-                                                                                   \
-int ObjArrayKlass::oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) {  \
-  return oop_oop_iterate<nvs_to_bool(nv_suffix)>(obj, closure);                    \
-}
-
-#if INCLUDE_ALL_GCS
-#define ObjArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix)              \
-int ObjArrayKlass::oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) {  \
-  /* No reverse implementation ATM. */                                                       \
-  return oop_oop_iterate<nvs_to_bool(nv_suffix)>(obj, closure);                              \
-}
-#else
-#define ObjArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix)
-#endif
-
-#define ObjArrayKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix)                              \
-                                                                                                     \
-int ObjArrayKlass::oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, MemRegion mr) {  \
-  return oop_oop_iterate_bounded<nvs_to_bool(nv_suffix)>(obj, closure, mr);                          \
-}
-
-#define ObjArrayKlass_OOP_OOP_ITERATE_DEFN_r(OopClosureType, nv_suffix)                                      \
-                                                                                                             \
-int ObjArrayKlass::oop_oop_iterate_range##nv_suffix(oop obj, OopClosureType* closure, int start, int end) {  \
-  return oop_oop_iterate_range<nvs_to_bool(nv_suffix)>(obj, closure, start, end);                            \
-}
-
-
-#define ALL_OBJ_ARRAY_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix)  \
-  ObjArrayKlass_OOP_OOP_ITERATE_DEFN(          OopClosureType, nv_suffix)    \
-  ObjArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix)    \
-  ObjArrayKlass_OOP_OOP_ITERATE_DEFN_m(        OopClosureType, nv_suffix)    \
-  ObjArrayKlass_OOP_OOP_ITERATE_DEFN_r(        OopClosureType, nv_suffix)
-
+#define ALL_OBJ_ARRAY_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix)    \
+  OOP_OOP_ITERATE_DEFN(             ObjArrayKlass, OopClosureType, nv_suffix)  \
+  OOP_OOP_ITERATE_DEFN_BOUNDED(     ObjArrayKlass, OopClosureType, nv_suffix)  \
+  OOP_OOP_ITERATE_DEFN_RANGE(       ObjArrayKlass, OopClosureType, nv_suffix)  \
+  OOP_OOP_ITERATE_DEFN_NO_BACKWARDS(ObjArrayKlass, OopClosureType, nv_suffix)
 
 #endif // SHARE_VM_OOPS_OBJARRAYKLASS_INLINE_HPP
--- a/hotspot/src/share/vm/oops/oop.inline.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/oops/oop.inline.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -741,7 +741,7 @@
 }                                                                     \
                                                                       \
 inline int oopDesc::oop_iterate(OopClosureType* blk, MemRegion mr) {  \
-  return klass()->oop_oop_iterate##nv_suffix##_m(this, blk, mr);      \
+  return klass()->oop_oop_iterate_bounded##nv_suffix(this, blk, mr);  \
 }
 
 
--- a/hotspot/src/share/vm/oops/typeArrayKlass.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/oops/typeArrayKlass.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -92,24 +92,24 @@
   // The implementation used by all oop_oop_iterate functions in TypeArrayKlasses.
   inline int oop_oop_iterate_impl(oop obj, ExtendedOopClosure* closure);
 
+  // Wraps oop_oop_iterate_impl to conform to macros.
+  template <bool nv, typename OopClosureType>
+  inline int oop_oop_iterate(oop obj, OopClosureType* closure);
+
+  // Wraps oop_oop_iterate_impl to conform to macros.
+  template <bool nv, typename OopClosureType>
+  inline int oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr);
+
  public:
 
-#define TypeArrayKlass_OOP_OOP_ITERATE_DECL(OopClosureType, nv_suffix)    \
-  int oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure);       \
-  int oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure,    \
-                                     MemRegion mr);                       \
-  int oop_oop_iterate_range##nv_suffix(oop obj, OopClosureType* closure,  \
-                                     int start, int end);
-
-  ALL_OOP_OOP_ITERATE_CLOSURES_1(TypeArrayKlass_OOP_OOP_ITERATE_DECL)
-  ALL_OOP_OOP_ITERATE_CLOSURES_2(TypeArrayKlass_OOP_OOP_ITERATE_DECL)
+  ALL_OOP_OOP_ITERATE_CLOSURES_1(OOP_OOP_ITERATE_DECL)
+  ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_OOP_ITERATE_DECL)
+  ALL_OOP_OOP_ITERATE_CLOSURES_1(OOP_OOP_ITERATE_DECL_RANGE)
+  ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_OOP_ITERATE_DECL_RANGE)
 
 #if INCLUDE_ALL_GCS
-#define TypeArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DECL(OopClosureType, nv_suffix)  \
-  int  oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure);
-
-  ALL_OOP_OOP_ITERATE_CLOSURES_1(TypeArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DECL)
-  ALL_OOP_OOP_ITERATE_CLOSURES_2(TypeArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DECL)
+  ALL_OOP_OOP_ITERATE_CLOSURES_1(OOP_OOP_ITERATE_DECL_NO_BACKWARDS)
+  ALL_OOP_OOP_ITERATE_CLOSURES_2(OOP_OOP_ITERATE_DECL_NO_BACKWARDS)
 #endif // INCLUDE_ALL_GCS
 
 
--- a/hotspot/src/share/vm/oops/typeArrayKlass.inline.hpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/oops/typeArrayKlass.inline.hpp	Wed Jul 05 20:37:09 2017 +0200
@@ -25,6 +25,8 @@
 #ifndef SHARE_VM_OOPS_TYPEARRAYKLASS_INLINE_HPP
 #define SHARE_VM_OOPS_TYPEARRAYKLASS_INLINE_HPP
 
+#include "oops/arrayKlass.hpp"
+#include "oops/klass.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/typeArrayKlass.hpp"
 #include "oops/typeArrayOop.hpp"
@@ -39,35 +41,19 @@
   return t->object_size();
 }
 
-#define TypeArrayKlass_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix)  \
-                                                                        \
-int TypeArrayKlass::                                                    \
-oop_oop_iterate##nv_suffix(oop obj, OopClosureType* closure) {          \
-  return oop_oop_iterate_impl(obj, closure);                            \
+template <bool nv, typename OopClosureType>
+int TypeArrayKlass::oop_oop_iterate(oop obj, OopClosureType* closure) {
+  return oop_oop_iterate_impl(obj, closure);
 }
 
-#if INCLUDE_ALL_GCS
-#define TypeArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix)  \
-                                                                                  \
-int TypeArrayKlass::                                                              \
-oop_oop_iterate_backwards##nv_suffix(oop obj, OopClosureType* closure) {          \
-  return oop_oop_iterate_impl(obj, closure);                                      \
-}
-#else
-#define TypeArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix)
-#endif
-
-
-#define TypeArrayKlass_OOP_OOP_ITERATE_DEFN_m(OopClosureType, nv_suffix)          \
-                                                                                  \
-int TypeArrayKlass::                                                              \
-oop_oop_iterate##nv_suffix##_m(oop obj, OopClosureType* closure, MemRegion mr) {  \
-  return oop_oop_iterate_impl(obj, closure);                                      \
+template <bool nv, typename OopClosureType>
+int TypeArrayKlass::oop_oop_iterate_bounded(oop obj, OopClosureType* closure, MemRegion mr) {
+  return oop_oop_iterate_impl(obj, closure);
 }
 
-#define ALL_TYPE_ARRAY_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix)  \
-  TypeArrayKlass_OOP_OOP_ITERATE_DEFN(          OopClosureType, nv_suffix)    \
-  TypeArrayKlass_OOP_OOP_ITERATE_DEFN_m(        OopClosureType, nv_suffix)    \
-  TypeArrayKlass_OOP_OOP_ITERATE_BACKWARDS_DEFN(OopClosureType, nv_suffix)
+#define ALL_TYPE_ARRAY_KLASS_OOP_OOP_ITERATE_DEFN(OopClosureType, nv_suffix)    \
+  OOP_OOP_ITERATE_DEFN(             TypeArrayKlass, OopClosureType, nv_suffix)  \
+  OOP_OOP_ITERATE_DEFN_BOUNDED(     TypeArrayKlass, OopClosureType, nv_suffix)  \
+  OOP_OOP_ITERATE_DEFN_NO_BACKWARDS(TypeArrayKlass, OopClosureType, nv_suffix)
 
 #endif // SHARE_VM_OOPS_TYPEARRAYKLASS_INLINE_HPP
--- a/hotspot/src/share/vm/runtime/arguments.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/runtime/arguments.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -1278,10 +1278,8 @@
 
   // Preferred young gen size for "short" pauses:
   // upper bound depends on # of threads and NewRatio.
-  const uintx parallel_gc_threads =
-    (ParallelGCThreads == 0 ? 1 : ParallelGCThreads);
   const size_t preferred_max_new_size_unaligned =
-    MIN2(max_heap/(NewRatio+1), ScaleForWordSize(young_gen_per_worker * parallel_gc_threads));
+    MIN2(max_heap/(NewRatio+1), ScaleForWordSize(young_gen_per_worker * ParallelGCThreads));
   size_t preferred_max_new_size =
     align_size_up(preferred_max_new_size_unaligned, os::vm_page_size());
 
--- a/hotspot/src/share/vm/utilities/elfFile.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/src/share/vm/utilities/elfFile.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -261,7 +261,12 @@
       }
     }
   }
+// AARCH64 defaults to noexecstack. All others default to execstack.
+#ifdef AARCH64
+  return true;
+#else
   return false;
+#endif
 }
 #endif
 
--- a/hotspot/test/compiler/stable/StableConfiguration.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/hotspot/test/compiler/stable/StableConfiguration.java	Wed Jul 05 20:37:09 2017 +0200
@@ -41,10 +41,32 @@
         System.out.println("Server Compiler: " + get());
     }
 
+    // The method 'get' below returns true if the method is server compiled
+    // and is used by the Stable tests to determine whether methods in
+    // general are being server compiled or not as the -XX:+FoldStableValues
+    // option is only applicable to -server.
+    //
+    // On aarch64 we DeOptimize when patching. This means that when the
+    // method is compiled as a result of -Xcomp it DeOptimizes immediately.
+    // The result is that getMethodCompilationLevel returns 0. This means
+    // the method returns true based on java.vm.name.
+    //
+    // However when the tests are run with -XX:+TieredCompilation and
+    // -XX:TieredStopAtLevel=1 this fails because methods will always
+    // be client compiled.
+    //
+    // Solution is to add a simple method 'get1' which should never be
+    // DeOpted and use that to determine the compilation level instead.
+    static void get1() {
+    }
+
+
+
     // ::get() is among immediately compiled methods.
     static boolean get() {
         try {
-            Method m = StableConfiguration.class.getDeclaredMethod("get");
+            get1();
+            Method m = StableConfiguration.class.getDeclaredMethod("get1");
             int level = WB.getMethodCompilationLevel(m);
             if (level > 0) {
               return (level == 4);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/sa/TestClassLoaderStats.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import jdk.test.lib.Platform;
+import jdk.test.lib.ProcessTools;
+import jdk.test.lib.OutputAnalyzer;
+
+/*
+ * @test
+ * @library /testlibrary
+ * @build jdk.test.lib.*
+ * @run main TestClassLoaderStats
+ */
+public class TestClassLoaderStats {
+
+    public static void main(String[] args) throws Exception {
+        if (!Platform.shouldSAAttach()) {
+            System.out.println("SA attach not expected to work - test skipped.");
+            return;
+        }
+
+        ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder(
+                "-XX:+UsePerfData",
+                "sun.jvm.hotspot.tools.ClassLoaderStats",
+                Integer.toString(ProcessTools.getProcessId()));
+        OutputAnalyzer output = ProcessTools.executeProcess(processBuilder);
+        System.out.println(output.getOutput());
+
+        output.shouldHaveExitValue(0);
+        output.shouldContain("Debugger attached successfully.");
+        // The class loader stats header needs to be presented in the output:
+        output.shouldMatch("class_loader\\W+classes\\W+bytes\\W+parent_loader\\W+alive?\\W+type");
+        output.stderrShouldNotMatch("[E|e]xception");
+        output.stderrShouldNotMatch("[E|e]rror");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/sa/TestStackTrace.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import jdk.test.lib.OutputAnalyzer;
+import jdk.test.lib.Platform;
+import jdk.test.lib.ProcessTools;
+
+/*
+ * @test
+ * @library /testlibrary
+ * @build jdk.test.lib.*
+ * @run main TestStackTrace
+ */
+public class TestStackTrace {
+
+    public static void main(String[] args) throws Exception {
+        if (!Platform.shouldSAAttach()) {
+            System.out.println("SA attach not expected to work - test skipped.");
+            return;
+        }
+
+        ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder(
+                "-XX:+UsePerfData",
+                "sun.jvm.hotspot.tools.StackTrace",
+                Integer.toString(ProcessTools.getProcessId()));
+        OutputAnalyzer output = ProcessTools.executeProcess(processBuilder);
+        System.out.println(output.getOutput());
+
+        output.shouldHaveExitValue(0);
+        output.shouldContain("Debugger attached successfully.");
+        output.stderrShouldNotMatch("[E|e]xception");
+        output.stderrShouldNotMatch("[E|e]rror");
+     }
+
+}
--- a/jaxp/.hgtags	Thu Jun 04 18:50:30 2015 -0700
+++ b/jaxp/.hgtags	Wed Jul 05 20:37:09 2017 +0200
@@ -309,3 +309,4 @@
 6f91749b5aaef1a171ec2254163233438d1071d1 jdk9-b64
 ae7406e82828fe1c245ac7507a9da5fd5b1c9529 jdk9-b65
 d5963ccce28d7a3e96ee3e2dc8a8676e61699b70 jdk9-b66
+78c2685daabafae827c686ca2d1bb2e451faed2b jdk9-b67
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/dtm/ref/DTMNodeProxy.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/dtm/ref/DTMNodeProxy.java	Wed Jul 05 20:37:09 2017 +0200
@@ -2116,7 +2116,7 @@
      */
     @Override
     public String getTextContent() throws DOMException {
-        return getNodeValue();  // overriden in some subclasses
+        return dtm.getStringValue(node).toString();
     }
 
      /**
--- a/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/dtm/ref/sax2dtm/SAX2DTM2.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/dtm/ref/sax2dtm/SAX2DTM2.java	Wed Jul 05 20:37:09 2017 +0200
@@ -3145,11 +3145,7 @@
                                   m_data.elementAt(-dataIndex+1));
       }
     }
-    else if (DTM.ELEMENT_NODE == type)
-    {
-      return getStringValueX(nodeHandle);
-    }
-    else if (DTM.DOCUMENT_FRAGMENT_NODE == type
+    else if (DTM.ELEMENT_NODE == type || DTM.DOCUMENT_FRAGMENT_NODE == type
              || DTM.DOCUMENT_NODE == type)
     {
       return null;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/ProblemList.txt	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,26 @@
+###########################################################################
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+###########################################################################
+
+# No jaxp tests are on the problem list.
--- a/jaxp/test/TEST.ROOT	Thu Jun 04 18:50:30 2015 -0700
+++ b/jaxp/test/TEST.ROOT	Wed Jul 05 20:37:09 2017 +0200
@@ -1,8 +1,21 @@
 # This file identifies the root of the test-suite hierarchy.
 # It also contains test-suite configuration information.
 
+# The list of keywords supported in the entire test suite.  The
+# "intermittent" keyword marks tests known to fail intermittently.
+# The "randomness" keyword marks tests using randomness with test
+# cases differing from run to run. (A test using a fixed random seed
+# would not count as "randomness" by this definition.) Extra care
+# should be taken to handle test failures of intermittent or
+# randomness tests.
+
+keys=intermittent randomness
+
 # Tests that must run in othervm mode
 othervm.dirs=javax/xml/jaxp
 
 # Group definitions
 groups=TEST.groups 
+
+# Minimum jtreg version
+requiredVersion=4.1 b11
--- a/jaxp/test/TEST.groups	Thu Jun 04 18:50:30 2015 -0700
+++ b/jaxp/test/TEST.groups	Wed Jul 05 20:37:09 2017 +0200
@@ -1,4 +1,4 @@
-#  Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+#  Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
 #  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 #  This code is free software; you can redistribute it and/or modify it
@@ -20,5 +20,14 @@
 #  questions.
 #
 
+# Tiered testing definitions
+
+# No jaxp tests are tier 1.
+tier1 = 
+
+# All jaxp tests are tier 2.
+tier2 = \
+    :jaxp_all
+
 jaxp_all = \
     javax/xml/jaxp
--- a/jaxp/test/javax/xml/jaxp/unittest/javax/xml/transform/DocumentExtFunc.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jaxp/test/javax/xml/jaxp/unittest/javax/xml/transform/DocumentExtFunc.java	Wed Jul 05 20:37:09 2017 +0200
@@ -30,6 +30,6 @@
 
     public static String test(NodeList list) {
         Node node = list.item(0);
-        return "["+node.getNodeName() + ":" + node.getNodeValue()+"]";
+        return "["+node.getNodeName() + ":" + node.getTextContent()+"]";
     }
 }
--- a/jaxws/.hgtags	Thu Jun 04 18:50:30 2015 -0700
+++ b/jaxws/.hgtags	Wed Jul 05 20:37:09 2017 +0200
@@ -312,3 +312,4 @@
 df100399ed27d0eaa57c137ca99819a0fee66178 jdk9-b64
 45ef73bb85c12ec1b291835c1d40e342a454e3f0 jdk9-b65
 1232f4013417e4a9cd291096798d10f2e601d69d jdk9-b66
+c9785bc8ade98a16a050d7520b70c68363857e00 jdk9-b67
--- a/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/assembler/MetroConfigLoader.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/assembler/MetroConfigLoader.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -41,6 +41,8 @@
 import javax.xml.bind.Unmarshaller;
 import javax.xml.stream.XMLInputFactory;
 import javax.xml.ws.WebServiceException;
+import java.io.IOException;
+import java.io.InputStream;
 import java.lang.reflect.Method;
 import java.net.MalformedURLException;
 import java.net.URI;
@@ -64,6 +66,7 @@
 // TODO Move the logic of this class directly into MetroConfig class.
 class MetroConfigLoader {
 
+    private static final String JAXWS_TUBES_JDK_XML_RESOURCE = "jaxws-tubes-default.xml";
     private static final Logger LOGGER = Logger.getLogger(MetroConfigLoader.class);
 
     private MetroConfigName defaultTubesConfigNames;
@@ -122,11 +125,10 @@
             defaultFileName = defaultTubesConfigNames.getDefaultFileName();
         }
         this.defaultConfigUrl = locateResource(defaultFileName, loaders);
-        if (defaultConfigUrl == null) {
-            throw LOGGER.logSevereException(new IllegalStateException(TubelineassemblyMessages.MASM_0001_DEFAULT_CFG_FILE_NOT_FOUND(defaultFileName)));
+        if (defaultConfigUrl != null) {
+            LOGGER.config(TubelineassemblyMessages.MASM_0002_DEFAULT_CFG_FILE_LOCATED(defaultFileName, defaultConfigUrl));
         }
 
-        LOGGER.config(TubelineassemblyMessages.MASM_0002_DEFAULT_CFG_FILE_LOCATED(defaultFileName, defaultConfigUrl));
         this.defaultConfig = MetroConfigLoader.loadMetroConfig(defaultConfigUrl);
         if (defaultConfig == null) {
             throw LOGGER.logSevereException(new IllegalStateException(TubelineassemblyMessages.MASM_0003_DEFAULT_CFG_FILE_NOT_LOADED(defaultFileName)));
@@ -235,17 +237,35 @@
     }
 
     private static MetroConfig loadMetroConfig(@NotNull URL resourceUrl) {
-        MetroConfig result = null;
-        try {
+        try (InputStream is = getConfigInputStream(resourceUrl)) {
             JAXBContext jaxbContext = createJAXBContext();
             Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
             XMLInputFactory factory = XmlUtil.newXMLInputFactory(true);
-            final JAXBElement<MetroConfig> configElement = unmarshaller.unmarshal(factory.createXMLStreamReader(resourceUrl.openStream()), MetroConfig.class);
-            result = configElement.getValue();
+            JAXBElement<MetroConfig> configElement = unmarshaller.unmarshal(factory.createXMLStreamReader(is), MetroConfig.class);
+            return configElement.getValue();
         } catch (Exception e) {
-            LOGGER.warning(TubelineassemblyMessages.MASM_0010_ERROR_READING_CFG_FILE_FROM_LOCATION(resourceUrl.toString()), e);
+            String message = TubelineassemblyMessages.MASM_0010_ERROR_READING_CFG_FILE_FROM_LOCATION(
+                    resourceUrl != null ? resourceUrl.toString() : null);
+            InternalError error = new InternalError(message);
+            LOGGER.logException(error, e, Level.SEVERE);
+            throw error;
         }
-        return result;
+    }
+
+    private static InputStream getConfigInputStream(URL resourceUrl) throws IOException {
+        InputStream is;
+        if (resourceUrl != null) {
+            is = resourceUrl.openStream();
+        } else {
+            is = MetroConfigLoader.class.getResourceAsStream(JAXWS_TUBES_JDK_XML_RESOURCE);
+
+            if (is == null)
+                throw LOGGER.logSevereException(
+                        new IllegalStateException(
+                                TubelineassemblyMessages.MASM_0001_DEFAULT_CFG_FILE_NOT_FOUND(JAXWS_TUBES_JDK_XML_RESOURCE)));
+        }
+
+        return is;
     }
 
     private static JAXBContext createJAXBContext() throws Exception {
--- a/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/jxc/ConfigReader.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/jxc/ConfigReader.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -181,7 +181,7 @@
     /**
      * Lazily parsed schema for the binding file.
      */
-    private static SchemaCache configSchema = new SchemaCache(Config.class.getResource("config.xsd"));
+    private static SchemaCache configSchema = new SchemaCache("config.xsd", Config.class);
 
 
     /**
--- a/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/SchemaCache.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/SchemaCache.java	Wed Jul 05 20:37:09 2017 +0200
@@ -25,14 +25,23 @@
 
 package com.sun.tools.internal.xjc;
 
-import java.net.URL;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 
+import javax.xml.transform.stream.StreamSource;
 import javax.xml.validation.Schema;
 import javax.xml.validation.SchemaFactory;
 import javax.xml.validation.ValidatorHandler;
 
 import com.sun.xml.internal.bind.v2.util.XmlFactory;
 import javax.xml.XMLConstants;
+
+import org.w3c.dom.ls.LSInput;
+import org.w3c.dom.ls.LSResourceResolver;
 import org.xml.sax.SAXException;
 
 import static com.sun.xml.internal.bind.v2.util.XmlFactory.allowExternalAccess;
@@ -47,30 +56,170 @@
  */
 public final class SchemaCache {
 
+    private final boolean createResolver;
+    private final String resourceName;
+    private final Class<?> clazz;
+
     private Schema schema;
 
-    private final URL source;
+    public SchemaCache(String resourceName, Class<?> classToResolveResources) {
+        this(resourceName, classToResolveResources, false);
+    }
 
-    public SchemaCache(URL source) {
-        this.source = source;
+    public SchemaCache(String resourceName, Class<?> classToResolveResources, boolean createResolver) {
+        this.resourceName = resourceName;
+        this.createResolver = createResolver;
+        this.clazz = classToResolveResources;
     }
 
     public ValidatorHandler newValidator() {
-        synchronized(this) {
-            if(schema==null) {
-                try {
-                    // do not disable secure processing - these are well-known schemas
-                    SchemaFactory sf = XmlFactory.createSchemaFactory(XMLConstants.W3C_XML_SCHEMA_NS_URI, false);
-                    schema = allowExternalAccess(sf, "file", false).newSchema(source);
-                } catch (SAXException e) {
-                    // we make sure that the schema is correct before we ship.
-                    throw new AssertionError(e);
+        if (schema==null) {
+            synchronized (this) {
+                if (schema == null) {
+
+                    ResourceResolver resourceResolver = null;
+                    try (InputStream is = clazz.getResourceAsStream(resourceName)) {
+
+                        StreamSource source = new StreamSource(is);
+                        source.setSystemId(resourceName);
+                        // do not disable secure processing - these are well-known schemas
+
+                        SchemaFactory sf = XmlFactory.createSchemaFactory(XMLConstants.W3C_XML_SCHEMA_NS_URI, false);
+                        SchemaFactory schemaFactory = allowExternalAccess(sf, "file", false);
+
+                        if (createResolver) {
+                            resourceResolver = new ResourceResolver(clazz);
+                            schemaFactory.setResourceResolver(resourceResolver);
+                        }
+                        schema = schemaFactory.newSchema(source);
+
+                    } catch (IOException | SAXException e) {
+                        throw new InternalError(e);
+                    } finally {
+                        if (resourceResolver != null) resourceResolver.closeStreams();
+                    }
+                }
+            }
+        }
+        return schema.newValidatorHandler();
+    }
+
+    class ResourceResolver implements LSResourceResolver {
+
+        private List<InputStream> streamsToClose = Collections.synchronizedList(new ArrayList<InputStream>());
+        private Class<?> clazz;
+
+        ResourceResolver(Class<?> clazz) {
+            this.clazz = clazz;
+        }
+
+        @Override
+        public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI) {
+            // XSOM passes the namespace URI to the publicID parameter.
+            // we do the same here .
+            InputStream is = clazz.getResourceAsStream(systemId);
+            streamsToClose.add(is);
+            return new Input(is, publicId, systemId);
+        }
+
+        void closeStreams() {
+            for (InputStream is : streamsToClose) {
+                if (is != null) {
+                    try {
+                        is.close();
+                    } catch (IOException e) {
+                        // nothing to do ...
+                    }
                 }
             }
         }
-
-        ValidatorHandler handler = schema.newValidatorHandler();
-        return handler;
     }
 
 }
+
+class Input implements LSInput {
+
+    private InputStream is;
+    private String publicId;
+    private String systemId;
+
+    public Input(InputStream is, String publicId, String systemId) {
+        this.is = is;
+        this.publicId = publicId;
+        this.systemId = systemId;
+    }
+
+    @Override
+    public Reader getCharacterStream() {
+        return null;
+    }
+
+    @Override
+    public void setCharacterStream(Reader characterStream) {
+    }
+
+    @Override
+    public InputStream getByteStream() {
+        return is;
+    }
+
+    @Override
+    public void setByteStream(InputStream byteStream) {
+    }
+
+    @Override
+    public String getStringData() {
+        return null;
+    }
+
+    @Override
+    public void setStringData(String stringData) {
+    }
+
+    @Override
+    public String getSystemId() {
+        return systemId;
+    }
+
+    @Override
+    public void setSystemId(String systemId) {
+    }
+
+    @Override
+    public String getPublicId() {
+        return publicId;
+    }
+
+    @Override
+    public void setPublicId(String publicId) {
+    }
+
+    @Override
+    public String getBaseURI() {
+        return null;
+    }
+
+    @Override
+    public void setBaseURI(String baseURI) {
+    }
+
+    @Override
+    public String getEncoding() {
+        return null;
+    }
+
+    @Override
+    public void setEncoding(String encoding) {
+    }
+
+    @Override
+    public boolean getCertifiedText() {
+        return false;
+    }
+
+    @Override
+    public void setCertifiedText(boolean certifiedText) {
+    }
+}
+
+
--- a/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/reader/dtd/bindinfo/BindInfo.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/reader/dtd/bindinfo/BindInfo.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -289,7 +289,7 @@
     /**
      * Lazily parsed schema for the binding file.
      */
-    private static SchemaCache bindingFileSchema = new SchemaCache(BindInfo.class.getResource("bindingfile.xsd"));
+    private static SchemaCache bindingFileSchema = new SchemaCache("bindingfile.xsd", BindInfo.class);
 
     /**
      * Parses an InputSource into dom4j Document.
--- a/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/reader/xmlschema/bindinfo/BindInfo.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/reader/xmlschema/bindinfo/BindInfo.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -353,5 +353,5 @@
     /**
      * Lazily parsed schema for the binding file.
      */
-    public static final SchemaCache bindingFileSchema = new SchemaCache(BindInfo.class.getResource("binding.xsd"));
+    public static SchemaCache bindingFileSchema = new SchemaCache("binding.xsd", BindInfo.class, true);
 }
--- a/jaxws/src/jdk.xml.bind/share/classes/com/sun/xml/internal/xsom/impl/parser/ParserContext.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jaxws/src/jdk.xml.bind/share/classes/com/sun/xml/internal/xsom/impl/parser/ParserContext.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -39,6 +39,8 @@
 import org.xml.sax.SAXException;
 import org.xml.sax.SAXParseException;
 
+import java.io.IOException;
+import java.io.InputStream;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
@@ -81,20 +83,18 @@
         this.owner = owner;
         this.parser = parser;
 
-        try {
-            parse(new InputSource(ParserContext.class.getResource("datatypes.xsd").toExternalForm()));
+        try (InputStream is = ParserContext.class.getResourceAsStream("datatypes.xsd")) {
+            InputSource source = new InputSource(is);
+            source.setSystemId("datatypes.xsd");
+            parse(source);
 
             SchemaImpl xs = (SchemaImpl)
-                schemaSet.getSchema("http://www.w3.org/2001/XMLSchema");
+                    schemaSet.getSchema("http://www.w3.org/2001/XMLSchema");
             xs.addSimpleType(schemaSet.anySimpleType,true);
             xs.addComplexType(schemaSet.anyType,true);
-        } catch( SAXException e ) {
+        } catch( SAXException | IOException e ) {
             // this must be a bug of XSOM
-            if(e.getException()!=null)
-                e.getException().printStackTrace();
-            else
-                e.printStackTrace();
-            throw new InternalError();
+            throw new InternalError(e.getMessage());
         }
     }
 
--- a/jdk/.hgtags	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/.hgtags	Wed Jul 05 20:37:09 2017 +0200
@@ -309,3 +309,4 @@
 7de8d036ad0980d988d1b9b4b4e6be555d9fbf98 jdk9-b64
 ed94f3e7ba6bbfec0772de6d24e39543e13f6d88 jdk9-b65
 4fbcca8ab812198c7fb747ea7b213b6e404f36e9 jdk9-b66
+1abd45df5480a04bff98fba1851d66a5230e67d4 jdk9-b67
--- a/jdk/make/mapfiles/libjava/mapfile-vers	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/make/mapfiles/libjava/mapfile-vers	Wed Jul 05 20:37:09 2017 +0200
@@ -166,6 +166,16 @@
 		Java_java_lang_Package_getSystemPackage0;
 		Java_java_lang_Package_getSystemPackages0;
 		Java_java_lang_ProcessEnvironment_environ;
+		Java_java_lang_ProcessHandleImpl_getCurrentPid0;
+		Java_java_lang_ProcessHandleImpl_parent0;
+		Java_java_lang_ProcessHandleImpl_isAlive0;
+		Java_java_lang_ProcessHandleImpl_getProcessPids0;
+		Java_java_lang_ProcessHandleImpl_destroy0;
+		Java_java_lang_ProcessHandleImpl_waitForProcessExit0;
+		Java_java_lang_ProcessHandleImpl_00024Info_initIDs;
+		Java_java_lang_ProcessHandleImpl_00024Info_info0;
+		Java_java_lang_ProcessImpl_init;
+		Java_java_lang_ProcessImpl_forkAndExec;
 		Java_java_lang_reflect_Array_get;
 		Java_java_lang_reflect_Array_getBoolean;
 		Java_java_lang_reflect_Array_getByte;
@@ -214,10 +224,6 @@
 		Java_java_lang_Throwable_fillInStackTrace;
                 Java_java_lang_Throwable_getStackTraceDepth;
                 Java_java_lang_Throwable_getStackTraceElement;
-		Java_java_lang_ProcessImpl_init;
-		Java_java_lang_ProcessImpl_waitForProcessExit;
-		Java_java_lang_ProcessImpl_forkAndExec;
-		Java_java_lang_ProcessImpl_destroyProcess;
                 Java_java_nio_Bits_copyFromShortArray;
                 Java_java_nio_Bits_copyToShortArray;
                 Java_java_nio_Bits_copyFromIntArray;
@@ -277,7 +283,7 @@
 
                 Java_jdk_internal_jimage_concurrent_ConcurrentPReader_initIDs;
                 Java_jdk_internal_jimage_concurrent_ConcurrentPReader_pread;
-		
+
                 # ZipFile.c needs this one
 		throwFileNotFoundException;
                 # zip_util.c needs this one
--- a/jdk/make/mapfiles/libnet/mapfile-vers	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/make/mapfiles/libnet/mapfile-vers	Wed Jul 05 20:37:09 2017 +0200
@@ -42,7 +42,7 @@
 		Java_java_net_Inet4Address_init;
 		Java_java_net_Inet6Address_init;
 		Java_java_net_PlainDatagramSocketImpl_setTTL;
-		Java_java_net_PlainDatagramSocketImpl_socketSetOption;
+		Java_java_net_PlainDatagramSocketImpl_socketSetOption0;
 		Java_java_net_PlainDatagramSocketImpl_bind0;
 		Java_java_net_PlainSocketImpl_socketAccept;
 		Java_java_net_DatagramPacket_init;
@@ -73,7 +73,7 @@
 		Java_java_net_SocketOutputStream_init;
 		Java_java_net_PlainDatagramSocketImpl_peek;
 		Java_java_net_PlainDatagramSocketImpl_peekData;
-		Java_java_net_PlainSocketImpl_socketSetOption;
+		Java_java_net_PlainSocketImpl_socketSetOption0;
 		Java_java_net_PlainSocketImpl_socketSendUrgentData;
 		Java_java_net_PlainDatagramSocketImpl_datagramSocketCreate;
 		Java_java_net_PlainSocketImpl_socketGetOption;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,401 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.
+ */
+
+#include "jni.h"
+#include "jni_util.h"
+#include "java_lang_ProcessHandleImpl.h"
+#include "java_lang_ProcessHandleImpl_Info.h"
+
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <sys/sysctl.h>
+
+/**
+ * Implementations of ProcessHandleImpl functions for MAC OS X;
+ * are NOT common to all Unix variants.
+ */
+
+static void getStatInfo(JNIEnv *env, jobject jinfo, pid_t pid);
+static void getCmdlineInfo(JNIEnv *env, jobject jinfo, pid_t pid);
+
+/*
+ * Common Unix function to lookup the uid and return the user name.
+ */
+extern jstring uidToUser(JNIEnv* env, uid_t uid);
+
+/* Field id for jString 'command' in java.lang.ProcessHandle.Info */
+static jfieldID ProcessHandleImpl_Info_commandID;
+
+/* Field id for jString[] 'arguments' in java.lang.ProcessHandle.Info */
+static jfieldID ProcessHandleImpl_Info_argumentsID;
+
+/* Field id for jlong 'totalTime' in java.lang.ProcessHandle.Info */
+static jfieldID ProcessHandleImpl_Info_totalTimeID;
+
+/* Field id for jlong 'startTime' in java.lang.ProcessHandle.Info */
+static jfieldID ProcessHandleImpl_Info_startTimeID;
+
+/* Field id for jString 'user' in java.lang.ProcessHandleImpl.Info */
+static jfieldID ProcessHandleImpl_Info_userID;
+
+/* static value for clock ticks per second. */
+static long clock_ticks_per_second;
+
+/**************************************************************
+ * Static method to initialize field IDs and the ticks per second rate.
+ *
+ * Class:     java_lang_ProcessHandleImpl_Info
+ * Method:    initIDs
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_java_lang_ProcessHandleImpl_00024Info_initIDs
+  (JNIEnv *env, jclass clazz) {
+
+    CHECK_NULL(ProcessHandleImpl_Info_commandID =
+            (*env)->GetFieldID(env, clazz, "command", "Ljava/lang/String;"));
+    CHECK_NULL(ProcessHandleImpl_Info_argumentsID =
+            (*env)->GetFieldID(env, clazz, "arguments", "[Ljava/lang/String;"));
+    CHECK_NULL(ProcessHandleImpl_Info_totalTimeID =
+            (*env)->GetFieldID(env, clazz, "totalTime", "J"));
+    CHECK_NULL(ProcessHandleImpl_Info_startTimeID =
+            (*env)->GetFieldID(env, clazz, "startTime", "J"));
+    CHECK_NULL(ProcessHandleImpl_Info_userID =
+            (*env)->GetFieldID(env, clazz, "user", "Ljava/lang/String;"));
+    clock_ticks_per_second = sysconf(_SC_CLK_TCK);
+}
+
+/*
+ * Returns the parent pid of the requested pid.
+ *
+ * Class:     java_lang_ProcessHandleImpl
+ * Method:    parent0
+ * Signature: (J)J
+ */
+JNIEXPORT jlong JNICALL Java_java_lang_ProcessHandleImpl_parent0
+(JNIEnv *env, jobject obj, jlong jpid) {
+    pid_t pid = (pid_t) jpid;
+    pid_t ppid = -1;
+
+    if (pid == getpid()) {
+        ppid = getppid();
+    } else {
+        const pid_t pid = (pid_t) jpid;
+        struct kinfo_proc kp;
+        size_t bufSize = sizeof kp;
+
+        // Read the process info for the specific pid
+        int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
+        if (sysctl(mib, 4, &kp, &bufSize, NULL, 0) < 0) {
+            JNU_ThrowByNameWithLastError(env,
+                "java/lang/RuntimeException", "sysctl failed");
+            return -1;
+        }
+        ppid = (bufSize > 0 && kp.kp_proc.p_pid == pid) ? kp.kp_eproc.e_ppid : -1;
+    }
+    return (jlong) ppid;
+}
+
+/*
+ * Returns the children of the requested pid and optionally each parent.
+ *
+ * Class:     java_lang_ProcessHandleImpl
+ * Method:    getProcessPids0
+ * Signature: (J[J[J)I
+ *
+ * Use sysctl to accumulate any process whose parent pid is zero or matches.
+ * The resulting pids are stored into the array of longs.
+ * The number of pids is returned if they all fit.
+ * If the parentArray is non-null, store the parent pid.
+ * If the array is too short, excess pids are not stored and
+ * the desired length is returned.
+ */
+JNIEXPORT jint JNICALL Java_java_lang_ProcessHandleImpl_getProcessPids0
+(JNIEnv *env, jclass clazz, jlong jpid,
+    jlongArray jarray, jlongArray jparentArray)
+{
+    size_t count = 0;
+    jlong* pids = NULL;
+    jlong* ppids = NULL;
+    size_t parentArraySize = 0;
+    size_t arraySize = 0;
+    size_t bufSize = 0;
+    pid_t pid = (pid_t) jpid;
+
+    arraySize = (*env)->GetArrayLength(env, jarray);
+    JNU_CHECK_EXCEPTION_RETURN(env, -1);
+    if (jparentArray != NULL) {
+        parentArraySize = (*env)->GetArrayLength(env, jparentArray);
+        JNU_CHECK_EXCEPTION_RETURN(env, -1);
+
+        if (arraySize != parentArraySize) {
+            JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
+            return 0;
+        }
+    }
+
+    // Get buffer size needed to read all processes
+    int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0};
+    if (sysctl(mib, 4, NULL, &bufSize, NULL, 0) < 0) {
+        JNU_ThrowByNameWithLastError(env,
+            "java/lang/RuntimeException", "sysctl failed");
+        return -1;
+    }
+
+    // Allocate buffer big enough for all processes
+    void *buffer = malloc(bufSize);
+    if (buffer == NULL) {
+        JNU_ThrowOutOfMemoryError(env, "malloc failed");
+        return -1;
+    }
+
+    // Read process info for all processes
+    if (sysctl(mib, 4, buffer, &bufSize, NULL, 0) < 0) {
+        JNU_ThrowByNameWithLastError(env,
+            "java/lang/RuntimeException", "sysctl failed");
+        free(buffer);
+        return -1;
+    }
+
+    do { // Block to break out of on Exception
+        struct kinfo_proc *kp = (struct kinfo_proc *) buffer;
+        unsigned long nentries = bufSize / sizeof (struct kinfo_proc);
+        long i;
+
+        pids = (*env)->GetLongArrayElements(env, jarray, NULL);
+        if (pids == NULL) {
+            break;
+        }
+        if (jparentArray != NULL) {
+            ppids  = (*env)->GetLongArrayElements(env, jparentArray, NULL);
+            if (ppids == NULL) {
+                break;
+            }
+        }
+
+        // Process each entry in the buffer
+        for (i = nentries; --i >= 0; ++kp) {
+            if (pid == 0 || kp->kp_eproc.e_ppid == pid) {
+                if (count < arraySize) {
+                    // Only store if it fits
+                    pids[count] = (jlong) kp->kp_proc.p_pid;
+                    if (ppids != NULL) {
+                        // Store the parentPid
+                        ppids[count] = (jlong) kp->kp_eproc.e_ppid;
+                    }
+                }
+                count++; // Count to tabulate size needed
+            }
+        }
+    } while (0);
+
+    if (pids != NULL) {
+        (*env)->ReleaseLongArrayElements(env, jarray, pids, 0);
+    }
+    if (ppids != NULL) {
+        (*env)->ReleaseLongArrayElements(env, jparentArray, ppids, 0);
+    }
+
+    free(buffer);
+    // If more pids than array had size for; count will be greater than array size
+    return count;
+}
+
+/**************************************************************
+ * Implementation of ProcessHandleImpl_Info native methods.
+ */
+
+/*
+ * Fill in the Info object from the OS information about the process.
+ *
+ * Class:     java_lang_ProcessHandleImpl
+ * Method:    info0
+ * Signature: (J)I
+ */
+JNIEXPORT void JNICALL Java_java_lang_ProcessHandleImpl_00024Info_info0
+  (JNIEnv *env, jobject jinfo, jlong jpid) {
+    pid_t pid = (pid_t) jpid;
+    getStatInfo(env, jinfo, pid);
+    getCmdlineInfo(env, jinfo, pid);
+}
+
+/**
+ * Read /proc/<pid>/stat and fill in the fields of the Info object.
+ * The executable name, plus the user, system, and start times are gathered.
+ */
+static void getStatInfo(JNIEnv *env, jobject jinfo, pid_t jpid) {
+    jlong totalTime;                    // nanoseconds
+    unsigned long long startTime;       // microseconds
+
+    const pid_t pid = (pid_t) jpid;
+    struct kinfo_proc kp;
+    size_t bufSize = sizeof kp;
+
+    // Read the process info for the specific pid
+    int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
+
+    if (sysctl(mib, 4, &kp, &bufSize, NULL, 0) < 0) {
+        if (errno == EINVAL) {
+            return;
+        } else {
+            JNU_ThrowByNameWithLastError(env,
+                "java/lang/RuntimeException", "sysctl failed");
+        }
+        return;
+    }
+
+    // Convert the UID to the username
+    jstring name = NULL;
+    CHECK_NULL((name = uidToUser(env, kp.kp_eproc.e_ucred.cr_uid)));
+    (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_userID, name);
+    JNU_CHECK_EXCEPTION(env);
+
+    startTime = kp.kp_proc.p_starttime.tv_sec * 1000 +
+                kp.kp_proc.p_starttime.tv_usec / 1000;
+
+    (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_startTimeID, startTime);
+    JNU_CHECK_EXCEPTION(env);
+
+    // Get cputime if for current process
+    if (pid == getpid()) {
+        struct rusage usage;
+        if (getrusage(RUSAGE_SELF, &usage) != 0) {
+            return;
+        }
+        jlong microsecs =
+            usage.ru_utime.tv_sec * 1000 * 1000 + usage.ru_utime.tv_usec +
+            usage.ru_stime.tv_sec * 1000 * 1000 + usage.ru_stime.tv_usec;
+        totalTime = microsecs * 1000;
+        (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_totalTimeID, totalTime);
+        JNU_CHECK_EXCEPTION(env);
+    }
+}
+
+/**
+ * Construct the argument array by parsing the arguments from the sequence of arguments.
+ */
+static int fillArgArray(JNIEnv *env, jobject jinfo, int nargs,
+                        const char *cp, const char *argsEnd) {
+    jstring str = NULL;
+    jobject argsArray;
+    int i;
+
+    if (nargs < 1) {
+        return 0;
+    }
+    // Create a String array for nargs-1 elements
+    CHECK_NULL_RETURN((argsArray = (*env)->NewObjectArray(env,
+            nargs - 1, JNU_ClassString(env), NULL)), -1);
+
+    for (i = 0; i < nargs - 1; i++) {
+        // skip to the next argument; omits arg[0]
+        cp += strnlen(cp, (argsEnd - cp)) + 1;
+
+        if (cp > argsEnd || *cp == '\0') {
+            return -2;  // Off the end pointer or an empty argument is an error
+        }
+
+        CHECK_NULL_RETURN((str = JNU_NewStringPlatform(env, cp)), -1);
+
+        (*env)->SetObjectArrayElement(env, argsArray, i, str);
+        JNU_CHECK_EXCEPTION_RETURN(env, -3);
+    }
+    (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_argumentsID, argsArray);
+    JNU_CHECK_EXCEPTION_RETURN(env, -4);
+    return 0;
+}
+
+/**
+ * Retrieve the command and arguments for the process and store them
+ * into the Info object.
+ */
+static void getCmdlineInfo(JNIEnv *env, jobject jinfo, pid_t pid) {
+    int mib[3], maxargs, nargs, i;
+    size_t size;
+    char *args, *cp, *sp, *np;
+
+    // Get the maximum size of the arguments
+    mib[0] = CTL_KERN;
+    mib[1] = KERN_ARGMAX;
+    size = sizeof(maxargs);
+    if (sysctl(mib, 2, &maxargs, &size, NULL, 0) == -1) {
+            JNU_ThrowByNameWithLastError(env,
+                    "java/lang/RuntimeException", "sysctl failed");
+        return;
+    }
+
+    // Allocate an args buffer and get the arguments
+    args = (char *)malloc(maxargs);
+    if (args == NULL) {
+        JNU_ThrowOutOfMemoryError(env, "malloc failed");
+        return;
+    }
+
+    do {            // a block to break out of on error
+        char *argsEnd;
+        jstring str = NULL;
+
+        mib[0] = CTL_KERN;
+        mib[1] = KERN_PROCARGS2;
+        mib[2] = pid;
+        size = (size_t) maxargs;
+        if (sysctl(mib, 3, args, &size, NULL, 0) == -1) {
+            if (errno != EINVAL) {
+            JNU_ThrowByNameWithLastError(env,
+                    "java/lang/RuntimeException", "sysctl failed");
+            }
+            break;
+        }
+        memcpy(&nargs, args, sizeof(nargs));
+
+        cp = &args[sizeof(nargs)];      // Strings start after nargs
+        argsEnd = &args[size];
+
+        // Store the command executable path
+        if ((str = JNU_NewStringPlatform(env, cp)) == NULL) {
+            break;
+        }
+        (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_commandID, str);
+        if ((*env)->ExceptionCheck(env)) {
+            break;
+        }
+
+        // Skip trailing nulls after the executable path
+        for (cp = cp + strnlen(cp, argsEnd - cp); cp < argsEnd; cp++) {
+            if (*cp != '\0') {
+                break;
+            }
+        }
+
+        fillArgArray(env, jinfo, nargs, cp, argsEnd);
+    } while (0);
+    // Free the arg buffer
+    free(args);
+}
+
--- a/jdk/src/java.base/share/classes/java/io/InputStream.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/io/InputStream.java	Wed Jul 05 20:37:09 2017 +0200
@@ -25,6 +25,7 @@
 
 package java.io;
 
+import java.util.Arrays;
 import java.util.Objects;
 
 /**
@@ -50,7 +51,7 @@
     // use when skipping.
     private static final int MAX_SKIP_BUFFER_SIZE = 2048;
 
-    private static final int TRANSFER_BUFFER_SIZE = 8192;
+    private static final int DEFAULT_BUFFER_SIZE = 8192;
 
     /**
      * Reads the next byte of data from the input stream. The value byte is
@@ -192,6 +193,128 @@
     }
 
     /**
+     * The maximum size of array to allocate.
+     * Some VMs reserve some header words in an array.
+     * Attempts to allocate larger arrays may result in
+     * OutOfMemoryError: Requested array size exceeds VM limit
+     */
+    private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
+
+    /**
+     * Reads all remaining bytes from the input stream. This method blocks until
+     * all remaining bytes have been read and end of stream is detected, or an
+     * exception is thrown. This method does not close the input stream.
+     *
+     * <p> When this stream reaches end of stream, further invocations of this
+     * method will return an empty byte array.
+     *
+     * <p> Note that this method is intended for simple cases where it is
+     * convenient to read all bytes into a byte array. It is not intended for
+     * reading input streams with large amounts of data.
+     *
+     * <p> The behavior for the case where the input stream is <i>asynchronously
+     * closed</i>, or the thread interrupted during the read, is highly input
+     * stream specific, and therefore not specified.
+     *
+     * <p> If an I/O error occurs reading from the input stream, then it may do
+     * so after some, but not all, bytes have been read. Consequently the input
+     * stream may not be at end of stream and may be in an inconsistent state.
+     * It is strongly recommended that the stream be promptly closed if an I/O
+     * error occurs.
+     *
+     * @return a byte array containing the bytes read from this input stream
+     * @throws IOException if an I/O error occurs
+     * @throws OutOfMemoryError if an array of the required size cannot be
+     *         allocated. For example, if an array larger than {@code 2GB} would
+     *         be required to store the bytes.
+     *
+     * @since 1.9
+     */
+    public byte[] readAllBytes() throws IOException {
+        byte[] buf = new byte[DEFAULT_BUFFER_SIZE];
+        int capacity = buf.length;
+        int nread = 0;
+        int n;
+        for (;;) {
+            // read to EOF which may read more or less than initial buffer size
+            while ((n = read(buf, nread, capacity - nread)) > 0)
+                nread += n;
+
+            // if the last call to read returned -1, then we're done
+            if (n < 0)
+                break;
+
+            // need to allocate a larger buffer
+            if (capacity <= MAX_BUFFER_SIZE - capacity) {
+                capacity = capacity << 1;
+            } else {
+                if (capacity == MAX_BUFFER_SIZE)
+                    throw new OutOfMemoryError("Required array size too large");
+                capacity = MAX_BUFFER_SIZE;
+            }
+            buf = Arrays.copyOf(buf, capacity);
+        }
+        return (capacity == nread) ? buf : Arrays.copyOf(buf, nread);
+    }
+
+    /**
+     * Reads the requested number of bytes from the input stream into the given
+     * byte array. This method blocks until {@code len} bytes of input data have
+     * been read, end of stream is detected, or an exception is thrown. The
+     * number of bytes actually read, possibly zero, is returned. This method
+     * does not close the input stream.
+     *
+     * <p> In the case where end of stream is reached before {@code len} bytes
+     * have been read, then the actual number of bytes read will be returned.
+     * When this stream reaches end of stream, further invocations of this
+     * method will return zero.
+     *
+     * <p> If {@code len} is zero, then no bytes are read and {@code 0} is
+     * returned; otherwise, there is an attempt to read up to {@code len} bytes.
+     *
+     * <p> The first byte read is stored into element {@code b[off]}, the next
+     * one in to {@code b[off+1]}, and so on. The number of bytes read is, at
+     * most, equal to {@code len}. Let <i>k</i> be the number of bytes actually
+     * read; these bytes will be stored in elements {@code b[off]} through
+     * {@code b[off+}<i>k</i>{@code -1]}, leaving elements {@code b[off+}<i>k</i>
+     * {@code ]} through {@code b[off+len-1]} unaffected.
+     *
+     * <p> The behavior for the case where the input stream is <i>asynchronously
+     * closed</i>, or the thread interrupted during the read, is highly input
+     * stream specific, and therefore not specified.
+     *
+     * <p> If an I/O error occurs reading from the input stream, then it may do
+     * so after some, but not all, bytes of {@code b} have been updated with
+     * data from the input stream. Consequently the input stream and {@code b}
+     * may be in an inconsistent state. It is strongly recommended that the
+     * stream be promptly closed if an I/O error occurs.
+     *
+     * @param  b the byte array into which the data is read
+     * @param  off the start offset in {@code b} at which the data is written
+     * @param  len the maximum number of bytes to read
+     * @return the actual number of bytes read into the buffer
+     * @throws IOException if an I/O error occurs
+     * @throws NullPointerException if {@code b} is {@code null}
+     * @throws IndexOutOfBoundsException If {@code off} is negative, {@code len}
+     *         is negative, or {@code len} is greater than {@code b.length - off}
+     *
+     * @since 1.9
+     */
+    public int readNBytes(byte[] b, int off, int len) throws IOException {
+        Objects.requireNonNull(b);
+        if (off < 0 || len < 0 || len > b.length - off)
+            throw new IndexOutOfBoundsException();
+        int n = 0;
+        while (n < len) {
+            int count = read(b, off + n, len - n);
+            if (count < 0)
+                break;
+            n += count;
+        }
+        return n;
+    }
+
+    /**
      * Skips over and discards <code>n</code> bytes of data from this input
      * stream. The <code>skip</code> method may, for a variety of reasons, end
      * up skipping over some smaller number of bytes, possibly <code>0</code>.
@@ -396,9 +519,9 @@
     public long transferTo(OutputStream out) throws IOException {
         Objects.requireNonNull(out, "out");
         long transferred = 0;
-        byte[] buffer = new byte[TRANSFER_BUFFER_SIZE];
+        byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
         int read;
-        while ((read = this.read(buffer, 0, TRANSFER_BUFFER_SIZE)) >= 0) {
+        while ((read = this.read(buffer, 0, DEFAULT_BUFFER_SIZE)) >= 0) {
             out.write(buffer, 0, read);
             transferred += read;
         }
--- a/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java	Wed Jul 05 20:37:09 2017 +0200
@@ -253,9 +253,6 @@
     /** flag set when at end of field value block with no TC_ENDBLOCKDATA */
     private boolean defaultDataEnd = false;
 
-    /** buffer for reading primitive field values */
-    private byte[] primVals;
-
     /** if true, invoke readObjectOverride() instead of readObject() */
     private final boolean enableOverride;
     /** if true, invoke resolveObject() */
@@ -500,7 +497,11 @@
         Object curObj = ctx.getObj();
         ObjectStreamClass curDesc = ctx.getDesc();
         bin.setBlockDataMode(false);
-        defaultReadFields(curObj, curDesc);
+        FieldValues vals = defaultReadFields(curObj, curDesc);
+        if (curObj != null) {
+            defaultCheckFieldValues(curObj, curDesc, vals);
+            defaultSetFieldValues(curObj, curDesc, vals);
+        }
         bin.setBlockDataMode(true);
         if (!curDesc.hasWriteObjectData()) {
             /*
@@ -1881,6 +1882,26 @@
         throws IOException
     {
         ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
+        // Best effort Failure Atomicity; slotValues will be non-null if field
+        // values can be set after reading all field data in the hierarchy.
+        // Field values can only be set after reading all data if there are no
+        // user observable methods in the hierarchy, readObject(NoData). The
+        // top most Serializable class in the hierarchy can be skipped.
+        FieldValues[] slotValues = null;
+
+        boolean hasSpecialReadMethod = false;
+        for (int i = 1; i < slots.length; i++) {
+            ObjectStreamClass slotDesc = slots[i].desc;
+            if (slotDesc.hasReadObjectMethod()
+                  || slotDesc.hasReadObjectNoDataMethod()) {
+                hasSpecialReadMethod = true;
+                break;
+            }
+        }
+        // No special read methods, can store values and defer setting.
+        if (!hasSpecialReadMethod)
+            slotValues = new FieldValues[slots.length];
+
         for (int i = 0; i < slots.length; i++) {
             ObjectStreamClass slotDesc = slots[i].desc;
 
@@ -1917,7 +1938,13 @@
                      */
                     defaultDataEnd = false;
                 } else {
-                    defaultReadFields(obj, slotDesc);
+                    FieldValues vals = defaultReadFields(obj, slotDesc);
+                    if (slotValues != null) {
+                        slotValues[i] = vals;
+                    } else if (obj != null) {
+                        defaultCheckFieldValues(obj, slotDesc, vals);
+                        defaultSetFieldValues(obj, slotDesc, vals);
+                    }
                 }
                 if (slotDesc.hasWriteObjectData()) {
                     skipCustomData();
@@ -1933,6 +1960,19 @@
                 }
             }
         }
+
+        if (obj != null && slotValues != null) {
+            // Check that the non-primitive types are assignable for all slots
+            // before assigning.
+            for (int i = 0; i < slots.length; i++) {
+                if (slotValues[i] != null)
+                    defaultCheckFieldValues(obj, slots[i].desc, slotValues[i]);
+            }
+            for (int i = 0; i < slots.length; i++) {
+                if (slotValues[i] != null)
+                    defaultSetFieldValues(obj, slots[i].desc, slotValues[i]);
+            }
+        }
     }
 
     /**
@@ -1964,12 +2004,22 @@
         }
     }
 
+    private class FieldValues {
+        final byte[] primValues;
+        final Object[] objValues;
+
+        FieldValues(byte[] primValues, Object[] objValues) {
+            this.primValues = primValues;
+            this.objValues = objValues;
+        }
+    }
+
     /**
      * Reads in values of serializable fields declared by given class
-     * descriptor.  If obj is non-null, sets field values in obj.  Expects that
-     * passHandle is set to obj's handle before this method is called.
+     * descriptor. Expects that passHandle is set to obj's handle before this
+     * method is called.
      */
-    private void defaultReadFields(Object obj, ObjectStreamClass desc)
+    private FieldValues defaultReadFields(Object obj, ObjectStreamClass desc)
         throws IOException
     {
         Class<?> cl = desc.forClass();
@@ -1977,22 +2027,19 @@
             throw new ClassCastException();
         }
 
+        byte[] primVals = null;
         int primDataSize = desc.getPrimDataSize();
         if (primDataSize > 0) {
-            if (primVals == null || primVals.length < primDataSize) {
-                primVals = new byte[primDataSize];
-            }
+            primVals = new byte[primDataSize];
             bin.readFully(primVals, 0, primDataSize, false);
-            if (obj != null) {
-                desc.setPrimFieldValues(obj, primVals);
-            }
         }
 
+        Object[] objVals = null;
         int numObjFields = desc.getNumObjFields();
         if (numObjFields > 0) {
             int objHandle = passHandle;
             ObjectStreamField[] fields = desc.getFields(false);
-            Object[] objVals = new Object[numObjFields];
+            objVals = new Object[numObjFields];
             int numPrimFields = fields.length - objVals.length;
             for (int i = 0; i < objVals.length; i++) {
                 ObjectStreamField f = fields[numPrimFields + i];
@@ -2001,11 +2048,30 @@
                     handles.markDependency(objHandle, passHandle);
                 }
             }
-            if (obj != null) {
-                desc.setObjFieldValues(obj, objVals);
-            }
             passHandle = objHandle;
         }
+
+        return new FieldValues(primVals, objVals);
+    }
+
+    /** Throws ClassCastException if any value is not assignable. */
+    private void defaultCheckFieldValues(Object obj, ObjectStreamClass desc,
+                                         FieldValues values) {
+        Object[] objectValues = values.objValues;
+        if (objectValues != null)
+            desc.checkObjFieldValueTypes(obj, objectValues);
+    }
+
+    /** Sets field values in obj. */
+    private void defaultSetFieldValues(Object obj, ObjectStreamClass desc,
+                                       FieldValues values) {
+        byte[] primValues = values.primValues;
+        Object[] objectValues = values.objValues;
+
+        if (primValues != null)
+            desc.setPrimFieldValues(obj, primValues);
+        if (objectValues != null)
+            desc.setObjFieldValues(obj, objectValues);
     }
 
     /**
--- a/jdk/src/java.base/share/classes/java/io/ObjectStreamClass.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/io/ObjectStreamClass.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1253,6 +1253,15 @@
     }
 
     /**
+     * Checks that the given values, from array vals starting at offset 0,
+     * are assignable to the given serializable object fields.
+     * @throws ClassCastException if any value is not assignable
+     */
+    void checkObjFieldValueTypes(Object obj, Object[] vals) {
+        fieldRefl.checkObjectFieldValueTypes(obj, vals);
+    }
+
+    /**
      * Sets the serializable object fields of object obj using values from
      * array vals starting at offset 0.  It is the responsibility of the caller
      * to ensure that obj is of the proper type if non-null.
@@ -2070,6 +2079,15 @@
         }
 
         /**
+         * Checks that the given values, from array vals starting at offset 0,
+         * are assignable to the given serializable object fields.
+         * @throws ClassCastException if any value is not assignable
+         */
+        void checkObjectFieldValueTypes(Object obj, Object[] vals) {
+            setObjFieldValues(obj, vals, true);
+        }
+
+        /**
          * Sets the serializable object fields of object obj using values from
          * array vals starting at offset 0.  The caller is responsible for
          * ensuring that obj is of the proper type; however, attempts to set a
@@ -2077,6 +2095,10 @@
          * ClassCastException.
          */
         void setObjFieldValues(Object obj, Object[] vals) {
+            setObjFieldValues(obj, vals, false);
+        }
+
+        private void setObjFieldValues(Object obj, Object[] vals, boolean dryRun) {
             if (obj == null) {
                 throw new NullPointerException();
             }
@@ -2101,7 +2123,8 @@
                                 f.getType().getName() + " in instance of " +
                                 obj.getClass().getName());
                         }
-                        unsafe.putObject(obj, key, val);
+                        if (!dryRun)
+                            unsafe.putObject(obj, key, val);
                         break;
 
                     default:
--- a/jdk/src/java.base/share/classes/java/lang/Character.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/Character.java	Wed Jul 05 20:37:09 2017 +0200
@@ -646,13 +646,11 @@
      */
     public static final class UnicodeBlock extends Subset {
         /**
-         * 510  - the expected number of enteties
+         * 510  - the expected number of entities
          * 0.75 - the default load factor of HashMap
          */
-        private static final int INITIAL_CAPACITY =
-                (int)(510 / 0.75f + 1.0f);
         private static Map<String, UnicodeBlock> map =
-                new HashMap<>(INITIAL_CAPACITY);
+                new HashMap<>((int)(510 / 0.75f + 1.0f));
 
         /**
          * Creates a UnicodeBlock with the given identifier name.
--- a/jdk/src/java.base/share/classes/java/lang/Process.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/Process.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,25 +26,31 @@
 package java.lang;
 
 import java.io.*;
+import java.lang.ProcessBuilder.Redirect;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ForkJoinPool;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Stream;
 
 /**
+ * {@code Process} provides control of native processes started by
+ * ProcessBuilder.start and Runtime.exec.
+ * The class provides methods for performing input from the process, performing
+ * output to the process, waiting for the process to complete,
+ * checking the exit status of the process, and destroying (killing)
+ * the process.
  * The {@link ProcessBuilder#start()} and
  * {@link Runtime#exec(String[],String[],File) Runtime.exec}
  * methods create a native process and return an instance of a
  * subclass of {@code Process} that can be used to control the process
- * and obtain information about it.  The class {@code Process}
- * provides methods for performing input from the process, performing
- * output to the process, waiting for the process to complete,
- * checking the exit status of the process, and destroying (killing)
- * the process.
+ * and obtain information about it.
  *
  * <p>The methods that create processes may not work well for special
  * processes on certain native platforms, such as native windowing
  * processes, daemon processes, Win16/DOS processes on Microsoft
  * Windows, or shell scripts.
  *
- * <p>By default, the created subprocess does not have its own terminal
+ * <p>By default, the created process does not have its own terminal
  * or console.  All its standard I/O (i.e. stdin, stdout, stderr)
  * operations will be redirected to the parent process, where they can
  * be accessed via the streams obtained using the methods
@@ -52,35 +58,49 @@
  * {@link #getInputStream()}, and
  * {@link #getErrorStream()}.
  * The parent process uses these streams to feed input to and get output
- * from the subprocess.  Because some native platforms only provide
+ * from the process.  Because some native platforms only provide
  * limited buffer size for standard input and output streams, failure
  * to promptly write the input stream or read the output stream of
- * the subprocess may cause the subprocess to block, or even deadlock.
+ * the process may cause the process to block, or even deadlock.
  *
  * <p>Where desired, <a href="ProcessBuilder.html#redirect-input">
- * subprocess I/O can also be redirected</a>
+ * process I/O can also be redirected</a>
  * using methods of the {@link ProcessBuilder} class.
  *
- * <p>The subprocess is not killed when there are no more references to
- * the {@code Process} object, but rather the subprocess
+ * <p>The process is not killed when there are no more references to
+ * the {@code Process} object, but rather the process
  * continues executing asynchronously.
  *
- * <p>There is no requirement that a process represented by a {@code
+ * <p>There is no requirement that the process represented by a {@code
  * Process} object execute asynchronously or concurrently with respect
  * to the Java process that owns the {@code Process} object.
  *
  * <p>As of 1.5, {@link ProcessBuilder#start()} is the preferred way
  * to create a {@code Process}.
  *
+ * <p>Subclasses of Process should override the {@link #onExit()} and
+ * {@link #toHandle()} methods to provide a fully functional Process including the
+ * {@link #getPid() process id},
+ * {@link #info() information about the process},
+ * {@link #children() direct children}, and
+ * {@link #allChildren() direct and indirect children} of the process.
+ * Delegating to the underlying Process or ProcessHandle is typically
+ * easiest and most efficient.
+ *
  * @since   1.0
  */
 public abstract class Process {
     /**
+     * Default constructor for Process.
+     */
+    public Process() {}
+
+    /**
      * Returns the output stream connected to the normal input of the
-     * subprocess.  Output to the stream is piped into the standard
+     * process.  Output to the stream is piped into the standard
      * input of the process represented by this {@code Process} object.
      *
-     * <p>If the standard input of the subprocess has been redirected using
+     * <p>If the standard input of the process has been redirected using
      * {@link ProcessBuilder#redirectInput(Redirect)
      * ProcessBuilder.redirectInput}
      * then this method will return a
@@ -90,42 +110,42 @@
      * output stream to be buffered.
      *
      * @return the output stream connected to the normal input of the
-     *         subprocess
+     *         process
      */
     public abstract OutputStream getOutputStream();
 
     /**
      * Returns the input stream connected to the normal output of the
-     * subprocess.  The stream obtains data piped from the standard
+     * process.  The stream obtains data piped from the standard
      * output of the process represented by this {@code Process} object.
      *
-     * <p>If the standard output of the subprocess has been redirected using
+     * <p>If the standard output of the process has been redirected using
      * {@link ProcessBuilder#redirectOutput(Redirect)
      * ProcessBuilder.redirectOutput}
      * then this method will return a
      * <a href="ProcessBuilder.html#redirect-output">null input stream</a>.
      *
-     * <p>Otherwise, if the standard error of the subprocess has been
+     * <p>Otherwise, if the standard error of the process has been
      * redirected using
      * {@link ProcessBuilder#redirectErrorStream(boolean)
      * ProcessBuilder.redirectErrorStream}
      * then the input stream returned by this method will receive the
-     * merged standard output and the standard error of the subprocess.
+     * merged standard output and the standard error of the process.
      *
      * <p>Implementation note: It is a good idea for the returned
      * input stream to be buffered.
      *
      * @return the input stream connected to the normal output of the
-     *         subprocess
+     *         process
      */
     public abstract InputStream getInputStream();
 
     /**
      * Returns the input stream connected to the error output of the
-     * subprocess.  The stream obtains data piped from the error output
+     * process.  The stream obtains data piped from the error output
      * of the process represented by this {@code Process} object.
      *
-     * <p>If the standard error of the subprocess has been redirected using
+     * <p>If the standard error of the process has been redirected using
      * {@link ProcessBuilder#redirectError(Redirect)
      * ProcessBuilder.redirectError} or
      * {@link ProcessBuilder#redirectErrorStream(boolean)
@@ -137,19 +157,19 @@
      * input stream to be buffered.
      *
      * @return the input stream connected to the error output of
-     *         the subprocess
+     *         the process
      */
     public abstract InputStream getErrorStream();
 
     /**
      * Causes the current thread to wait, if necessary, until the
      * process represented by this {@code Process} object has
-     * terminated.  This method returns immediately if the subprocess
-     * has already terminated.  If the subprocess has not yet
+     * terminated.  This method returns immediately if the process
+     * has already terminated.  If the process has not yet
      * terminated, the calling thread will be blocked until the
-     * subprocess exits.
+     * process exits.
      *
-     * @return the exit value of the subprocess represented by this
+     * @return the exit value of the process represented by this
      *         {@code Process} object.  By convention, the value
      *         {@code 0} indicates normal termination.
      * @throws InterruptedException if the current thread is
@@ -161,10 +181,10 @@
 
     /**
      * Causes the current thread to wait, if necessary, until the
-     * subprocess represented by this {@code Process} object has
+     * process represented by this {@code Process} object has
      * terminated, or the specified waiting time elapses.
      *
-     * <p>If the subprocess has already terminated then this method returns
+     * <p>If the process has already terminated then this method returns
      * immediately with the value {@code true}.  If the process has not
      * terminated and the timeout value is less than, or equal to, zero, then
      * this method returns immediately with the value {@code false}.
@@ -176,8 +196,8 @@
      *
      * @param timeout the maximum time to wait
      * @param unit the time unit of the {@code timeout} argument
-     * @return {@code true} if the subprocess has exited and {@code false} if
-     *         the waiting time elapsed before the subprocess has exited.
+     * @return {@code true} if the process has exited and {@code false} if
+     *         the waiting time elapsed before the process has exited.
      * @throws InterruptedException if the current thread is interrupted
      *         while waiting.
      * @throws NullPointerException if unit is null
@@ -204,41 +224,60 @@
     }
 
     /**
-     * Returns the exit value for the subprocess.
+     * Returns the exit value for the process.
      *
-     * @return the exit value of the subprocess represented by this
+     * @return the exit value of the process represented by this
      *         {@code Process} object.  By convention, the value
      *         {@code 0} indicates normal termination.
-     * @throws IllegalThreadStateException if the subprocess represented
+     * @throws IllegalThreadStateException if the process represented
      *         by this {@code Process} object has not yet terminated
      */
     public abstract int exitValue();
 
     /**
-     * Kills the subprocess. Whether the subprocess represented by this
-     * {@code Process} object is forcibly terminated or not is
+     * Kills the process.
+     * Whether the process represented by this {@code Process} object is
+     * {@link #supportsNormalTermination normally terminated} or not is
      * implementation dependent.
+     * Forcible process destruction is defined as the immediate termination of a
+     * process, whereas normal termination allows the process to shut down cleanly.
+     * If the process is not alive, no action is taken.
+     * <p>
+     * The {@link java.util.concurrent.CompletableFuture} from {@link #onExit} is
+     * {@link java.util.concurrent.CompletableFuture#complete completed}
+     * when the process has terminated.
      */
     public abstract void destroy();
 
     /**
-     * Kills the subprocess. The subprocess represented by this
+     * Kills the process forcibly. The process represented by this
      * {@code Process} object is forcibly terminated.
+     * Forcible process destruction is defined as the immediate termination of a
+     * process, whereas normal termination allows the process to shut down cleanly.
+     * If the process is not alive, no action is taken.
+     * <p>
+     * The {@link java.util.concurrent.CompletableFuture} from {@link #onExit} is
+     * {@link java.util.concurrent.CompletableFuture#complete completed}
+     * when the process has terminated.
+     * <p>
+     * Invoking this method on {@code Process} objects returned by
+     * {@link ProcessBuilder#start} and {@link Runtime#exec} forcibly terminate
+     * the process.
      *
-     * <p>The default implementation of this method invokes {@link #destroy}
-     * and so may not forcibly terminate the process. Concrete implementations
-     * of this class are strongly encouraged to override this method with a
-     * compliant implementation.  Invoking this method on {@code Process}
-     * objects returned by {@link ProcessBuilder#start} and
-     * {@link Runtime#exec} will forcibly terminate the process.
-     *
-     * <p>Note: The subprocess may not terminate immediately.
+     * @implSpec
+     * The default implementation of this method invokes {@link #destroy}
+     * and so may not forcibly terminate the process.
+     * @implNote
+     * Concrete implementations of this class are strongly encouraged to override
+     * this method with a compliant implementation.
+     * @apiNote
+     * The process may not terminate immediately.
      * i.e. {@code isAlive()} may return true for a brief period
      * after {@code destroyForcibly()} is called. This method
      * may be chained to {@code waitFor()} if needed.
      *
      * @return the {@code Process} object representing the
-     *         subprocess to be forcibly destroyed.
+     *         process forcibly destroyed
      * @since 1.8
      */
     public Process destroyForcibly() {
@@ -247,10 +286,36 @@
     }
 
     /**
-     * Tests whether the subprocess represented by this {@code Process} is
+     * Returns {@code true} if the implementation of {@link #destroy} is to
+     * normally terminate the process,
+     * Returns {@code false} if the implementation of {@code destroy}
+     * forcibly and immediately terminates the process.
+     * <p>
+     * Invoking this method on {@code Process} objects returned by
+     * {@link ProcessBuilder#start} and {@link Runtime#exec} return
+     * {@code true} or {@code false} depending on the platform implementation.
+     *
+     * @implSpec
+     * This implementation throws an instance of
+     * {@link java.lang.UnsupportedOperationException} and performs no other action.
+     *
+     * @return {@code true} if the implementation of {@link #destroy} is to
+     *         normally terminate the process;
+     *         otherwise, {@link #destroy} forcibly terminates the process
+     * @throws UnsupportedOperationException if the Process implementation
+     *         does not support this operation
+     * @since 1.9
+     */
+    public boolean supportsNormalTermination() {
+        throw new UnsupportedOperationException(this.getClass()
+                + ".supportsNormalTermination() not supported" );
+    }
+
+    /**
+     * Tests whether the process represented by this {@code Process} is
      * alive.
      *
-     * @return {@code true} if the subprocess represented by this
+     * @return {@code true} if the process represented by this
      *         {@code Process} object has not yet terminated.
      * @since 1.8
      */
@@ -264,16 +329,222 @@
     }
 
     /**
-     * Returns the native process id of the subprocess.
-     * The native process id is an identification number that the operating
+     * Returns the native process ID of the process.
+     * The native process ID is an identification number that the operating
      * system assigns to the process.
      *
-     * @return the native process id of the subprocess
+     * @implSpec
+     * The implementation of this method returns the process id as:
+     * {@link #toHandle toHandle().getPid()}.
+     *
+     * @return the native process id of the process
      * @throws UnsupportedOperationException if the Process implementation
-     *     does not support this operation
+     *         does not support this operation
      * @since 1.9
      */
     public long getPid() {
-        throw new UnsupportedOperationException();
+        return toHandle().getPid();
+    }
+
+    /**
+     * Returns a {@code CompletableFuture<Process>} for the termination of the Process.
+     * The {@link java.util.concurrent.CompletableFuture} provides the ability
+     * to trigger dependent functions or actions that may be run synchronously
+     * or asynchronously upon process termination.
+     * When the process terminates the CompletableFuture is
+     * {@link java.util.concurrent.CompletableFuture#complete completed} regardless
+     * of the exit status of the process.
+     * <p>
+     * Calling {@code onExit().get()} waits for the process to terminate and returns
+     * the Process. The future can be used to check if the process is
+     * {@link java.util.concurrent.CompletableFuture#isDone done} or to
+     * {@link java.util.concurrent.CompletableFuture#get() wait} for it to terminate.
+     * {@link java.util.concurrent.CompletableFuture#cancel(boolean) Cancelling}
+     * the CompletableFuture does not affect the Process.
+     * <p>
+     * If the process is {@link #isAlive not alive} the {@link CompletableFuture}
+     * returned has been {@link java.util.concurrent.CompletableFuture#complete completed}.
+     * <p>
+     * Processes returned from {@link ProcessBuilder#start} override the
+     * default implementation to provide an efficient mechanism to wait
+     * for process exit.
+     * <p>
+     * @apiNote
+     * Using {@link #onExit() onExit} is an alternative to
+     * {@link #waitFor() waitFor} that enables both additional concurrency
+     * and convenient access to the result of the Process.
+     * Lambda expressions can be used to evaluate the result of the Process
+     * execution.
+     * If there is other processing to be done before the value is used
+     * then {@linkplain #onExit onExit} is a convenient mechanism to
+     * free the current thread and block only if and when the value is needed.
+     * <br>
+     * For example, launching a process to compare two files and get a boolean if they are identical:
+     * <pre> {@code   Process p = new ProcessBuilder("cmp", "f1", "f2").start();
+     *    Future<Boolean> identical = p.onExit().thenApply(p1 -> p1.exitValue() == 0);
+     *    ...
+     *    if (identical.get()) { ... }
+     * }</pre>
+     *
+     * @implSpec
+     * This implementation executes {@link #waitFor()} in a separate thread
+     * repeatedly until it returns successfully. If the execution of
+     * {@code waitFor} is interrupted, the thread's interrupt status is preserved.
+     * <p>
+     * When {@link #waitFor()} returns successfully the CompletableFuture is
+     * {@link java.util.concurrent.CompletableFuture#complete completed} regardless
+     * of the exit status of the process.
+     *
+     * This implementation may consume a lot of memory for thread stacks if a
+     * large number of processes are waited for concurrently.
+     * <p>
+     * External implementations should override this method and provide
+     * a more efficient implementation. For example, to delegate to the underlying
+     * process, it can do the following:
+     * <pre>{@code
+     *    public CompletableFuture<Process> onExit() {
+     *       return delegate.onExit().thenApply(p -> this);
+     *    }
+     * }</pre>
+     *
+     * @return a new {@code CompletableFuture<Process>} for the Process
+     *
+     * @since 1.9
+     */
+    public CompletableFuture<Process> onExit() {
+        return CompletableFuture.supplyAsync(this::waitForInternal);
     }
+
+    /**
+     * Wait for the process to exit by calling {@code waitFor}.
+     * If the thread is interrupted, remember the interrupted state to
+     * be restored before returning. Use ForkJoinPool.ManagedBlocker
+     * so that the number of workers in case ForkJoinPool is used is
+     * compensated when the thread blocks in waitFor().
+     *
+     * @return the Process
+     */
+    private Process waitForInternal() {
+        boolean interrupted = false;
+        while (true) {
+            try {
+                ForkJoinPool.managedBlock(new ForkJoinPool.ManagedBlocker() {
+                    @Override
+                    public boolean block() throws InterruptedException {
+                        waitFor();
+                        return true;
+                    }
+
+                    @Override
+                    public boolean isReleasable() {
+                        return !isAlive();
+                    }
+                });
+                break;
+            } catch (InterruptedException x) {
+                interrupted = true;
+            }
+        }
+        if (interrupted) {
+            Thread.currentThread().interrupt();
+        }
+        return this;
+    }
+
+    /**
+     * Returns a ProcessHandle for the Process.
+     *
+     * {@code Process} objects returned by {@link ProcessBuilder#start} and
+     * {@link Runtime#exec} implement {@code toHandle} as the equivalent of
+     * {@link ProcessHandle#of(long) ProcessHandle.of(pid)} including the
+     * check for a SecurityManager and {@code RuntimePermission("manageProcess")}.
+     *
+     * @implSpec
+     * This implementation throws an instance of
+     * {@link java.lang.UnsupportedOperationException} and performs no other action.
+     * Subclasses should override this method to provide a ProcessHandle for the
+     * process.  The methods {@link #getPid}, {@link #info}, {@link #children},
+     * and {@link #allChildren}, unless overridden, operate on the ProcessHandle.
+     *
+     * @return Returns a ProcessHandle for the Process
+     * @throws UnsupportedOperationException if the Process implementation
+     *         does not support this operation
+     * @throws SecurityException if a security manager has been installed and
+     *         it denies RuntimePermission("manageProcess")
+     * @since 1.9
+     */
+    public ProcessHandle toHandle() {
+        throw new UnsupportedOperationException(this.getClass()
+                + ".toHandle() not supported");
+    }
+
+    /**
+     * Returns a snapshot of information about the process.
+     *
+     * <p> An {@link ProcessHandle.Info} instance has various accessor methods
+     * that return information about the process, if the process is alive and
+     * the information is available, otherwise {@code null} is returned.
+     *
+     * @implSpec
+     * This implementation returns information about the process as:
+     * {@link #toHandle toHandle().info()}.
+     *
+     * @return a snapshot of information about the process, always non-null
+     * @throws UnsupportedOperationException if the Process implementation
+     *         does not support this operation
+     * @since 1.9
+     */
+    public ProcessHandle.Info info() {
+        return toHandle().info();
+    }
+
+    /**
+     * Returns a snapshot of the direct children of the process.
+     * A process that is {@link #isAlive not alive} has zero children.
+     * <p>
+     * <em>Note that processes are created and terminate asynchronously.
+     * There is no guarantee that a process is {@link #isAlive alive}.
+     * </em>
+     *
+     * @implSpec
+     * This implementation returns the direct children as:
+     * {@link #toHandle toHandle().children()}.
+     *
+     * @return a Stream of ProcessHandles for processes that are direct children
+     *         of the process
+     * @throws UnsupportedOperationException if the Process implementation
+     *         does not support this operation
+     * @throws SecurityException if a security manager has been installed and
+     *         it denies RuntimePermission("manageProcess")
+     * @since 1.9
+     */
+    public Stream<ProcessHandle> children() {
+        return toHandle().children();
+    }
+
+    /**
+     * Returns a snapshot of the direct and indirect children of the process.
+     * A process that is {@link #isAlive not alive} has zero children.
+     * <p>
+     * <em>Note that processes are created and terminate asynchronously.
+     * There is no guarantee that a process is {@link #isAlive alive}.
+     * </em>
+     *
+     * @implSpec
+     * This implementation returns all children as:
+     * {@link #toHandle toHandle().allChildren()}.
+     *
+     * @return a Stream of ProcessHandles for processes that are direct and
+     *         indirect children of the process
+     * @throws UnsupportedOperationException if the Process implementation
+     *         does not support this operation
+     * @throws SecurityException if a security manager has been installed and
+     *         it denies RuntimePermission("manageProcess")
+     * @since 1.9
+     */
+    public Stream<ProcessHandle> allChildren() {
+        return toHandle().allChildren();
+    }
+
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/ProcessHandle.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.stream.Stream;
+
+/**
+ * ProcessHandle identifies and provides control of native processes. Each
+ * individual process can be monitored for liveness, list its children,
+ * get information about the process or destroy it.
+ * By comparison, {@link java.lang.Process Process} instances were started
+ * by the current process and additionally provide access to the process
+ * input, output, and error streams.
+ * <p>
+ * The native process ID is an identification number that the
+ * operating system assigns to the process.
+ * The range for process id values is dependent on the operating system.
+ * For example, an embedded system might use a 16-bit value.
+ * Status information about a process is retrieved from the native system
+ * and may change asynchronously; processes may be created or terminate
+ * spontaneously.
+ * The time between when a process terminates and the process id
+ * is reused for a new process is unpredictable.
+ * Race conditions can exist between checking the status of a process and
+ * acting upon it. When using ProcessHandles avoid assumptions
+ * about the liveness or identity of the underlying process.
+ * <p>
+ * Each ProcessHandle identifies and allows control of a process in the native
+ * system. ProcessHandles are returned from the factory methods {@link #current()},
+ * {@link #of(long)},
+ * {@link #children}, {@link #allChildren}, {@link #parent()} and
+ * {@link #allProcesses()}.
+ * <p>
+ * The {@link Process} instances created by {@link ProcessBuilder} can be queried
+ * for a ProcessHandle that provides information about the Process.
+ * ProcessHandle references should not be freely distributed.
+ *
+ * <p>
+ * A {@link java.util.concurrent.CompletableFuture} available from {@link #onExit}
+ * can be used to wait for process termination, and possibly trigger dependent
+ * actions.
+ * <p>
+ * The factory methods limit access to ProcessHandles using the
+ * SecurityManager checking the {@link RuntimePermission RuntimePermission("manageProcess")}.
+ * The ability to control processes is also restricted by the native system,
+ * ProcessHandle provides no more access to, or control over, the native process
+ * than would be allowed by a native application.
+ * <p>
+ * @implSpec
+ * In the case where ProcessHandles cannot be supported then the factory
+ * methods must consistently throw {@link java.lang.UnsupportedOperationException}.
+ * The methods of this class throw {@link java.lang.UnsupportedOperationException}
+ * if the operating system does not allow access to query or kill a process.
+ *
+ * @see Process
+ * @since 1.9
+ */
+public interface ProcessHandle extends Comparable<ProcessHandle> {
+
+    /**
+     * Returns the native process ID of the process. The native process ID is an
+     * identification number that the operating system assigns to the process.
+     *
+     * @return the native process ID of the process
+     * @throws UnsupportedOperationException if the implementation
+     *         does not support this operation
+     */
+    long getPid();
+
+    /**
+     * Returns an {@code Optional<ProcessHandle>} for an existing native process.
+     *
+     * @param pid a native process ID
+     * @return an {@code Optional<ProcessHandle>} of the PID for the process;
+     *         the {@code Optional} is empty if the process does not exist
+     * @throws SecurityException if a security manager has been installed and
+     *         it denies RuntimePermission("manageProcess")
+     * @throws UnsupportedOperationException if the implementation
+     *         does not support this operation
+     */
+    public static Optional<ProcessHandle> of(long pid) {
+        return ProcessHandleImpl.get(pid);
+    }
+
+    /**
+     * Returns a ProcessHandle for the current process. The ProcessHandle cannot be
+     * used to destroy the current process, use {@link System#exit System.exit} instead.
+     *
+     * @return a ProcessHandle for the current process
+     * @throws SecurityException if a security manager has been installed and
+     *         it denies RuntimePermission("manageProcess")
+     * @throws UnsupportedOperationException if the implementation
+     *         does not support this operation
+     */
+    public static ProcessHandle current() {
+        return ProcessHandleImpl.current();
+    }
+
+    /**
+     * Returns an {@code Optional<ProcessHandle>} for the parent process.
+     * Note that Processes in a zombie state usually don't have a parent.
+     *
+     * @return an {@code Optional<ProcessHandle>} of the parent process;
+     *         the {@code Optional} is empty if the child process does not have a parent
+     *         or if the parent is not available, possibly due to operating system limitations
+     * @throws SecurityException if a security manager has been installed and
+     *         it denies RuntimePermission("manageProcess")
+     */
+    Optional<ProcessHandle> parent();
+
+    /**
+     * Returns a snapshot of the current direct children of the process.
+     * A process that is {@link #isAlive not alive} has zero children.
+     * <p>
+     * <em>Note that processes are created and terminate asynchronously.
+     * There is no guarantee that a process is {@link #isAlive alive}.
+     * </em>
+     *
+     * @return a Stream of ProcessHandles for processes that are direct children
+     *         of the process
+     * @throws SecurityException if a security manager has been installed and
+     *         it denies RuntimePermission("manageProcess")
+     */
+    Stream<ProcessHandle> children();
+
+    /**
+     * Returns a snapshot of the current direct and indirect children of the process.
+     * A process that is {@link #isAlive not alive} has zero children.
+     * <p>
+     * <em>Note that processes are created and terminate asynchronously.
+     * There is no guarantee that a process is {@link #isAlive alive}.
+     * </em>
+     *
+     * @return a Stream of ProcessHandles for processes that are direct and
+     *         indirect children of the process
+     * @throws SecurityException if a security manager has been installed and
+     *         it denies RuntimePermission("manageProcess")
+     */
+    Stream<ProcessHandle> allChildren();
+
+    /**
+     * Returns a snapshot of all processes visible to the current process.
+     * <p>
+     * <em>Note that processes are created and terminate asynchronously. There
+     * is no guarantee that a process in the stream is alive or that no other
+     * processes may have been created since the inception of the snapshot.
+     * </em>
+     *
+     * @return a Stream of ProcessHandles for all processes
+     * @throws SecurityException if a security manager has been installed and
+     *         it denies RuntimePermission("manageProcess")
+     * @throws UnsupportedOperationException if the implementation
+     *         does not support this operation
+     */
+    static Stream<ProcessHandle> allProcesses() {
+        return ProcessHandleImpl.children(0);
+    }
+
+    /**
+     * Returns a snapshot of information about the process.
+     *
+     * <p> An {@code Info} instance has various accessor methods that return
+     * information about the process, if the process is alive and the
+     * information is available.
+     *
+     * @return a snapshot of information about the process, always non-null
+     */
+    Info info();
+
+    /**
+     * Information snapshot about the process.
+     * The attributes of a process vary by operating system and are not available
+     * in all implementations.  Information about processes is limited
+     * by the operating system privileges of the process making the request.
+     * The return types are {@code Optional<T>} allowing explicit tests
+     * and actions if the value is available.
+     * @since 1.9
+     */
+    public interface Info {
+        /**
+         * Returns the executable pathname of the process.
+         *
+         * @return an {@code Optional<String>} of the executable pathname
+         *         of the process
+         */
+        public Optional<String> command();
+
+        /**
+         * Returns an array of Strings of the arguments of the process.
+         *
+         * @return an {@code Optional<String[]>} of the arguments of the process
+         */
+        public Optional<String[]> arguments();
+
+        /**
+         * Returns the start time of the process.
+         *
+         * @return an {@code Optional<Instant>} of the start time of the process
+         */
+        public Optional<Instant> startInstant();
+
+        /**
+         * Returns the total cputime accumulated of the process.
+         *
+         * @return an {@code Optional<Duration>} for the accumulated total cputime
+         */
+        public Optional<Duration> totalCpuDuration();
+
+        /**
+         * Return the user of the process.
+         *
+         * @return an {@code Optional<String>} for the user of the process
+         */
+        public Optional<String> user();
+    }
+
+    /**
+     * Returns a {@code CompletableFuture<ProcessHandle>} for the termination
+     * of the process.
+     * The {@link java.util.concurrent.CompletableFuture} provides the ability
+     * to trigger dependent functions or actions that may be run synchronously
+     * or asynchronously upon process termination.
+     * When the process terminates the CompletableFuture is
+     * {@link java.util.concurrent.CompletableFuture#complete completed} regardless
+     * of the exit status of the process.
+     * The {@code onExit} method can be called multiple times to invoke
+     * independent actions when the process exits.
+     * <p>
+     * Calling {@code onExit().get()} waits for the process to terminate and returns
+     * the ProcessHandle. The future can be used to check if the process is
+     * {@link java.util.concurrent.CompletableFuture#isDone done} or to
+     * {@link java.util.concurrent.Future#get() wait} for it to terminate.
+     * {@link java.util.concurrent.Future#cancel(boolean) Cancelling}
+     * the CompleteableFuture does not affect the Process.
+     * <p>
+     * If the process is {@link #isAlive not alive} the {@link CompletableFuture}
+     * returned has been {@link java.util.concurrent.CompletableFuture#complete completed}.
+     *
+     * @return a new {@code CompletableFuture<ProcessHandle>} for the ProcessHandle
+     *
+     * @throws IllegalStateException if the process is the current process
+     */
+    CompletableFuture<ProcessHandle> onExit();
+
+    /**
+     * Returns {@code true} if the implementation of {@link #destroy}
+     * normally terminates the process.
+     * Returns {@code false} if the implementation of {@code destroy}
+     * forcibly and immediately terminates the process.
+     *
+     * @return {@code true} if the implementation of {@link #destroy}
+     *         normally terminates the process;
+     *         otherwise, {@link #destroy} forcibly terminates the process
+     */
+    boolean supportsNormalTermination();
+
+    /**
+     * Requests the process to be killed.
+     * Whether the process represented by this {@code ProcessHandle} object is
+     * {@link #supportsNormalTermination normally terminated} or not is
+     * implementation dependent.
+     * Forcible process destruction is defined as the immediate termination of the
+     * process, whereas normal termination allows the process to shut down cleanly.
+     * If the process is not alive, no action is taken.
+     * The operating system access controls may prevent the process
+     * from being killed.
+     * <p>
+     * The {@link java.util.concurrent.CompletableFuture} from {@link #onExit} is
+     * {@link java.util.concurrent.CompletableFuture#complete completed}
+     * when the process has terminated.
+     * <p>
+     * Note: The process may not terminate immediately.
+     * For example, {@code isAlive()} may return true for a brief period
+     * after {@code destroy()} is called.
+     *
+     * @return {@code true} if termination was successfully requested,
+     *         otherwise {@code false}
+     * @throws IllegalStateException if the process is the current process
+     */
+    boolean destroy();
+
+    /**
+     * Requests the process to be killed forcibly.
+     * The process represented by this {@code ProcessHandle} object is
+     * forcibly terminated.
+     * Forcible process destruction is defined as the immediate termination of the
+     * process, whereas normal termination allows the process to shut down cleanly.
+     * If the process is not alive, no action is taken.
+     * The operating system access controls may prevent the process
+     * from being killed.
+     * <p>
+     * The {@link java.util.concurrent.CompletableFuture} from {@link #onExit} is
+     * {@link java.util.concurrent.CompletableFuture#complete completed}
+     * when the process has terminated.
+     * <p>
+     * Note: The process may not terminate immediately.
+     * For example, {@code isAlive()} may return true for a brief period
+     * after {@code destroyForcibly()} is called.
+     *
+     * @return {@code true} if termination was successfully requested,
+     *         otherwise {@code false}
+     * @throws IllegalStateException if the process is the current process
+     */
+    boolean destroyForcibly();
+
+    /**
+     * Tests whether the process represented by this {@code ProcessHandle} is alive.
+     * Process termination is implementation and operating system specific.
+     * The process is considered alive as long as the PID is valid.
+     *
+     * @return {@code true} if the process represented by this
+     *         {@code ProcessHandle} object has not yet terminated
+     */
+   boolean isAlive();
+
+    /**
+     * Compares this ProcessHandle with the specified ProcessHandle for order.
+     * The order is not specified, but is consistent with {@link Object#equals},
+     * which returns {@code true} if and only if two instances of ProcessHandle
+     * are of the same implementation and represent the same system process.
+     * Comparison is only supported among objects of same implementation.
+     * If attempt is made to mutually compare two different implementations
+     * of {@link ProcessHandle}s, {@link ClassCastException} is thrown.
+     *
+     * @param other the ProcessHandle to be compared
+     * @return a negative integer, zero, or a positive integer as this object
+     * is less than, equal to, or greater than the specified object.
+     * @throws NullPointerException if the specified object is null
+     * @throws ClassCastException if the specified object is not of same class
+     *         as this object
+     */
+    @Override
+    int compareTo(ProcessHandle other);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/ProcessHandleImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,528 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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;
+
+import java.security.PrivilegedAction;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Stream;
+
+import sun.misc.InnocuousThread;
+
+import static java.security.AccessController.doPrivileged;
+
+/**
+ * ProcessHandleImpl is the implementation of ProcessHandle.
+ *
+ * @see Process
+ * @since 1.9
+ */
+final class ProcessHandleImpl implements ProcessHandle {
+
+    /**
+     * The thread pool of "process reaper" daemon threads.
+     */
+    private static final Executor processReaperExecutor =
+            doPrivileged((PrivilegedAction<Executor>) () -> {
+
+                ThreadGroup tg = Thread.currentThread().getThreadGroup();
+                while (tg.getParent() != null) tg = tg.getParent();
+                ThreadGroup systemThreadGroup = tg;
+
+                ThreadFactory threadFactory = grimReaper -> {
+                    // Our thread stack requirement is quite modest.
+                    Thread t = new Thread(systemThreadGroup, grimReaper,
+                            "process reaper", 32768);
+                    t.setDaemon(true);
+                    // A small attempt (probably futile) to avoid priority inversion
+                    t.setPriority(Thread.MAX_PRIORITY);
+                    return t;
+                };
+
+                return Executors.newCachedThreadPool(threadFactory);
+            });
+
+    private static class ExitCompletion extends CompletableFuture<Integer> {
+        final boolean isReaping;
+
+        ExitCompletion(boolean isReaping) {
+            this.isReaping = isReaping;
+        }
+    }
+
+    private static final ConcurrentMap<Long, ExitCompletion>
+        completions = new ConcurrentHashMap<>();
+
+    /**
+     * Returns a CompletableFuture that completes with process exit status when
+     * the process completes.
+     *
+     * @param shouldReap true if the exit value should be reaped
+     */
+    static CompletableFuture<Integer> completion(long pid, boolean shouldReap) {
+        // check canonicalizing cache 1st
+        ExitCompletion completion = completions.get(pid);
+        // re-try until we get a completion that shouldReap => isReaping
+        while (completion == null || (shouldReap && !completion.isReaping)) {
+            ExitCompletion newCompletion = new ExitCompletion(shouldReap);
+            if (completion == null) {
+                completion = completions.putIfAbsent(pid, newCompletion);
+            } else {
+                completion = completions.replace(pid, completion, newCompletion)
+                    ? null : completions.get(pid);
+            }
+            if (completion == null) {
+                // newCompletion has just been installed successfully
+                completion = newCompletion;
+                // spawn a thread to wait for and deliver the exit value
+                processReaperExecutor.execute(() -> {
+                    int exitValue = waitForProcessExit0(pid, shouldReap);
+                    newCompletion.complete(exitValue);
+                    // remove from cache afterwards
+                    completions.remove(pid, newCompletion);
+                });
+            }
+        }
+        return completion;
+    }
+
+    @Override
+    public CompletableFuture<ProcessHandle> onExit() {
+        if (this.equals(current)) {
+            throw new IllegalStateException("onExit for current process not allowed");
+        }
+
+        return ProcessHandleImpl.completion(getPid(), false)
+                .handleAsync((exitStatus, unusedThrowable) -> this);
+    }
+
+    /**
+     * Wait for the process to exit, return the value.
+     * Conditionally reap the value if requested
+     * @param pid the processId
+     * @param reapvalue if true, the value is retrieved,
+     *                   else return the value and leave the process waitable
+     *
+     * @return the value or -1 if an error occurs
+     */
+    private static native int waitForProcessExit0(long pid, boolean reapvalue);
+
+    /**
+     * Cache the ProcessHandle of this process.
+     */
+    private static final ProcessHandleImpl current =
+            new ProcessHandleImpl(getCurrentPid0());
+
+    /**
+     * The pid of this ProcessHandle.
+     */
+    private final long pid;
+
+    /**
+     * Private constructor.  Instances are created by the {@code get(long)} factory.
+     * @param pid the pid for this instance
+     */
+    private ProcessHandleImpl(long pid) {
+        this.pid = pid;
+    }
+
+    /**
+     * Returns a ProcessHandle for an existing native process.
+     *
+     * @param pid the native process identifier
+     * @return The ProcessHandle for the pid if the process is alive;
+     *      or {@code null} if the process ID does not exist in the native system.
+     * @throws SecurityException if RuntimePermission("manageProcess") is not granted
+     */
+    static Optional<ProcessHandle> get(long pid) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new RuntimePermission("manageProcess"));
+        }
+        return Optional.ofNullable(isAlive0(pid) ? new ProcessHandleImpl(pid) : null);
+    }
+
+    /**
+     * Returns a ProcessHandle corresponding known to exist pid.
+     * Called from ProcessImpl, it does not perform a security check or check if the process is alive.
+     * @param pid of the known to exist process
+     * @return a ProcessHandle corresponding to an existing Process instance
+     */
+    static ProcessHandle getUnchecked(long pid) {
+        return new ProcessHandleImpl(pid);
+    }
+
+    /**
+     * Returns the native process ID.
+     * A {@code long} is used to be able to fit the system specific binary values
+     * for the process.
+     *
+     * @return the native process ID
+     */
+    @Override
+    public long getPid() {
+        return pid;
+    }
+
+    /**
+     * Returns the ProcessHandle for the current native process.
+     *
+     * @return The ProcessHandle for the OS process.
+     * @throws SecurityException if RuntimePermission("manageProcess") is not granted
+     */
+    public static ProcessHandleImpl current() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new RuntimePermission("manageProcess"));
+        }
+        return current;
+    }
+
+    /**
+     * Return the pid of the current process.
+     *
+     * @return the pid of the  current process
+     */
+    private static native long getCurrentPid0();
+
+    /**
+     * Returns a ProcessHandle for the parent process.
+     *
+     * @return a ProcessHandle of the parent process; {@code null} is returned
+     *         if the child process does not have a parent
+     * @throws SecurityException           if permission is not granted by the
+     *                                     security policy
+     */
+    static Optional<ProcessHandle> parent(long pid) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new RuntimePermission("manageProcess"));
+        }
+        long ppid = parent0(pid);
+        if (ppid <= 0) {
+            return Optional.empty();
+        }
+        return get(ppid);
+    }
+
+    /**
+     * Returns the parent of the native pid argument.
+     *
+     * @return the parent of the native pid; if any, otherwise -1
+     */
+    private static native long parent0(long pid);
+
+    /**
+     * Returns the number of pids filled in to the array.
+     * @param pid if {@code pid} equals zero, then all known processes are returned;
+     *      otherwise only direct child process pids are returned
+     * @param pids an allocated long array to receive the pids
+     * @param ppids an allocated long array to receive the parent pids; may be null
+     * @return if greater than or equals to zero is the number of pids in the array;
+     *      if greater than the length of the arrays, the arrays are too small
+     */
+    private static native int getProcessPids0(long pid, long[] pids, long[] ppids);
+
+    /**
+     * Destroy the process for this ProcessHandle.
+     * @param pid the processs ID to destroy
+     * @param force {@code true} if the process should be terminated forcibly;
+     *     else {@code false} for a normal termination
+     */
+    static void destroyProcess(long pid, boolean force) {
+        destroy0(pid, force);
+    }
+
+    private static native boolean destroy0(long pid, boolean forcibly);
+
+    @Override
+    public boolean destroy() {
+        if (this.equals(current)) {
+            throw new IllegalStateException("destroy of current process not allowed");
+        }
+        return destroy0(getPid(), false);
+    }
+
+    @Override
+    public boolean destroyForcibly() {
+        if (this.equals(current)) {
+            throw new IllegalStateException("destroy of current process not allowed");
+        }
+        return destroy0(getPid(), true);
+    }
+
+
+    @Override
+    public boolean supportsNormalTermination() {
+        return ProcessImpl.SUPPORTS_NORMAL_TERMINATION;
+    }
+
+    /**
+     * Tests whether the process represented by this {@code ProcessHandle} is alive.
+     *
+     * @return {@code true} if the process represented by this
+     * {@code ProcessHandle} object has not yet terminated.
+     * @since 1.9
+     */
+    @Override
+    public boolean isAlive() {
+        return isAlive0(pid);
+    }
+
+    /**
+     * Returns true or false depending on whether the pid is alive.
+     * This must not reap the exitValue like the isAlive method above.
+     *
+     * @param pid the pid to check
+     * @return true or false
+     */
+    private static native boolean isAlive0(long pid);
+
+    @Override
+    public Optional<ProcessHandle> parent() {
+        return parent(pid);
+    }
+
+    @Override
+    public Stream<ProcessHandle> children() {
+        return children(pid);
+    }
+
+    /**
+     * Returns a Stream of the children of a process or all processes.
+     *
+     * @param pid the pid of the process for which to find the children;
+     *            0 for all processes
+     * @return a stream of ProcessHandles
+     */
+    static Stream<ProcessHandle> children(long pid) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new RuntimePermission("manageProcess"));
+        }
+        int size = 100;
+        long[] childpids = null;
+        while (childpids == null || size > childpids.length) {
+            childpids = new long[size];
+            size = getProcessPids0(pid, childpids, null);
+        }
+        return Arrays.stream(childpids, 0, size).mapToObj((id) -> new ProcessHandleImpl(id));
+    }
+
+    @Override
+    public Stream<ProcessHandle> allChildren() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new RuntimePermission("manageProcess"));
+        }
+        int size = 100;
+        long[] pids = null;
+        long[] ppids = null;
+        while (pids == null || size > pids.length) {
+            pids = new long[size];
+            ppids = new long[size];
+            size = getProcessPids0(0, pids, ppids);
+        }
+
+        int next = 0;       // index of next process to check
+        int count = -1;     // count of subprocesses scanned
+        long ppid = pid;    // start looking for this parent
+        do {
+            // Scan from next to size looking for ppid
+            // if found, exchange it to index next
+            for (int i = next; i < size; i++) {
+                if (ppids[i] == ppid) {
+                    swap(pids, i, next);
+                    swap(ppids, i, next);
+                    next++;
+                }
+            }
+            ppid = pids[++count];   // pick up the next pid to scan for
+        } while (count < next);
+
+        return Arrays.stream(pids, 0, count).mapToObj((id) -> new ProcessHandleImpl(id));
+    }
+
+    // Swap two elements in an array
+    private static void swap(long[] array, int x, int y) {
+        long v = array[x];
+        array[x] = array[y];
+        array[y] = v;
+    }
+
+    @Override
+    public ProcessHandle.Info info() {
+        return ProcessHandleImpl.Info.info(pid);
+    }
+
+    @Override
+    public int compareTo(ProcessHandle other) {
+        return Long.compare(pid, ((ProcessHandleImpl) other).pid);
+    }
+
+    @Override
+    public String toString() {
+        return Long.toString(pid);
+    }
+
+    @Override
+    public int hashCode() {
+        return Long.hashCode(pid);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        return (obj instanceof ProcessHandleImpl) &&
+            (pid == ((ProcessHandleImpl) obj).pid);
+    }
+
+    /**
+     * Implementation of ProcessHandle.Info.
+     * Information snapshot about a process.
+     * The attributes of a process vary by operating system and not available
+     * in all implementations.  Additionally, information about other processes
+     * is limited by the operating system privileges of the process making the request.
+     * If a value is not available, either a {@code null} or {@code -1} is stored.
+     * The accessor methods return {@code null} if the value is not available.
+     */
+    static class Info implements ProcessHandle.Info {
+        static {
+            initIDs();
+        }
+
+        /**
+         * Initialization of JNI fieldIDs.
+         */
+        private static native void initIDs();
+
+        /**
+         * Fill in this Info instance with information about the native process.
+         * If values are not available the native code does not modify the field.
+         * @param pid  of the native process
+         */
+        private native void info0(long pid);
+
+        String command;
+        String[] arguments;
+        long startTime;
+        long totalTime;
+        String user;
+
+        Info() {
+            command = null;
+            arguments = null;
+            startTime = -1L;
+            totalTime = -1L;
+            user = null;
+        }
+
+        /**
+         * Returns the Info object with the fields from the process.
+         * Whatever fields are provided by native are returned.
+         *
+         * @param pid the native process identifier
+         * @return ProcessHandle.Info non-null; individual fields may be null
+         *          or -1 if not available.
+         */
+        public static ProcessHandle.Info info(long pid) {
+            Info info = new Info();
+            info.info0(pid);
+            return info;
+        }
+
+        @Override
+        public Optional<String> command() {
+            return Optional.ofNullable(command);
+        }
+
+        @Override
+        public Optional<String[]> arguments() {
+            return Optional.ofNullable(arguments);
+        }
+
+        @Override
+        public Optional<Instant> startInstant() {
+            return (startTime > 0)
+                    ? Optional.of(Instant.ofEpochMilli(startTime))
+                    : Optional.empty();
+        }
+
+        @Override
+        public Optional<Duration> totalCpuDuration() {
+            return (totalTime != -1)
+                    ? Optional.of(Duration.ofNanos(totalTime))
+                    : Optional.empty();
+        }
+
+        @Override
+        public Optional<String> user() {
+            return Optional.ofNullable(user);
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(60);
+            sb.append('[');
+            if (user != null) {
+                sb.append("user: ");
+                sb.append(user());
+            }
+            if (command != null) {
+                if (sb.length() != 0) sb.append(", ");
+                sb.append("cmd: ");
+                sb.append(command);
+            }
+            if (arguments != null && arguments.length > 0) {
+                if (sb.length() != 0) sb.append(", ");
+                sb.append("args: ");
+                sb.append(Arrays.toString(arguments));
+            }
+            if (startTime != -1) {
+                if (sb.length() != 0) sb.append(", ");
+                sb.append("startTime: ");
+                sb.append(startInstant());
+            }
+            if (totalTime != -1) {
+                if (sb.length() != 0) sb.append(", ");
+                sb.append("totalTime: ");
+                sb.append(totalCpuDuration().toString());
+            }
+            sb.append(']');
+            return sb.toString();
+        }
+    }
+}
--- a/jdk/src/java.base/share/classes/java/lang/RuntimePermission.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/RuntimePermission.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -333,6 +333,12 @@
  *   "../../../technotes/guides/plugin/developer_guide/rsa_how.html#use">
  *   usePolicy Permission</a>.</td>
  * </tr>
+ * <tr>
+ *   <td>manageProcess</td>
+ *   <td>Native process termination and information about processes
+ *       {@link ProcessHandle}.</td>
+ *   <td>Allows code to identify and terminate processes that it did not create.</td>
+ * </tr>
  *
  * <tr>
  *   <td>localeServiceProvider</td>
--- a/jdk/src/java.base/share/classes/java/lang/String.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/String.java	Wed Jul 05 20:37:09 2017 +0200
@@ -2247,8 +2247,29 @@
      * @since 1.5
      */
     public String replace(CharSequence target, CharSequence replacement) {
-        return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(
-                this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
+        String starget = target.toString();
+        String srepl = replacement.toString();
+        int j = indexOf(starget);
+        if (j < 0) {
+            return this;
+        }
+        int targLen = starget.length();
+        int targLen1 = Math.max(targLen, 1);
+        final char[] value = this.value;
+        final char[] replValue = srepl.value;
+        int newLenHint = value.length - targLen + replValue.length;
+        if (newLenHint < 0) {
+            throw new OutOfMemoryError();
+        }
+        StringBuilder sb = new StringBuilder(newLenHint);
+        int i = 0;
+        do {
+            sb.append(value, i, j - i)
+                    .append(replValue);
+            i = j + targLen;
+        } while (j < value.length && (j = indexOf(starget, j + targLen1)) > 0);
+
+        return sb.append(value, i, value.length - i).toString();
     }
 
     /**
--- a/jdk/src/java.base/share/classes/java/net/AbstractPlainSocketImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/net/AbstractPlainSocketImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -312,11 +312,16 @@
             ret = socketGetOption(opt, null);
             return ret;
         case IP_TOS:
-            ret = socketGetOption(opt, null);
-            if (ret == -1) { // ipv6 tos
-                return trafficClass;
-            } else {
-                return ret;
+            try {
+                ret = socketGetOption(opt, null);
+                if (ret == -1) { // ipv6 tos
+                    return trafficClass;
+                } else {
+                    return ret;
+                }
+            } catch (SocketException se) {
+                    // TODO - should make better effort to read TOS or TCLASS
+                    return trafficClass; // ipv6 tos
             }
         case SO_KEEPALIVE:
             ret = socketGetOption(opt, null);
--- a/jdk/src/java.base/share/classes/java/net/DatagramSocket.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/net/DatagramSocket.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1184,7 +1184,14 @@
 
         if (isClosed())
             throw new SocketException("Socket is closed");
-        getImpl().setOption(SocketOptions.IP_TOS, tc);
+        try {
+            getImpl().setOption(SocketOptions.IP_TOS, tc);
+        } catch (SocketException se) {
+            // not supported if socket already connected
+            // Solaris returns error in such cases
+            if(!isConnected())
+                throw se;
+        }
     }
 
     /**
--- a/jdk/src/java.base/share/classes/java/net/Socket.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/net/Socket.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1380,7 +1380,14 @@
 
         if (isClosed())
             throw new SocketException("Socket is closed");
-        getImpl().setOption(SocketOptions.IP_TOS, tc);
+        try {
+            getImpl().setOption(SocketOptions.IP_TOS, tc);
+        } catch (SocketException se) {
+            // not supported if socket already connected
+            // Solaris returns error in such cases
+            if(!isConnected())
+                throw se;
+        }
     }
 
     /**
--- a/jdk/src/java.base/share/classes/java/time/zone/ZoneOffsetTransition.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/time/zone/ZoneOffsetTransition.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -156,6 +156,7 @@
      * @param offsetAfter  the offset at and after the transition, not null
      */
     ZoneOffsetTransition(LocalDateTime transition, ZoneOffset offsetBefore, ZoneOffset offsetAfter) {
+        assert transition.getNano() == 0;
         this.epochSecond = transition.toEpochSecond(offsetBefore);
         this.transition = transition;
         this.offsetBefore = offsetBefore;
@@ -250,7 +251,7 @@
      * @return the transition instant, not null
      */
     public Instant getInstant() {
-        return transition.toInstant(offsetBefore);
+        return Instant.ofEpochSecond(epochSecond);
     }
 
     /**
@@ -403,13 +404,7 @@
      */
     @Override
     public int compareTo(ZoneOffsetTransition transition) {
-        if (epochSecond < transition.epochSecond) {
-            return -1;
-        } else if (epochSecond > transition.epochSecond) {
-            return 1;
-        } else {
-            return this.getInstant().compareTo(transition.getInstant());
-        }
+        return Long.compare(epochSecond, transition.epochSecond);
     }
 
     //-----------------------------------------------------------------------
@@ -429,7 +424,6 @@
         if (other instanceof ZoneOffsetTransition) {
             ZoneOffsetTransition d = (ZoneOffsetTransition) other;
             return epochSecond == d.epochSecond &&
-                transition.equals(d.transition) &&
                 offsetBefore.equals(d.offsetBefore) && offsetAfter.equals(d.offsetAfter);
         }
         return false;
--- a/jdk/src/java.base/share/classes/java/time/zone/ZoneOffsetTransitionRule.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/time/zone/ZoneOffsetTransitionRule.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -167,6 +167,7 @@
      * @return the rule, not null
      * @throws IllegalArgumentException if the day of month indicator is invalid
      * @throws IllegalArgumentException if the end of day flag is true when the time is not midnight
+     * @throws IllegalArgumentException if {@code time.getNano()} returns non-zero value
      */
     public static ZoneOffsetTransitionRule of(
             Month month,
@@ -190,6 +191,9 @@
         if (timeEndOfDay && time.equals(LocalTime.MIDNIGHT) == false) {
             throw new IllegalArgumentException("Time must be midnight when end of day flag is true");
         }
+        if (time.getNano() != 0) {
+            throw new IllegalArgumentException("Time's nano-of-second must be zero");
+        }
         return new ZoneOffsetTransitionRule(month, dayOfMonthIndicator, dayOfWeek, time, timeEndOfDay, timeDefnition, standardOffset, offsetBefore, offsetAfter);
     }
 
@@ -220,6 +224,7 @@
             ZoneOffset standardOffset,
             ZoneOffset offsetBefore,
             ZoneOffset offsetAfter) {
+        assert time.getNano() == 0;
         this.month = month;
         this.dom = (byte) dayOfMonthIndicator;
         this.dow = dayOfWeek;
--- a/jdk/src/java.base/share/classes/java/util/Enumeration.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/Enumeration.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -40,11 +40,14 @@
  * vector, the keys of a hashtable, and the values in a hashtable.
  * Enumerations are also used to specify the input streams to a
  * <code>SequenceInputStream</code>.
- * <p>
- * NOTE: The functionality of this interface is duplicated by the Iterator
- * interface.  In addition, Iterator adds an optional remove operation, and
- * has shorter method names.  New implementations should consider using
- * Iterator in preference to Enumeration.
+ *
+ * @apiNote
+ * The functionality of this interface is duplicated by the {@link Iterator}
+ * interface.  In addition, {@code Iterator} adds an optional remove operation,
+ * and has shorter method names.  New implementations should consider using
+ * {@code Iterator} in preference to {@code Enumeration}. It is possible to
+ * adapt an {@code Enumeration} to an {@code Iterator} by using the
+ * {@link #asIterator} method.
  *
  * @see     java.util.Iterator
  * @see     java.io.SequenceInputStream
@@ -76,4 +79,49 @@
      * @exception  NoSuchElementException  if no more elements exist.
      */
     E nextElement();
+
+    /**
+     * Returns an {@link Iterator} that traverses the remaining elements
+     * covered by this enumeration. Traversal is undefined if any methods
+     * are called on this enumeration after the call to {@code asIterator}.
+     *
+     * @apiNote
+     * This method is intended to help adapt code that produces
+     * {@code Enumeration} instances to code that consumes {@code Iterator}
+     * instances. For example, the {@link java.util.jar.JarFile#entries
+     * JarFile.entries()} method returns an {@code Enumeration<JarEntry>}.
+     * This can be turned into an {@code Iterator}, and then the
+     * {@code forEachRemaining()} method can be used:
+     *
+     * <pre>{@code
+     *     JarFile jarFile = ... ;
+     *     jarFile.entries().asIterator().forEachRemaining(entry -> { ... });
+     * }</pre>
+     *
+     * (Note that there is also a {@link java.util.jar.JarFile#stream
+     * JarFile.stream()} method that returns a {@code Stream} of entries,
+     * which may be more convenient in some cases.)
+     *
+     * @implSpec
+     * The default implementation returns an {@code Iterator} whose
+     * {@link Iterator#hasNext hasNext} method calls this Enumeration's
+     * {@code hasMoreElements} method, whose {@link Iterator#next next}
+     * method calls this Enumeration's {@code nextElement} method, and
+     * whose {@link Iterator#remove remove} method throws
+     * {@code UnsupportedOperationException}.
+     *
+     * @return an Iterator representing the remaining elements of this Enumeration
+     *
+     * @since 1.9
+     */
+    default Iterator<E> asIterator() {
+        return new Iterator<>() {
+            @Override public boolean hasNext() {
+                return hasMoreElements();
+            }
+            @Override public E next() {
+                return nextElement();
+            }
+        };
+    }
 }
--- a/jdk/src/java.base/share/classes/java/util/Iterator.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/java/util/Iterator.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -43,6 +43,10 @@
  * <a href="{@docRoot}/../technotes/guides/collections/index.html">
  * Java Collections Framework</a>.
  *
+ * @apiNote
+ * An {@link Enumeration} can be converted into an {@code Iterator} by
+ * using the {@link Enumeration#asIterator} method.
+ *
  * @param <E> the type of elements returned by this iterator
  *
  * @author  Josh Bloch
--- a/jdk/src/java.base/share/classes/javax/net/ssl/ExtendedSSLSession.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/ExtendedSSLSession.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,7 +28,7 @@
 import java.util.List;
 
 /**
- * Extends the <code>SSLSession</code> interface to support additional
+ * Extends the {@code SSLSession} interface to support additional
  * session attributes.
  *
  * @since 1.7
@@ -39,8 +39,8 @@
      * is willing to use.
      * <p>
      * Note: this method is used to indicate to the peer which signature
-     * algorithms may be used for digital signatures in TLS 1.2. It is
-     * not meaningful for TLS versions prior to 1.2.
+     * algorithms may be used for digital signatures in TLS/DTLS 1.2. It is
+     * not meaningful for TLS/DTLS versions prior to 1.2.
      * <p>
      * The signature algorithm name must be a standard Java Security
      * name (such as "SHA1withRSA", "SHA256withECDSA", and so on).
@@ -52,7 +52,7 @@
      * Note: the local supported signature algorithms should conform to
      * the algorithm constraints specified by
      * {@link SSLParameters#getAlgorithmConstraints getAlgorithmConstraints()}
-     * method in <code>SSLParameters</code>.
+     * method in {@code SSLParameters}.
      *
      * @return An array of supported signature algorithms, in descending
      *     order of preference.  The return value is an empty array if
@@ -67,8 +67,8 @@
      * able to use.
      * <p>
      * Note: this method is used to indicate to the local side which signature
-     * algorithms may be used for digital signatures in TLS 1.2. It is
-     * not meaningful for TLS versions prior to 1.2.
+     * algorithms may be used for digital signatures in TLS/DTLS 1.2. It is
+     * not meaningful for TLS/DTLS versions prior to 1.2.
      * <p>
      * The signature algorithm name must be a standard Java Security
      * name (such as "SHA1withRSA", "SHA256withECDSA", and so on).
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SNIServerName.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SNIServerName.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,7 @@
  * Instances of this class represent a server name in a Server Name
  * Indication (SNI) extension.
  * <P>
- * The SNI extension is a feature that extends the SSL/TLS protocols to
+ * The SNI extension is a feature that extends the SSL/TLS/DTLS protocols to
  * indicate what server name the client is attempting to connect to during
  * handshaking.  See section 3, "Server Name Indication", of <A
  * HREF="http://www.ietf.org/rfc/rfc6066.txt">TLS Extensions (RFC 6066)</A>.
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLContext.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLContext.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,12 +32,12 @@
 /**
  * Instances of this class represent a secure socket protocol
  * implementation which acts as a factory for secure socket
- * factories or <code>SSLEngine</code>s. This class is initialized
+ * factories or {@code SSLEngine}s. This class is initialized
  * with an optional set of key and trust managers and source of
  * secure random bytes.
  *
  * <p> Every implementation of the Java platform is required to support the
- * following standard <code>SSLContext</code> protocol:
+ * following standard {@code SSLContext} protocol:
  * <ul>
  * <li><tt>TLSv1</tt></li>
  * </ul>
@@ -79,7 +79,7 @@
      * <p>If a default context was set using the {@link #setDefault
      * SSLContext.setDefault()} method, it is returned. Otherwise, the first
      * call of this method triggers the call
-     * <code>SSLContext.getInstance("Default")</code>.
+     * {@code SSLContext.getInstance("Default")}.
      * If successful, that object is made the default SSL context and returned.
      *
      * <p>The default context is immediately
@@ -106,8 +106,8 @@
      * @param context the SSLContext
      * @throws  NullPointerException if context is null
      * @throws  SecurityException if a security manager exists and its
-     *          <code>checkPermission</code> method does not allow
-     *          <code>SSLPermission("setDefaultSSLContext")</code>
+     *          {@code checkPermission} method does not allow
+     *          {@code SSLPermission("setDefaultSSLContext")}
      * @since 1.6
      */
     public static synchronized void setDefault(SSLContext context) {
@@ -122,7 +122,7 @@
     }
 
     /**
-     * Returns a <code>SSLContext</code> object that implements the
+     * Returns a {@code SSLContext} object that implements the
      * specified secure socket protocol.
      *
      * <p> This method traverses the list of registered security Providers,
@@ -141,7 +141,7 @@
      *          Documentation</a>
      *          for information about standard protocol names.
      *
-     * @return the new <code>SSLContext</code> object.
+     * @return the new {@code SSLContext} object.
      *
      * @exception NoSuchAlgorithmException if no Provider supports a
      *          SSLContextSpi implementation for the
@@ -159,7 +159,7 @@
     }
 
     /**
-     * Returns a <code>SSLContext</code> object that implements the
+     * Returns a {@code SSLContext} object that implements the
      * specified secure socket protocol.
      *
      * <p> A new SSLContext object encapsulating the
@@ -179,7 +179,7 @@
      *
      * @param provider the name of the provider.
      *
-     * @return the new <code>SSLContext</code> object.
+     * @return the new {@code SSLContext} object.
      *
      * @throws NoSuchAlgorithmException if a SSLContextSpi
      *          implementation for the specified protocol is not
@@ -202,7 +202,7 @@
     }
 
     /**
-     * Returns a <code>SSLContext</code> object that implements the
+     * Returns a {@code SSLContext} object that implements the
      * specified secure socket protocol.
      *
      * <p> A new SSLContext object encapsulating the
@@ -219,7 +219,7 @@
      *
      * @param provider an instance of the provider.
      *
-     * @return the new <code>SSLContext</code> object.
+     * @return the new {@code SSLContext} object.
      *
      * @throws NoSuchAlgorithmException if a SSLContextSpi
      *          implementation for the specified protocol is not available
@@ -239,22 +239,22 @@
     }
 
     /**
-     * Returns the protocol name of this <code>SSLContext</code> object.
+     * Returns the protocol name of this {@code SSLContext} object.
      *
      * <p>This is the same name that was specified in one of the
-     * <code>getInstance</code> calls that created this
-     * <code>SSLContext</code> object.
+     * {@code getInstance} calls that created this
+     * {@code SSLContext} object.
      *
-     * @return the protocol name of this <code>SSLContext</code> object.
+     * @return the protocol name of this {@code SSLContext} object.
      */
     public final String getProtocol() {
         return this.protocol;
     }
 
     /**
-     * Returns the provider of this <code>SSLContext</code> object.
+     * Returns the provider of this {@code SSLContext} object.
      *
-     * @return the provider of this <code>SSLContext</code> object
+     * @return the provider of this {@code SSLContext} object
      */
     public final Provider getProvider() {
         return this.provider;
@@ -283,31 +283,35 @@
     }
 
     /**
-     * Returns a <code>SocketFactory</code> object for this
+     * Returns a {@code SocketFactory} object for this
      * context.
      *
-     * @return the <code>SocketFactory</code> object
+     * @return the {@code SocketFactory} object
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
      * @throws IllegalStateException if the SSLContextImpl requires
-     *          initialization and the <code>init()</code> has not been called
+     *         initialization and the {@code init()} has not been called
      */
     public final SSLSocketFactory getSocketFactory() {
         return contextSpi.engineGetSocketFactory();
     }
 
     /**
-     * Returns a <code>ServerSocketFactory</code> object for
+     * Returns a {@code ServerSocketFactory} object for
      * this context.
      *
-     * @return the <code>ServerSocketFactory</code> object
+     * @return the {@code ServerSocketFactory} object
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
      * @throws IllegalStateException if the SSLContextImpl requires
-     *          initialization and the <code>init()</code> has not been called
+     *         initialization and the {@code init()} has not been called
      */
     public final SSLServerSocketFactory getServerSocketFactory() {
         return contextSpi.engineGetServerSocketFactory();
     }
 
     /**
-     * Creates a new <code>SSLEngine</code> using this context.
+     * Creates a new {@code SSLEngine} using this context.
      * <P>
      * Applications using this factory method are providing no hints
      * for an internal session reuse strategy. If hints are desired,
@@ -317,11 +321,11 @@
      * Some cipher suites (such as Kerberos) require remote hostname
      * information, in which case this factory method should not be used.
      *
-     * @return  the <code>SSLEngine</code> object
+     * @return  the {@code SSLEngine} object
      * @throws  UnsupportedOperationException if the underlying provider
      *          does not implement the operation.
      * @throws  IllegalStateException if the SSLContextImpl requires
-     *          initialization and the <code>init()</code> has not been called
+     *          initialization and the {@code init()} has not been called
      * @since   1.5
      */
     public final SSLEngine createSSLEngine() {
@@ -338,7 +342,7 @@
     }
 
     /**
-     * Creates a new <code>SSLEngine</code> using this context using
+     * Creates a new {@code SSLEngine} using this context using
      * advisory peer information.
      * <P>
      * Applications using this factory method are providing hints
@@ -349,11 +353,11 @@
      *
      * @param   peerHost the non-authoritative name of the host
      * @param   peerPort the non-authoritative port
-     * @return  the new <code>SSLEngine</code> object
+     * @return  the new {@code SSLEngine} object
      * @throws  UnsupportedOperationException if the underlying provider
      *          does not implement the operation.
      * @throws  IllegalStateException if the SSLContextImpl requires
-     *          initialization and the <code>init()</code> has not been called
+     *          initialization and the {@code init()} has not been called
      * @since   1.5
      */
     public final SSLEngine createSSLEngine(String peerHost, int peerPort) {
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLContextSpi.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLContextSpi.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,7 @@
 
 /**
  * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
- * for the <code>SSLContext</code> class.
+ * for the {@code SSLContext} class.
  *
  * <p> All the abstract methods in this class must be implemented by each
  * cryptographic service provider who wishes to supply the implementation
@@ -52,31 +52,35 @@
         SecureRandom sr) throws KeyManagementException;
 
     /**
-     * Returns a <code>SocketFactory</code> object for this
+     * Returns a {@code SocketFactory} object for this
      * context.
      *
-     * @return the <code>SocketFactory</code> object
+     * @return the {@code SocketFactory} object
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
      * @throws IllegalStateException if the SSLContextImpl requires
-     *         initialization and the <code>engineInit()</code>
+     *         initialization and the {@code engineInit()}
      *         has not been called
      * @see javax.net.ssl.SSLContext#getSocketFactory()
      */
     protected abstract SSLSocketFactory engineGetSocketFactory();
 
     /**
-     * Returns a <code>ServerSocketFactory</code> object for
+     * Returns a {@code ServerSocketFactory} object for
      * this context.
      *
-     * @return the <code>ServerSocketFactory</code> object
+     * @return the {@code ServerSocketFactory} object
+     * @throws UnsupportedOperationException if the underlying provider
+     *         does not implement the operation.
      * @throws IllegalStateException if the SSLContextImpl requires
-     *         initialization and the <code>engineInit()</code>
+     *         initialization and the {@code engineInit()}
      *         has not been called
      * @see javax.net.ssl.SSLContext#getServerSocketFactory()
      */
     protected abstract SSLServerSocketFactory engineGetServerSocketFactory();
 
     /**
-     * Creates a new <code>SSLEngine</code> using this context.
+     * Creates a new {@code SSLEngine} using this context.
      * <P>
      * Applications using this factory method are providing no hints
      * for an internal session reuse strategy. If hints are desired,
@@ -86,9 +90,9 @@
      * Some cipher suites (such as Kerberos) require remote hostname
      * information, in which case this factory method should not be used.
      *
-     * @return  the <code>SSLEngine</code> Object
+     * @return  the {@code SSLEngine} Object
      * @throws IllegalStateException if the SSLContextImpl requires
-     *         initialization and the <code>engineInit()</code>
+     *         initialization and the {@code engineInit()}
      *         has not been called
      *
      * @see     SSLContext#createSSLEngine()
@@ -98,7 +102,7 @@
     protected abstract SSLEngine engineCreateSSLEngine();
 
     /**
-     * Creates a <code>SSLEngine</code> using this context.
+     * Creates a {@code SSLEngine} using this context.
      * <P>
      * Applications using this factory method are providing hints
      * for an internal session reuse strategy.
@@ -108,9 +112,9 @@
      *
      * @param host the non-authoritative name of the host
      * @param port the non-authoritative port
-     * @return  the <code>SSLEngine</code> Object
+     * @return  the {@code SSLEngine} Object
      * @throws IllegalStateException if the SSLContextImpl requires
-     *         initialization and the <code>engineInit()</code>
+     *         initialization and the {@code engineInit()}
      *         has not been called
      *
      * @see     SSLContext#createSSLEngine(String, int)
@@ -120,19 +124,19 @@
     protected abstract SSLEngine engineCreateSSLEngine(String host, int port);
 
     /**
-     * Returns a server <code>SSLSessionContext</code> object for
+     * Returns a server {@code SSLSessionContext} object for
      * this context.
      *
-     * @return the <code>SSLSessionContext</code> object
+     * @return the {@code SSLSessionContext} object
      * @see javax.net.ssl.SSLContext#getServerSessionContext()
      */
     protected abstract SSLSessionContext engineGetServerSessionContext();
 
     /**
-     * Returns a client <code>SSLSessionContext</code> object for
+     * Returns a client {@code SSLSessionContext} object for
      * this context.
      *
-     * @return the <code>SSLSessionContext</code> object
+     * @return the {@code SSLSessionContext} object
      * @see javax.net.ssl.SSLContext#getClientSessionContext()
      */
     protected abstract SSLSessionContext engineGetClientSessionContext();
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLEngine.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLEngine.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,15 +37,15 @@
  * <P>
  * The secure communications modes include: <UL>
  *
- *      <LI> <em>Integrity Protection</em>.  SSL/TLS protects against
+ *      <LI> <em>Integrity Protection</em>.  SSL/TLS/DTLS protects against
  *      modification of messages by an active wiretapper.
  *
- *      <LI> <em>Authentication</em>.  In most modes, SSL/TLS provides
+ *      <LI> <em>Authentication</em>.  In most modes, SSL/TLS/DTLS provides
  *      peer authentication.  Servers are usually authenticated, and
  *      clients may be authenticated as requested by servers.
  *
  *      <LI> <em>Confidentiality (Privacy Protection)</em>.  In most
- *      modes, SSL/TLS encrypts data being sent between client and
+ *      modes, SSL/TLS/DTLS encrypts data being sent between client and
  *      server.  This protects the confidentiality of data, so that
  *      passive wiretappers won't see sensitive data such as financial
  *      information or personal information of many kinds.
@@ -65,19 +65,19 @@
  * handshaking has completed, you can access session attributes by
  * using the {@link #getSession()} method.
  * <P>
- * The <code>SSLSocket</code> class provides much of the same security
+ * The {@code SSLSocket} class provides much of the same security
  * functionality, but all of the inbound and outbound data is
  * automatically transported using the underlying {@link
  * java.net.Socket Socket}, which by design uses a blocking model.
  * While this is appropriate for many applications, this model does not
  * provide the scalability required by large servers.
  * <P>
- * The primary distinction of an <code>SSLEngine</code> is that it
+ * The primary distinction of an {@code SSLEngine} is that it
  * operates on inbound and outbound byte streams, independent of the
  * transport mechanism.  It is the responsibility of the
- * <code>SSLEngine</code> user to arrange for reliable I/O transport to
- * the peer.  By separating the SSL/TLS abstraction from the I/O
- * transport mechanism, the <code>SSLEngine</code> can be used for a
+ * {@code SSLEngine} user to arrange for reliable I/O transport to
+ * the peer.  By separating the SSL/TLS/DTLS abstraction from the I/O
+ * transport mechanism, the {@code SSLEngine} can be used for a
  * wide variety of I/O types, such as {@link
  * java.nio.channels.spi.AbstractSelectableChannel#configureBlocking(boolean)
  * non-blocking I/O (polling)}, {@link java.nio.channels.Selector
@@ -87,7 +87,7 @@
  * HREF="http://www.jcp.org/en/jsr/detail?id=203"> future asynchronous
  * I/O models </A>, and so on.
  * <P>
- * At a high level, the <code>SSLEngine</code> appears thus:
+ * At a high level, the {@code SSLEngine} appears thus:
  *
  * <pre>
  *                   app data
@@ -115,18 +115,18 @@
  * mechanism.  Inbound data is data which has been received from the
  * peer, and outbound data is destined for the peer.
  * <P>
- * (In the context of an <code>SSLEngine</code>, the term "handshake
+ * (In the context of an {@code SSLEngine}, the term "handshake
  * data" is taken to mean any data exchanged to establish and control a
- * secure connection.  Handshake data includes the SSL/TLS messages
+ * secure connection.  Handshake data includes the SSL/TLS/DTLS messages
  * "alert", "change_cipher_spec," and "handshake.")
  * <P>
- * There are five distinct phases to an <code>SSLEngine</code>.
+ * There are five distinct phases to an {@code SSLEngine}.
  *
  * <OL>
- *     <li> Creation - The <code>SSLEngine</code> has been created and
+ *     <li> Creation - The {@code SSLEngine} has been created and
  *     initialized, but has not yet been used.  During this phase, an
- *     application may set any <code>SSLEngine</code>-specific settings
- *     (enabled cipher suites, whether the <code>SSLEngine</code> should
+ *     application may set any {@code SSLEngine}-specific settings
+ *     (enabled cipher suites, whether the {@code SSLEngine} should
  *     handshake in client or server mode, and so on).  Once
  *     handshaking has begun, though, any new settings (except
  *     client/server mode, see below) will be used for
@@ -139,7 +139,7 @@
  *
  *     <li> Application Data - Once the communication parameters have
  *     been established and the handshake is complete, application data
- *     may flow through the <code>SSLEngine</code>.  Outbound
+ *     may flow through the {@code SSLEngine}.  Outbound
  *     application messages are encrypted and integrity protected,
  *     and inbound messages reverse the process.
  *
@@ -147,50 +147,50 @@
  *     the session at any time during the Application Data phase.  New
  *     handshaking data can be intermixed among the application data.
  *     Before starting the rehandshake phase, the application may
- *     reset the SSL/TLS communication parameters such as the list of
+ *     reset the SSL/TLS/DTLS communication parameters such as the list of
  *     enabled ciphersuites and whether to use client authentication,
  *     but can not change between client/server modes.  As before, once
- *     handshaking has begun, any new <code>SSLEngine</code>
+ *     handshaking has begun, any new {@code SSLEngine}
  *     configuration settings will not be used until the next
  *     handshake.
  *
  *     <li>  Closure - When the connection is no longer needed, the
- *     application should close the <code>SSLEngine</code> and should
+ *     application should close the {@code SSLEngine} and should
  *     send/receive any remaining messages to the peer before
  *     closing the underlying transport mechanism.  Once an engine is
- *     closed, it is not reusable:  a new <code>SSLEngine</code> must
+ *     closed, it is not reusable:  a new {@code SSLEngine} must
  *     be created.
  * </OL>
- * An <code>SSLEngine</code> is created by calling {@link
+ * An {@code SSLEngine} is created by calling {@link
  * SSLContext#createSSLEngine()} from an initialized
- * <code>SSLContext</code>.  Any configuration
+ * {@code SSLContext}.  Any configuration
  * parameters should be set before making the first call to
- * <code>wrap()</code>, <code>unwrap()</code>, or
- * <code>beginHandshake()</code>.  These methods all trigger the
+ * {@code wrap()}, {@code unwrap()}, or
+ * {@code beginHandshake()}.  These methods all trigger the
  * initial handshake.
  * <P>
  * Data moves through the engine by calling {@link #wrap(ByteBuffer,
  * ByteBuffer) wrap()} or {@link #unwrap(ByteBuffer, ByteBuffer)
  * unwrap()} on outbound or inbound data, respectively.  Depending on
- * the state of the <code>SSLEngine</code>, a <code>wrap()</code> call
+ * the state of the {@code SSLEngine}, a {@code wrap()} call
  * may consume application data from the source buffer and may produce
  * network data in the destination buffer.  The outbound data
  * may contain application and/or handshake data.  A call to
- * <code>unwrap()</code> will examine the source buffer and may
+ * {@code unwrap()} will examine the source buffer and may
  * advance the handshake if the data is handshaking information, or
  * may place application data in the destination buffer if the data
- * is application.  The state of the underlying SSL/TLS algorithm
+ * is application.  The state of the underlying SSL/TLS/DTLS algorithm
  * will determine when data is consumed and produced.
  * <P>
- * Calls to <code>wrap()</code> and <code>unwrap()</code> return an
- * <code>SSLEngineResult</code> which indicates the status of the
+ * Calls to {@code wrap()} and {@code unwrap()} return an
+ * {@code SSLEngineResult} which indicates the status of the
  * operation, and (optionally) how to interact with the engine to make
  * progress.
  * <P>
- * The <code>SSLEngine</code> produces/consumes complete SSL/TLS
+ * The {@code SSLEngine} produces/consumes complete SSL/TLS/DTLS
  * packets only, and does not store application data internally between
- * calls to <code>wrap()/unwrap()</code>.  Thus input and output
- * <code>ByteBuffer</code>s must be sized appropriately to hold the
+ * calls to {@code wrap()/unwrap()}.  Thus input and output
+ * {@code ByteBuffer}s must be sized appropriately to hold the
  * maximum record that can be produced.  Calls to {@link
  * SSLSession#getPacketBufferSize()} and {@link
  * SSLSession#getApplicationBufferSize()} should be used to determine
@@ -200,12 +200,12 @@
  * must determine (via {@link SSLEngineResult}) and correct the
  * problem, and then try the call again.
  * <P>
- * For example, <code>unwrap()</code> will return a {@link
+ * For example, {@code unwrap()} will return a {@link
  * SSLEngineResult.Status#BUFFER_OVERFLOW} result if the engine
  * determines that there is not enough destination buffer space available.
  * Applications should call {@link SSLSession#getApplicationBufferSize()}
  * and compare that value with the space available in the destination buffer,
- * enlarging the buffer if necessary.  Similarly, if <code>unwrap()</code>
+ * enlarging the buffer if necessary.  Similarly, if {@code unwrap()}
  * were to return a {@link SSLEngineResult.Status#BUFFER_UNDERFLOW}, the
  * application should call {@link SSLSession#getPacketBufferSize()} to ensure
  * that the source buffer has enough room to hold a record (enlarging if
@@ -241,8 +241,8 @@
  * }</pre>
  *
  * <P>
- * Unlike <code>SSLSocket</code>, all methods of SSLEngine are
- * non-blocking.  <code>SSLEngine</code> implementations may
+ * Unlike {@code SSLSocket}, all methods of SSLEngine are
+ * non-blocking.  {@code SSLEngine} implementations may
  * require the results of tasks that may take an extended period of
  * time to complete, or may even block.  For example, a TrustManager
  * may need to connect to a remote certificate validation service,
@@ -252,8 +252,8 @@
  * seemingly blocking.
  * <P>
  * For any operation which may potentially block, the
- * <code>SSLEngine</code> will create a {@link java.lang.Runnable}
- * delegated task.  When <code>SSLEngineResult</code> indicates that a
+ * {@code SSLEngine} will create a {@link java.lang.Runnable}
+ * delegated task.  When {@code SSLEngineResult} indicates that a
  * delegated task result is needed, the application must call {@link
  * #getDelegatedTask()} to obtain an outstanding delegated task and
  * call its {@link java.lang.Runnable#run() run()} method (possibly using
@@ -262,16 +262,16 @@
  * exist, and try the original operation again.
  * <P>
  * At the end of a communication session, applications should properly
- * close the SSL/TLS link.  The SSL/TLS protocols have closure handshake
- * messages, and these messages should be communicated to the peer
- * before releasing the <code>SSLEngine</code> and closing the
+ * close the SSL/TLS/DTLS link.  The SSL/TLS/DTLS protocols have closure
+ * handshake messages, and these messages should be communicated to the
+ * peer before releasing the {@code SSLEngine} and closing the
  * underlying transport mechanism.  A close can be initiated by one of:
  * an SSLException, an inbound closure handshake message, or one of the
  * close methods.  In all cases, closure handshake messages are
- * generated by the engine, and <code>wrap()</code> should be repeatedly
- * called until the resulting <code>SSLEngineResult</code>'s status
+ * generated by the engine, and {@code wrap()} should be repeatedly
+ * called until the resulting {@code SSLEngineResult}'s status
  * returns "CLOSED", or {@link #isOutboundDone()} returns true.  All
- * data obtained from the <code>wrap()</code> method should be sent to the
+ * data obtained from the {@code wrap()} method should be sent to the
  * peer.
  * <P>
  * {@link #closeOutbound()} is used to signal the engine that the
@@ -279,12 +279,12 @@
  * <P>
  * A peer will signal its intent to close by sending its own closure
  * handshake message.  After this message has been received and
- * processed by the local <code>SSLEngine</code>'s <code>unwrap()</code>
+ * processed by the local {@code SSLEngine}'s {@code unwrap()}
  * call, the application can detect the close by calling
- * <code>unwrap()</code> and looking for a <code>SSLEngineResult</code>
+ * {@code unwrap()} and looking for a {@code SSLEngineResult}
  * with status "CLOSED", or if {@link #isInboundDone()} returns true.
  * If for some reason the peer closes the communication link without
- * sending the proper SSL/TLS closure message, the application can
+ * sending the proper SSL/TLS/DTLS closure message, the application can
  * detect the end-of-stream and can signal the engine via {@link
  * #closeInbound()} that there will no more inbound messages to
  * process.  Some applications might choose to require orderly shutdown
@@ -315,16 +315,16 @@
  * and/or non-private (unencrypted) communications will such a
  * cipher suite be selected.
  * <P>
- * Each SSL/TLS connection must have one client and one server, thus
+ * Each SSL/TLS/DTLS connection must have one client and one server, thus
  * each endpoint must decide which role to assume.  This choice determines
  * who begins the handshaking process as well as which type of messages
  * should be sent by each party.  The method {@link
  * #setUseClientMode(boolean)} configures the mode.  Once the initial
- * handshaking has started, an <code>SSLEngine</code> can not switch
+ * handshaking has started, an {@code SSLEngine} can not switch
  * between client and server modes, even when performing renegotiations.
  * <P>
  * Applications might choose to process delegated tasks in different
- * threads.  When an <code>SSLEngine</code>
+ * threads.  When an {@code SSLEngine}
  * is created, the current {@link java.security.AccessControlContext}
  * is saved.  All future delegated tasks will be processed using this
  * context:  that is, all access control decisions will be made using the
@@ -336,10 +336,10 @@
  * There are two concurrency issues to be aware of:
  *
  * <OL>
- *      <li>The <code>wrap()</code> and <code>unwrap()</code> methods
+ *      <li>The {@code wrap()} and {@code unwrap()} methods
  *      may execute concurrently of each other.
  *
- *      <li> The SSL/TLS protocols employ ordered packets.
+ *      <li> The SSL/TLS/DTLS protocols employ ordered packets.
  *      Applications must take care to ensure that generated packets
  *      are delivered in sequence.  If packets arrive
  *      out-of-order, unexpected or fatal results may occur.
@@ -354,7 +354,7 @@
  *      </pre>
  *
  *      As a corollary, two threads must not attempt to call the same method
- *      (either <code>wrap()</code> or <code>unwrap()</code>) concurrently,
+ *      (either {@code wrap()} or {@code unwrap()}) concurrently,
  *      because there is no way to guarantee the eventual packet ordering.
  * </OL>
  *
@@ -374,7 +374,7 @@
     private int peerPort = -1;
 
     /**
-     * Constructor for an <code>SSLEngine</code> providing no hints
+     * Constructor for an {@code SSLEngine} providing no hints
      * for an internal session reuse strategy.
      *
      * @see     SSLContext#createSSLEngine()
@@ -384,10 +384,10 @@
     }
 
     /**
-     * Constructor for an <code>SSLEngine</code>.
+     * Constructor for an {@code SSLEngine}.
      * <P>
-     * <code>SSLEngine</code> implementations may use the
-     * <code>peerHost</code> and <code>peerPort</code> parameters as hints
+     * {@code SSLEngine} implementations may use the
+     * {@code peerHost} and {@code peerPort} parameters as hints
      * for their internal session reuse strategy.
      * <P>
      * Some cipher suites (such as Kerberos) require remote hostname
@@ -395,7 +395,7 @@
      * constructor to use Kerberos.
      * <P>
      * The parameters are not authenticated by the
-     * <code>SSLEngine</code>.
+     * {@code SSLEngine}.
      *
      * @param   peerHost the name of the peer host
      * @param   peerPort the port number of the peer
@@ -435,7 +435,7 @@
 
     /**
      * Attempts to encode a buffer of plaintext application data into
-     * SSL/TLS network data.
+     * SSL/TLS/DTLS network data.
      * <P>
      * An invocation of this method behaves in exactly the same manner
      * as the invocation:
@@ -445,20 +445,20 @@
      * </pre></blockquote>
      *
      * @param   src
-     *          a <code>ByteBuffer</code> containing outbound application data
+     *          a {@code ByteBuffer} containing outbound application data
      * @param   dst
-     *          a <code>ByteBuffer</code> to hold outbound network data
-     * @return  an <code>SSLEngineResult</code> describing the result
+     *          a {@code ByteBuffer} to hold outbound network data
+     * @return  an {@code SSLEngineResult} describing the result
      *          of this operation.
      * @throws  SSLException
      *          A problem was encountered while processing the
-     *          data that caused the <code>SSLEngine</code> to abort.
+     *          data that caused the {@code SSLEngine} to abort.
      *          See the class description for more information on
      *          engine closure.
      * @throws  ReadOnlyBufferException
-     *          if the <code>dst</code> buffer is read-only.
+     *          if the {@code dst} buffer is read-only.
      * @throws  IllegalArgumentException
-     *          if either <code>src</code> or <code>dst</code>
+     *          if either {@code src} or {@code dst}
      *          is null.
      * @throws  IllegalStateException if the client/server mode
      *          has not yet been set.
@@ -471,7 +471,7 @@
 
     /**
      * Attempts to encode plaintext bytes from a sequence of data
-     * buffers into SSL/TLS network data.
+     * buffers into SSL/TLS/DTLS network data.
      * <P>
      * An invocation of this method behaves in exactly the same manner
      * as the invocation:
@@ -481,22 +481,22 @@
      * </pre></blockquote>
      *
      * @param   srcs
-     *          an array of <code>ByteBuffers</code> containing the
+     *          an array of {@code ByteBuffers} containing the
      *          outbound application data
      * @param   dst
-     *          a <code>ByteBuffer</code> to hold outbound network data
-     * @return  an <code>SSLEngineResult</code> describing the result
+     *          a {@code ByteBuffer} to hold outbound network data
+     * @return  an {@code SSLEngineResult} describing the result
      *          of this operation.
      * @throws  SSLException
      *          A problem was encountered while processing the
-     *          data that caused the <code>SSLEngine</code> to abort.
+     *          data that caused the {@code SSLEngine} to abort.
      *          See the class description for more information on
      *          engine closure.
      * @throws  ReadOnlyBufferException
-     *          if the <code>dst</code> buffer is read-only.
+     *          if the {@code dst} buffer is read-only.
      * @throws  IllegalArgumentException
-     *          if either <code>srcs</code> or <code>dst</code>
-     *          is null, or if any element in <code>srcs</code> is null.
+     *          if either {@code srcs} or {@code dst}
+     *          is null, or if any element in {@code srcs} is null.
      * @throws  IllegalStateException if the client/server mode
      *          has not yet been set.
      * @see     #wrap(ByteBuffer [], int, int, ByteBuffer)
@@ -512,7 +512,7 @@
 
     /**
      * Attempts to encode plaintext bytes from a subsequence of data
-     * buffers into SSL/TLS network data.  This <i>"gathering"</i>
+     * buffers into SSL/TLS/DTLS network data.  This <i>"gathering"</i>
      * operation encodes, in a single invocation, a sequence of bytes
      * from one or more of a given sequence of buffers.  Gathering
      * wraps are often useful when implementing network protocols or
@@ -535,49 +535,49 @@
      * it was generated.  The application must properly synchronize
      * multiple calls to this method.
      * <P>
-     * If this <code>SSLEngine</code> has not yet started its initial
+     * If this {@code SSLEngine} has not yet started its initial
      * handshake, this method will automatically start the handshake.
      * <P>
-     * This method will attempt to produce SSL/TLS records, and will
+     * This method will attempt to produce SSL/TLS/DTLS records, and will
      * consume as much source data as possible, but will never consume
      * more than the sum of the bytes remaining in each buffer.  Each
-     * <code>ByteBuffer</code>'s position is updated to reflect the
+     * {@code ByteBuffer}'s position is updated to reflect the
      * amount of data consumed or produced.  The limits remain the
      * same.
      * <P>
-     * The underlying memory used by the <code>srcs</code> and
-     * <code>dst ByteBuffer</code>s must not be the same.
+     * The underlying memory used by the {@code srcs} and
+     * {@code dst ByteBuffer}s must not be the same.
      * <P>
      * See the class description for more information on engine closure.
      *
      * @param   srcs
-     *          an array of <code>ByteBuffers</code> containing the
+     *          an array of {@code ByteBuffers} containing the
      *          outbound application data
      * @param   offset
      *          The offset within the buffer array of the first buffer from
      *          which bytes are to be retrieved; it must be non-negative
-     *          and no larger than <code>srcs.length</code>
+     *          and no larger than {@code srcs.length}
      * @param   length
      *          The maximum number of buffers to be accessed; it must be
      *          non-negative and no larger than
-     *          <code>srcs.length</code>&nbsp;-&nbsp;<code>offset</code>
+     *          {@code srcs.length}&nbsp;-&nbsp;{@code offset}
      * @param   dst
-     *          a <code>ByteBuffer</code> to hold outbound network data
-     * @return  an <code>SSLEngineResult</code> describing the result
+     *          a {@code ByteBuffer} to hold outbound network data
+     * @return  an {@code SSLEngineResult} describing the result
      *          of this operation.
      * @throws  SSLException
      *          A problem was encountered while processing the
-     *          data that caused the <code>SSLEngine</code> to abort.
+     *          data that caused the {@code SSLEngine} to abort.
      *          See the class description for more information on
      *          engine closure.
      * @throws  IndexOutOfBoundsException
-     *          if the preconditions on the <code>offset</code> and
-     *          <code>length</code> parameters do not hold.
+     *          if the preconditions on the {@code offset} and
+     *          {@code length} parameters do not hold.
      * @throws  ReadOnlyBufferException
-     *          if the <code>dst</code> buffer is read-only.
+     *          if the {@code dst} buffer is read-only.
      * @throws  IllegalArgumentException
-     *          if either <code>srcs</code> or <code>dst</code>
-     *          is null, or if any element in the <code>srcs</code>
+     *          if either {@code srcs} or {@code dst}
+     *          is null, or if any element in the {@code srcs}
      *          subsequence specified is null.
      * @throws  IllegalStateException if the client/server mode
      *          has not yet been set.
@@ -589,7 +589,7 @@
             int length, ByteBuffer dst) throws SSLException;
 
     /**
-     * Attempts to decode SSL/TLS network data into a plaintext
+     * Attempts to decode SSL/TLS/DTLS network data into a plaintext
      * application data buffer.
      * <P>
      * An invocation of this method behaves in exactly the same manner
@@ -600,20 +600,20 @@
      * </pre></blockquote>
      *
      * @param   src
-     *          a <code>ByteBuffer</code> containing inbound network data.
+     *          a {@code ByteBuffer} containing inbound network data.
      * @param   dst
-     *          a <code>ByteBuffer</code> to hold inbound application data.
-     * @return  an <code>SSLEngineResult</code> describing the result
+     *          a {@code ByteBuffer} to hold inbound application data.
+     * @return  an {@code SSLEngineResult} describing the result
      *          of this operation.
      * @throws  SSLException
      *          A problem was encountered while processing the
-     *          data that caused the <code>SSLEngine</code> to abort.
+     *          data that caused the {@code SSLEngine} to abort.
      *          See the class description for more information on
      *          engine closure.
      * @throws  ReadOnlyBufferException
-     *          if the <code>dst</code> buffer is read-only.
+     *          if the {@code dst} buffer is read-only.
      * @throws  IllegalArgumentException
-     *          if either <code>src</code> or <code>dst</code>
+     *          if either {@code src} or {@code dst}
      *          is null.
      * @throws  IllegalStateException if the client/server mode
      *          has not yet been set.
@@ -625,7 +625,7 @@
     }
 
     /**
-     * Attempts to decode SSL/TLS network data into a sequence of plaintext
+     * Attempts to decode SSL/TLS/DTLS network data into a sequence of plaintext
      * application data buffers.
      * <P>
      * An invocation of this method behaves in exactly the same manner
@@ -636,22 +636,22 @@
      * </pre></blockquote>
      *
      * @param   src
-     *          a <code>ByteBuffer</code> containing inbound network data.
+     *          a {@code ByteBuffer} containing inbound network data.
      * @param   dsts
-     *          an array of <code>ByteBuffer</code>s to hold inbound
+     *          an array of {@code ByteBuffer}s to hold inbound
      *          application data.
-     * @return  an <code>SSLEngineResult</code> describing the result
+     * @return  an {@code SSLEngineResult} describing the result
      *          of this operation.
      * @throws  SSLException
      *          A problem was encountered while processing the
-     *          data that caused the <code>SSLEngine</code> to abort.
+     *          data that caused the {@code SSLEngine} to abort.
      *          See the class description for more information on
      *          engine closure.
      * @throws  ReadOnlyBufferException
-     *          if any of the <code>dst</code> buffers are read-only.
+     *          if any of the {@code dst} buffers are read-only.
      * @throws  IllegalArgumentException
-     *          if either <code>src</code> or <code>dsts</code>
-     *          is null, or if any element in <code>dsts</code> is null.
+     *          if either {@code src} or {@code dsts}
+     *          is null, or if any element in {@code dsts} is null.
      * @throws  IllegalStateException if the client/server mode
      *          has not yet been set.
      * @see     #unwrap(ByteBuffer, ByteBuffer [], int, int)
@@ -665,7 +665,7 @@
     }
 
     /**
-     * Attempts to decode SSL/TLS network data into a subsequence of
+     * Attempts to decode SSL/TLS/DTLS network data into a subsequence of
      * plaintext application data buffers.  This <i>"scattering"</i>
      * operation decodes, in a single invocation, a sequence of bytes
      * into one or more of a given sequence of buffers.  Scattering
@@ -688,55 +688,55 @@
      * order it was received.  The application must properly synchronize
      * multiple calls to this method.
      * <P>
-     * If this <code>SSLEngine</code> has not yet started its initial
+     * If this {@code SSLEngine} has not yet started its initial
      * handshake, this method will automatically start the handshake.
      * <P>
-     * This method will attempt to consume one complete SSL/TLS network
+     * This method will attempt to consume one complete SSL/TLS/DTLS network
      * packet, but will never consume more than the sum of the bytes
-     * remaining in the buffers.  Each <code>ByteBuffer</code>'s
+     * remaining in the buffers.  Each {@code ByteBuffer}'s
      * position is updated to reflect the amount of data consumed or
      * produced.  The limits remain the same.
      * <P>
-     * The underlying memory used by the <code>src</code> and
-     * <code>dsts ByteBuffer</code>s must not be the same.
+     * The underlying memory used by the {@code src} and
+     * {@code dsts ByteBuffer}s must not be the same.
      * <P>
      * The inbound network buffer may be modified as a result of this
      * call:  therefore if the network data packet is required for some
      * secondary purpose, the data should be duplicated before calling this
      * method.  Note:  the network data will not be useful to a second
      * SSLEngine, as each SSLEngine contains unique random state which
-     * influences the SSL/TLS messages.
+     * influences the SSL/TLS/DTLS messages.
      * <P>
      * See the class description for more information on engine closure.
      *
      * @param   src
-     *          a <code>ByteBuffer</code> containing inbound network data.
+     *          a {@code ByteBuffer} containing inbound network data.
      * @param   dsts
-     *          an array of <code>ByteBuffer</code>s to hold inbound
+     *          an array of {@code ByteBuffer}s to hold inbound
      *          application data.
      * @param   offset
      *          The offset within the buffer array of the first buffer from
      *          which bytes are to be transferred; it must be non-negative
-     *          and no larger than <code>dsts.length</code>.
+     *          and no larger than {@code dsts.length}.
      * @param   length
      *          The maximum number of buffers to be accessed; it must be
      *          non-negative and no larger than
-     *          <code>dsts.length</code>&nbsp;-&nbsp;<code>offset</code>.
-     * @return  an <code>SSLEngineResult</code> describing the result
+     *          {@code dsts.length}&nbsp;-&nbsp;{@code offset}.
+     * @return  an {@code SSLEngineResult} describing the result
      *          of this operation.
      * @throws  SSLException
      *          A problem was encountered while processing the
-     *          data that caused the <code>SSLEngine</code> to abort.
+     *          data that caused the {@code SSLEngine} to abort.
      *          See the class description for more information on
      *          engine closure.
      * @throws  IndexOutOfBoundsException
-     *          If the preconditions on the <code>offset</code> and
-     *          <code>length</code> parameters do not hold.
+     *          If the preconditions on the {@code offset} and
+     *          {@code length} parameters do not hold.
      * @throws  ReadOnlyBufferException
-     *          if any of the <code>dst</code> buffers are read-only.
+     *          if any of the {@code dst} buffers are read-only.
      * @throws  IllegalArgumentException
-     *          if either <code>src</code> or <code>dsts</code>
-     *          is null, or if any element in the <code>dsts</code>
+     *          if either {@code src} or {@code dsts}
+     *          is null, or if any element in the {@code dsts}
      *          subsequence specified is null.
      * @throws  IllegalStateException if the client/server mode
      *          has not yet been set.
@@ -749,19 +749,19 @@
 
 
     /**
-     * Returns a delegated <code>Runnable</code> task for
-     * this <code>SSLEngine</code>.
+     * Returns a delegated {@code Runnable} task for
+     * this {@code SSLEngine}.
      * <P>
-     * <code>SSLEngine</code> operations may require the results of
+     * {@code SSLEngine} operations may require the results of
      * operations that block, or may take an extended period of time to
      * complete.  This method is used to obtain an outstanding {@link
      * java.lang.Runnable} operation (task).  Each task must be assigned
      * a thread (possibly the current) to perform the {@link
      * java.lang.Runnable#run() run} operation.  Once the
-     * <code>run</code> method returns, the <code>Runnable</code> object
+     * {@code run} method returns, the {@code Runnable} object
      * is no longer needed and may be discarded.
      * <P>
-     * Delegated tasks run in the <code>AccessControlContext</code>
+     * Delegated tasks run in the {@code AccessControlContext}
      * in place when this object was created.
      * <P>
      * A call to this method will return each outstanding task
@@ -769,7 +769,7 @@
      * <P>
      * Multiple delegated tasks can be run in parallel.
      *
-     * @return  a delegated <code>Runnable</code> task, or null
+     * @return  a delegated {@code Runnable} task, or null
      *          if none are available.
      */
     public abstract Runnable getDelegatedTask();
@@ -777,7 +777,7 @@
 
     /**
      * Signals that no more inbound network data will be sent
-     * to this <code>SSLEngine</code>.
+     * to this {@code SSLEngine}.
      * <P>
      * If the application initiated the closing process by calling
      * {@link #closeOutbound()}, under some circumstances it is not
@@ -789,9 +789,9 @@
      * <P>
      * But if the application did not initiate the closure process, or
      * if the circumstances above do not apply, this method should be
-     * called whenever the end of the SSL/TLS data stream is reached.
+     * called whenever the end of the SSL/TLS/DTLS data stream is reached.
      * This ensures closure of the inbound side, and checks that the
-     * peer followed the SSL/TLS close procedure properly, thus
+     * peer followed the SSL/TLS/DTLS close procedure properly, thus
      * detecting possible truncation attacks.
      * <P>
      * This method is idempotent:  if the inbound side has already
@@ -801,7 +801,7 @@
      * called to flush any remaining handshake data.
      *
      * @throws  SSLException
-     *          if this engine has not received the proper SSL/TLS close
+     *          if this engine has not received the proper SSL/TLS/DTLS close
      *          notification message from the peer.
      *
      * @see     #isInboundDone()
@@ -814,7 +814,7 @@
      * Returns whether {@link #unwrap(ByteBuffer, ByteBuffer)} will
      * accept any more inbound data messages.
      *
-     * @return  true if the <code>SSLEngine</code> will not
+     * @return  true if the {@code SSLEngine} will not
      *          consume anymore network data (and by implication,
      *          will not produce any more application data.)
      * @see     #closeInbound()
@@ -824,7 +824,7 @@
 
     /**
      * Signals that no more outbound application data will be sent
-     * on this <code>SSLEngine</code>.
+     * on this {@code SSLEngine}.
      * <P>
      * This method is idempotent:  if the outbound side has already
      * been closed, this method does not do anything.
@@ -841,12 +841,12 @@
      * Returns whether {@link #wrap(ByteBuffer, ByteBuffer)} will
      * produce any more outbound data messages.
      * <P>
-     * Note that during the closure phase, a <code>SSLEngine</code> may
+     * Note that during the closure phase, a {@code SSLEngine} may
      * generate handshake closure data that must be sent to the peer.
-     * <code>wrap()</code> must be called to generate this data.  When
+     * {@code wrap()} must be called to generate this data.  When
      * this method returns true, no more outbound data will be created.
      *
-     * @return  true if the <code>SSLEngine</code> will not produce
+     * @return  true if the {@code SSLEngine} will not produce
      *          any more network data
      *
      * @see     #closeOutbound()
@@ -890,10 +890,10 @@
     /**
      * Sets the cipher suites enabled for use on this engine.
      * <P>
-     * Each cipher suite in the <code>suites</code> parameter must have
+     * Each cipher suite in the {@code suites} parameter must have
      * been listed by getSupportedCipherSuites(), or the method will
      * fail.  Following a successful call to this method, only suites
-     * listed in the <code>suites</code> parameter are enabled for use.
+     * listed in the {@code suites} parameter are enabled for use.
      * <P>
      * See {@link #getEnabledCipherSuites()} for more information
      * on why a specific cipher suite may never be used on a engine.
@@ -910,7 +910,7 @@
 
     /**
      * Returns the names of the protocols which could be enabled for use
-     * with this <code>SSLEngine</code>.
+     * with this {@code SSLEngine}.
      *
      * @return  an array of protocols supported
      */
@@ -919,7 +919,7 @@
 
     /**
      * Returns the names of the protocol versions which are currently
-     * enabled for use with this <code>SSLEngine</code>.
+     * enabled for use with this {@code SSLEngine}.
      *
      * @return  an array of protocols
      * @see     #setEnabledProtocols(String [])
@@ -932,7 +932,7 @@
      * <P>
      * The protocols must have been listed by getSupportedProtocols()
      * as being supported.  Following a successful call to this method,
-     * only protocols listed in the <code>protocols</code> parameter
+     * only protocols listed in the {@code protocols} parameter
      * are enabled for use.
      *
      * @param   protocols Names of all the protocols to enable.
@@ -945,8 +945,8 @@
 
 
     /**
-     * Returns the <code>SSLSession</code> in use in this
-     * <code>SSLEngine</code>.
+     * Returns the {@code SSLSession} in use in this
+     * {@code SSLEngine}.
      * <P>
      * These can be long lived, and frequently correspond to an entire
      * login session for some user.  The session specifies a particular
@@ -961,22 +961,22 @@
      * a session object which reports an invalid cipher suite of
      * "SSL_NULL_WITH_NULL_NULL".
      *
-     * @return  the <code>SSLSession</code> for this <code>SSLEngine</code>
+     * @return  the {@code SSLSession} for this {@code SSLEngine}
      * @see     SSLSession
      */
     public abstract SSLSession getSession();
 
 
     /**
-     * Returns the {@code SSLSession} being constructed during a SSL/TLS
+     * Returns the {@code SSLSession} being constructed during a SSL/TLS/DTLS
      * handshake.
      * <p>
-     * TLS protocols may negotiate parameters that are needed when using
+     * TLS/DTLS protocols may negotiate parameters that are needed when using
      * an instance of this class, but before the {@code SSLSession} has
      * been completely initialized and made available via {@code getSession}.
      * For example, the list of valid signature algorithms may restrict
      * the type of certificates that can used during TrustManager
-     * decisions, or the maximum TLS fragment packet sizes can be
+     * decisions, or the maximum TLS/DTLS fragment packet sizes can be
      * resized to better support the network environment.
      * <p>
      * This method provides early access to the {@code SSLSession} being
@@ -1012,26 +1012,26 @@
      * Initiates handshaking (initial or renegotiation) on this SSLEngine.
      * <P>
      * This method is not needed for the initial handshake, as the
-     * <code>wrap()</code> and <code>unwrap()</code> methods will
+     * {@code wrap()} and {@code unwrap()} methods will
      * implicitly call this method if handshaking has not already begun.
      * <P>
      * Note that the peer may also request a session renegotiation with
-     * this <code>SSLEngine</code> by sending the appropriate
+     * this {@code SSLEngine} by sending the appropriate
      * session renegotiate handshake message.
      * <P>
      * Unlike the {@link SSLSocket#startHandshake()
      * SSLSocket#startHandshake()} method, this method does not block
      * until handshaking is completed.
      * <P>
-     * To force a complete SSL/TLS session renegotiation, the current
+     * To force a complete SSL/TLS/DTLS session renegotiation, the current
      * session should be invalidated prior to calling this method.
      * <P>
      * Some protocols may not support multiple handshakes on an existing
-     * engine and may throw an <code>SSLException</code>.
+     * engine and may throw an {@code SSLException}.
      *
      * @throws  SSLException
      *          if a problem was encountered while signaling the
-     *          <code>SSLEngine</code> to begin a new handshake.
+     *          {@code SSLEngine} to begin a new handshake.
      *          See the class description for more information on
      *          engine closure.
      * @throws  IllegalStateException if the client/server mode
@@ -1042,9 +1042,9 @@
 
 
     /**
-     * Returns the current handshake status for this <code>SSLEngine</code>.
+     * Returns the current handshake status for this {@code SSLEngine}.
      *
-     * @return  the current <code>SSLEngineResult.HandshakeStatus</code>.
+     * @return  the current {@code SSLEngineResult.HandshakeStatus}.
      */
     public abstract SSLEngineResult.HandshakeStatus getHandshakeStatus();
 
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLEngineResult.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLEngineResult.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,13 +27,13 @@
 
 /**
  * An encapsulation of the result state produced by
- * <code>SSLEngine</code> I/O calls.
+ * {@code SSLEngine} I/O calls.
  *
- * <p> A <code>SSLEngine</code> provides a means for establishing
- * secure communication sessions between two peers.  <code>SSLEngine</code>
+ * <p> A {@code SSLEngine} provides a means for establishing
+ * secure communication sessions between two peers.  {@code SSLEngine}
  * operations typically consume bytes from an input buffer and produce
  * bytes in an output buffer.  This class provides operational result
- * values describing the state of the <code>SSLEngine</code>, including
+ * values describing the state of the {@code SSLEngine}, including
  * indications of what operations are needed to finish an
  * ongoing handshake.  Lastly, it reports the number of bytes consumed
  * and produced as a result of this operation.
@@ -49,12 +49,12 @@
 public class SSLEngineResult {
 
     /**
-     * An <code>SSLEngineResult</code> enum describing the overall result
-     * of the <code>SSLEngine</code> operation.
+     * An {@code SSLEngineResult} enum describing the overall result
+     * of the {@code SSLEngine} operation.
      *
-     * The <code>Status</code> value does not reflect the
-     * state of a <code>SSLEngine</code> handshake currently
-     * in progress.  The <code>SSLEngineResult's HandshakeStatus</code>
+     * The {@code Status} value does not reflect the
+     * state of a {@code SSLEngine} handshake currently
+     * in progress.  The {@code SSLEngineResult's HandshakeStatus}
      * should be consulted for that information.
      *
      * @author Brad R. Wetmore
@@ -63,7 +63,7 @@
     public static enum Status {
 
         /**
-         * The <code>SSLEngine</code> was not able to unwrap the
+         * The {@code SSLEngine} was not able to unwrap the
          * incoming data because there were not enough source bytes
          * available to make a complete packet.
          *
@@ -73,7 +73,7 @@
         BUFFER_UNDERFLOW,
 
         /**
-         * The <code>SSLEngine</code> was not able to process the
+         * The {@code SSLEngine} was not able to process the
          * operation because there are not enough bytes available in the
          * destination buffer to hold the result.
          * <P>
@@ -85,22 +85,22 @@
         BUFFER_OVERFLOW,
 
         /**
-         * The <code>SSLEngine</code> completed the operation, and
+         * The {@code SSLEngine} completed the operation, and
          * is available to process similar calls.
          */
         OK,
 
         /**
          * The operation just closed this side of the
-         * <code>SSLEngine</code>, or the operation
+         * {@code SSLEngine}, or the operation
          * could not be completed because it was already closed.
          */
         CLOSED;
     }
 
     /**
-     * An <code>SSLEngineResult</code> enum describing the current
-     * handshaking state of this <code>SSLEngine</code>.
+     * An {@code SSLEngineResult} enum describing the current
+     * handshaking state of this {@code SSLEngine}.
      *
      * @author Brad R. Wetmore
      * @since 1.5
@@ -108,17 +108,17 @@
     public static enum HandshakeStatus {
 
         /**
-         * The <code>SSLEngine</code> is not currently handshaking.
+         * The {@code SSLEngine} is not currently handshaking.
          */
         NOT_HANDSHAKING,
 
         /**
-         * The <code>SSLEngine</code> has just finished handshaking.
+         * The {@code SSLEngine} has just finished handshaking.
          * <P>
          * This value is only generated by a call to
-         * <code>SSLEngine.wrap()/unwrap()</code> when that call
+         * {@code SSLEngine.wrap()/unwrap()} when that call
          * finishes a handshake.  It is never generated by
-         * <code>SSLEngine.getHandshakeStatus()</code>.
+         * {@code SSLEngine.getHandshakeStatus()}.
          *
          * @see SSLEngine#wrap(ByteBuffer, ByteBuffer)
          * @see SSLEngine#unwrap(ByteBuffer, ByteBuffer)
@@ -127,7 +127,7 @@
         FINISHED,
 
         /**
-         * The <code>SSLEngine</code> needs the results of one (or more)
+         * The {@code SSLEngine} needs the results of one (or more)
          * delegated tasks before handshaking can continue.
          *
          * @see SSLEngine#getDelegatedTask()
@@ -135,8 +135,8 @@
         NEED_TASK,
 
         /**
-         * The <code>SSLEngine</code> must send data to the remote side
-         * before handshaking can continue, so <code>SSLEngine.wrap()</code>
+         * The {@code SSLEngine} must send data to the remote side
+         * before handshaking can continue, so {@code SSLEngine.wrap()}
          * should be called.
          *
          * @see SSLEngine#wrap(ByteBuffer, ByteBuffer)
@@ -144,10 +144,22 @@
         NEED_WRAP,
 
         /**
-         * The <code>SSLEngine</code> needs to receive data from the
+         * The {@code SSLEngine} needs to receive data from the
          * remote side before handshaking can continue.
          */
-        NEED_UNWRAP;
+        NEED_UNWRAP,
+
+        /**
+         * The {@code SSLEngine} needs to unwrap before handshaking can
+         * can continue.
+         * <P>
+         * This value is used to indicate that not-yet-interpreted data
+         * has been previously received from the remote side, and does
+         * not need to be received again.
+         *
+         * @since   1.9
+         */
+        NEED_UNWRAP_AGAIN;
     }
 
 
@@ -155,6 +167,7 @@
     private final HandshakeStatus handshakeStatus;
     private final int bytesConsumed;
     private final int bytesProduced;
+    private final long sequenceNumber;
 
     /**
      * Initializes a new instance of this class.
@@ -172,12 +185,44 @@
      *          the number of bytes placed into the destination ByteBuffer
      *
      * @throws  IllegalArgumentException
-     *          if the <code>status</code> or <code>handshakeStatus</code>
-     *          arguments are null, or if <code>bytesConsumed</code> or
-     *          <code>bytesProduced</code> is negative.
+     *          if the {@code status} or {@code handshakeStatus}
+     *          arguments are null, or if {@code bytesConsumed} or
+     *          {@code bytesProduced} is negative.
      */
     public SSLEngineResult(Status status, HandshakeStatus handshakeStatus,
             int bytesConsumed, int bytesProduced) {
+        this(status, handshakeStatus, bytesConsumed, bytesProduced, -1);
+    }
+
+    /**
+     * Initializes a new instance of this class.
+     *
+     * @param   status
+     *          the return value of the operation.
+     *
+     * @param   handshakeStatus
+     *          the current handshaking status.
+     *
+     * @param   bytesConsumed
+     *          the number of bytes consumed from the source ByteBuffer
+     *
+     * @param   bytesProduced
+     *          the number of bytes placed into the destination ByteBuffer
+     *
+     * @param   sequenceNumber
+     *          the sequence number (unsigned long) of the produced or
+     *          consumed SSL/TLS/DTLS record, or ${@code -1L} if no record
+     *          produced or consumed
+     *
+     * @throws  IllegalArgumentException
+     *          if the {@code status} or {@code handshakeStatus}
+     *          arguments are null, or if {@code bytesConsumed} or
+     *          {@code bytesProduced} is negative
+     *
+     * @since   1.9
+     */
+    public SSLEngineResult(Status status, HandshakeStatus handshakeStatus,
+            int bytesConsumed, int bytesProduced, long sequenceNumber) {
 
         if ((status == null) || (handshakeStatus == null) ||
                 (bytesConsumed < 0) || (bytesProduced < 0)) {
@@ -188,10 +233,11 @@
         this.handshakeStatus = handshakeStatus;
         this.bytesConsumed = bytesConsumed;
         this.bytesProduced = bytesProduced;
+        this.sequenceNumber = sequenceNumber;
     }
 
     /**
-     * Gets the return value of this <code>SSLEngine</code> operation.
+     * Gets the return value of this {@code SSLEngine} operation.
      *
      * @return  the return value
      */
@@ -200,7 +246,7 @@
     }
 
     /**
-     * Gets the handshake status of this <code>SSLEngine</code>
+     * Gets the handshake status of this {@code SSLEngine}
      * operation.
      *
      * @return  the handshake status
@@ -228,6 +274,41 @@
     }
 
     /**
+     * Returns the sequence number of the produced or consumed SSL/TLS/DTLS
+     * record (optional operation).
+     *
+     * @apiNote  Note that sequence number is an unsigned long and cannot
+     *           exceed {@code -1L}.  It is desired to use the unsigned
+     *           long comparing mode for comparison of unsigned long values
+     *           (see also {@link java.lang.Long#compareUnsigned(long, long)
+     *           Long.compareUnsigned()}).
+     *           <P>
+     *           For DTLS protocols, the first 16 bits of the sequence
+     *           number is a counter value (epoch) that is incremented on
+     *           every cipher state change.  The remaining 48 bits on the
+     *           right side of the sequence number represents the sequence
+     *           of the record, which is maintained separately for each epoch.
+     *
+     * @implNote It is recommended that providers should never allow the
+     *           sequence number incremented to {@code -1L}.  If the sequence
+     *           number is close to wrapping, renegotiate should be requested,
+     *           otherwise the connection should be closed immediately.
+     *           This should be carried on automatically by the underlying
+     *           implementation.
+     *
+     * @return  the sequence number of the produced or consumed SSL/TLS/DTLS
+     *          record; or ${@code -1L} if no record is produced or consumed,
+     *          or this operation is not supported by the underlying provider
+     *
+     * @see     java.lang.Long#compareUnsigned(long, long)
+     *
+     * @since   1.9
+     */
+    final public long sequenceNumber() {
+        return sequenceNumber;
+    }
+
+    /**
      * Returns a String representation of this object.
      */
     @Override
@@ -235,6 +316,8 @@
         return ("Status = " + status +
             " HandshakeStatus = " + handshakeStatus +
             "\nbytesConsumed = " + bytesConsumed +
-            " bytesProduced = " + bytesProduced);
+            " bytesProduced = " + bytesProduced +
+            (sequenceNumber == -1 ? "" :
+                " sequenceNumber = " + Long.toUnsignedString(sequenceNumber)));
     }
 }
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLParameters.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLParameters.java	Wed Jul 05 20:37:09 2017 +0200
@@ -35,22 +35,22 @@
 import java.util.LinkedHashMap;
 
 /**
- * Encapsulates parameters for an SSL/TLS connection. The parameters
- * are the list of ciphersuites to be accepted in an SSL/TLS handshake,
+ * Encapsulates parameters for an SSL/TLS/DTLS connection. The parameters
+ * are the list of ciphersuites to be accepted in an SSL/TLS/DTLS handshake,
  * 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, etc.
+ * algorithm during SSL/TLS/DTLS handshaking, the Server Name Indication (SNI),
+ * the maximum network packet size, the algorithm constraints and whether
+ * SSL/TLS/DTLS servers should request 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>
+ * Objects can also be obtained using the {@code getSSLParameters()}
  * methods in
  * {@link SSLSocket#getSSLParameters SSLSocket} and
  * {@link SSLServerSocket#getSSLParameters SSLServerSocket} and
  * {@link SSLEngine#getSSLParameters SSLEngine} or the
  * {@link SSLContext#getDefaultSSLParameters getDefaultSSLParameters()} and
  * {@link SSLContext#getSupportedSSLParameters getSupportedSSLParameters()}
- * methods in <code>SSLContext</code>.
+ * methods in {@code SSLContext}.
  * <p>
  * SSLParameters can be applied to a connection via the methods
  * {@link SSLSocket#setSSLParameters SSLSocket.setSSLParameters()} and
@@ -74,14 +74,18 @@
     private Map<Integer, SNIServerName> sniNames = null;
     private Map<Integer, SNIMatcher> sniMatchers = null;
     private boolean preferLocalCipherSuites;
+    private boolean enableRetransmissions = true;
+    private int maximumPacketSize = 0;
 
     /**
      * 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>, useCipherSuitesOrder,
-     * wantClientAuth and needClientAuth are set to <code>false</code>.
+     * server name matchers are set to {@code null}; useCipherSuitesOrder,
+     * wantClientAuth and needClientAuth are set to {@code false};
+     * enableRetransmissions is set to {@code true}; maximum network packet
+     * size is set to {@code 0}.
      */
     public SSLParameters() {
         // empty
@@ -92,7 +96,7 @@
      * <p>
      * Calling this constructor is equivalent to calling the no-args
      * constructor followed by
-     * <code>setCipherSuites(cipherSuites);</code>.
+     * {@code setCipherSuites(cipherSuites);}.
      *
      * @param cipherSuites the array of ciphersuites (or null)
      */
@@ -106,7 +110,7 @@
      * <p>
      * Calling this constructor is equivalent to calling the no-args
      * constructor followed by
-     * <code>setCipherSuites(cipherSuites); setProtocols(protocols);</code>.
+     * {@code setCipherSuites(cipherSuites); setProtocols(protocols);}.
      *
      * @param cipherSuites the array of ciphersuites (or null)
      * @param protocols the array of protocols (or null)
@@ -171,7 +175,7 @@
 
     /**
      * Sets whether client authentication should be requested. Calling
-     * this method clears the <code>needClientAuth</code> flag.
+     * this method clears the {@code needClientAuth} flag.
      *
      * @param wantClientAuth whether client authentication should be requested
      */
@@ -191,7 +195,7 @@
 
     /**
      * Sets whether client authentication should be required. Calling
-     * this method clears the <code>wantClientAuth</code> flag.
+     * this method clears the {@code wantClientAuth} flag.
      *
      * @param needClientAuth whether client authentication should be required
      */
@@ -218,9 +222,9 @@
      * Sets the cryptographic algorithm constraints, which will be used
      * in addition to any configured by the runtime environment.
      * <p>
-     * If the <code>constraints</code> parameter is non-null, every
+     * If the {@code constraints} parameter is non-null, every
      * cryptographic algorithm, key and algorithm parameters used in the
-     * SSL/TLS handshake must be permitted by the constraints.
+     * SSL/TLS/DTLS handshake must be permitted by the constraints.
      *
      * @param constraints the algorithm constraints (or null)
      *
@@ -249,9 +253,9 @@
     /**
      * Sets the endpoint identification algorithm.
      * <p>
-     * If the <code>algorithm</code> parameter is non-null or non-empty, the
+     * If the {@code algorithm} parameter is non-null or non-empty, the
      * endpoint identification/verification procedures must be handled during
-     * SSL/TLS handshaking.  This is to prevent man-in-the-middle attacks.
+     * SSL/TLS/DTLS handshaking.  This is to prevent man-in-the-middle attacks.
      *
      * @param algorithm The standard string name of the endpoint
      *     identification algorithm (or null).  See Appendix A in the <a href=
@@ -317,7 +321,7 @@
      * This method is only useful to {@link SSLSocket}s or {@link SSLEngine}s
      * operating in client mode.
      * <P>
-     * For SSL/TLS connections, the underlying SSL/TLS provider
+     * For SSL/TLS/DTLS connections, the underlying SSL/TLS/DTLS provider
      * may specify a default value for a certain server name type.  In
      * client mode, it is recommended that, by default, providers should
      * include the server name indication whenever the server can be located
@@ -440,7 +444,7 @@
      *
      * @param honorOrder whether local cipher suites order in
      *        {@code #getCipherSuites} should be honored during
-     *        SSL/TLS handshaking.
+     *        SSL/TLS/DTLS handshaking.
      *
      * @see #getUseCipherSuitesOrder()
      *
@@ -454,7 +458,7 @@
      * 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.
+     *         should be honored during SSL/TLS/DTLS handshaking.
      *
      * @see #setUseCipherSuitesOrder(boolean)
      *
@@ -463,5 +467,107 @@
     public final boolean getUseCipherSuitesOrder() {
         return preferLocalCipherSuites;
     }
+
+    /**
+     * Sets whether DTLS handshake retransmissions should be enabled.
+     *
+     * This method only applies to DTLS.
+     *
+     * @param   enableRetransmissions
+     *          {@code true} indicates that DTLS handshake retransmissions
+     *          should be enabled; {@code false} indicates that DTLS handshake
+     *          retransmissions should be disabled
+     *
+     * @see     #getEnableRetransmissions()
+     *
+     * @since 1.9
+     */
+    public void setEnableRetransmissions(boolean enableRetransmissions) {
+        this.enableRetransmissions = enableRetransmissions;
+    }
+
+    /**
+     * Returns whether DTLS handshake retransmissions should be enabled.
+     *
+     * This method only applies to DTLS.
+     *
+     * @return  true, if DTLS handshake retransmissions should be enabled
+     *
+     * @see     #setEnableRetransmissions(boolean)
+     *
+     * @since 1.9
+     */
+    public boolean getEnableRetransmissions() {
+        return enableRetransmissions;
+    }
+
+    /**
+     * Sets the maximum expected network packet size in bytes for
+     * SSL/TLS/DTLS records.
+     *
+     * @apiNote  It is recommended that if possible, the maximum packet size
+     *           should not be less than 256 bytes so that small handshake
+     *           messages, such as HelloVerifyRequests, are not fragmented.
+     *
+     * @implNote If the maximum packet size is too small to hold a minimal
+     *           record, an implementation may attempt to generate as minimal
+     *           records as possible.  However, this may cause a generated
+     *           packet to be larger than the maximum packet size.
+     *
+     * @param   maximumPacketSize
+     *          the maximum expected network packet size in bytes, or
+     *          {@code 0} to use the implicit size that is automatically
+     *          specified by the underlying implementation.
+     * @throws  IllegalArgumentException
+     *          if {@code maximumPacketSize} is negative.
+     *
+     * @see     #getMaximumPacketSize()
+     *
+     * @since 1.9
+     */
+    public void setMaximumPacketSize(int maximumPacketSize) {
+        if (maximumPacketSize < 0) {
+            throw new IllegalArgumentException(
+                "The maximum packet size cannot be negative");
+        }
+
+        this.maximumPacketSize = maximumPacketSize;
+    }
+
+    /**
+     * Returns the maximum expected network packet size in bytes for
+     * SSL/TLS/DTLS records.
+     *
+     * @apiNote  The implicit size may not be a fixed value, especially
+     *           for a DTLS protocols implementation.
+     *
+     * @implNote For SSL/TLS/DTLS connections, the underlying provider
+     *           should calculate and specify the implicit value of the
+     *           maximum expected network packet size if it is not
+     *           configured explicitly.  For any connection populated
+     *           object, this method should never return {@code 0} so
+     *           that applications can retrieve the actual implicit size
+     *           of the underlying implementation.
+     *           <P>
+     *           An implementation should attempt to comply with the maximum
+     *           packet size configuration.  However, if the maximum packet
+     *           size is too small to hold a minimal record, an implementation
+     *           may try to generate as minimal records as possible.  This
+     *           may cause a generated packet to be larger than the maximum
+     *           packet size.
+     *
+     * @return   the maximum expected network packet size, or {@code 0} if
+     *           use the implicit size that is automatically specified by
+     *           the underlying implementation and this object has not been
+     *           populated by any connection.
+     *
+     * @see      #setMaximumPacketSize(int)
+     *
+     * @since 1.9
+     */
+    public int getMaximumPacketSize() {
+        return maximumPacketSize;
+    }
+
 }
 
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLSession.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLSession.java	Wed Jul 05 20:37:09 2017 +0200
@@ -35,7 +35,7 @@
  * also be replaced by a different session.  Sessions are created, or
  * rejoined, as part of the SSL handshaking protocol. Sessions may be
  * invalidated due to policies affecting security or resource usage,
- * or by an application explicitly calling <code>invalidate</code>.
+ * or by an application explicitly calling {@code invalidate}.
  * Session management policies are typically used to tune performance.
  *
  * <P> In addition to the standard session attributes, SSL sessions expose
@@ -82,8 +82,8 @@
      * security manager installed, the caller may require
      * permission to access it or a security exception may be thrown.
      * In a Java environment, the security manager's
-     * <code>checkPermission</code> method is called with a
-     * <code>SSLPermission("getSSLSessionContext")</code> permission.
+     * {@code checkPermission} method is called with a
+     * {@code SSLPermission("getSSLSessionContext")} permission.
      *
      * @throws SecurityException if the calling thread does not have
      *         permission to get SSL session context.
@@ -148,14 +148,14 @@
 
     /**
      *
-     * Binds the specified <code>value</code> object into the
+     * Binds the specified {@code value} object into the
      * session's application layer data
-     * with the given <code>name</code>.
+     * with the given {@code name}.
      * <P>
-     * Any existing binding using the same <code>name</code> is
-     * replaced.  If the new (or existing) <code>value</code> implements the
-     * <code>SSLSessionBindingListener</code> interface, the object
-     * represented by <code>value</code> is notified appropriately.
+     * Any existing binding using the same {@code name} is
+     * replaced.  If the new (or existing) {@code value} implements the
+     * {@code SSLSessionBindingListener} interface, the object
+     * represented by {@code value} is notified appropriately.
      * <p>
      * For security reasons, the same named values may not be
      * visible across different access control contexts.
@@ -187,7 +187,7 @@
      * Removes the object bound to the given name in the session's
      * application layer data.  Does nothing if there is no object
      * bound to the given name.  If the bound existing object
-     * implements the <code>SessionBindingListener</code> interface,
+     * implements the {@code SessionBindingListener} interface,
      * it is notified appropriately.
      * <p>
      * For security reasons, the same named values may not be
@@ -349,7 +349,7 @@
      * by this method.
      * <P>
      * This value is not authenticated and should not be relied upon.
-     * It is mainly used as a hint for <code>SSLSession</code> caching
+     * It is mainly used as a hint for {@code SSLSession} caching
      * strategies.
      *
      * @return  the host name of the peer host, or null if no information
@@ -364,7 +364,7 @@
      * the client, it is the server's port number.
      * <P>
      * This value is not authenticated and should not be relied upon.
-     * It is mainly used as a hint for <code>SSLSession</code> caching
+     * It is mainly used as a hint for {@code SSLSession} caching
      * strategies.
      *
      * @return  the port number of the peer host, or -1 if no information
@@ -375,14 +375,14 @@
     public int getPeerPort();
 
     /**
-     * Gets the current size of the largest SSL/TLS packet that is expected
-     * when using this session.
+     * Gets the current size of the largest SSL/TLS/DTLS packet that is
+     * expected when using this session.
      * <P>
-     * A <code>SSLEngine</code> using this session may generate SSL/TLS
+     * An {@code SSLEngine} using this session may generate SSL/TLS/DTLS
      * packets of any size up to and including the value returned by this
-     * method. All <code>SSLEngine</code> network buffers should be sized
+     * method. All {@code SSLEngine} network buffers should be sized
      * at least this large to avoid insufficient space problems when
-     * performing <code>wrap</code> and <code>unwrap</code> calls.
+     * performing {@code wrap} and {@code unwrap} calls.
      *
      * @return  the current maximum expected network packet size
      *
@@ -398,7 +398,7 @@
      * Gets the current size of the largest application data that is
      * expected when using this session.
      * <P>
-     * <code>SSLEngine</code> application data buffers must be large
+     * {@code SSLEngine} application data buffers must be large
      * enough to hold the application data from any inbound network
      * application data packet received.  Typically, outbound
      * application data buffers can be of any size.
--- a/jdk/src/java.base/share/classes/javax/net/ssl/X509ExtendedTrustManager.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/X509ExtendedTrustManager.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,16 +32,17 @@
 import java.security.cert.CertificateException;
 
 /**
- * Extensions to the <code>X509TrustManager</code> interface to support
- * SSL/TLS connection sensitive trust management.
+ * Extensions to the {@code X509TrustManager} interface to support
+ * SSL/TLS/DTLS connection sensitive trust management.
  * <p>
  * To prevent man-in-the-middle attacks, hostname checks can be done
  * to verify that the hostname in an end-entity certificate matches the
- * targeted hostname.  TLS does not require such checks, but some protocols
- * over TLS (such as HTTPS) do.  In earlier versions of the JDK, the
- * certificate chain checks were done at the SSL/TLS layer, and the hostname
- * verification checks were done at the layer over TLS.  This class allows
- * for the checking to be done during a single call to this class.
+ * targeted hostname.  TLS/DTLS does not require such checks, but some
+ * protocols over TLS/DTLS (such as HTTPS) do.  In earlier versions of the
+ * JDK, the certificate chain checks were done at the SSL/TLS/DTLS layer,
+ * and the hostname verification checks were done at the layer over TLS/DTLS.
+ * This class allows for the checking to be done during a single call to
+ * this class.
  * <p>
  * RFC 2830 defines the server identification specification for the "LDAPS"
  * algorithm. RFC 2818 defines both the server identification and the
@@ -62,17 +63,17 @@
      * used. For instance, if RSAPublicKey is used, the authType
      * should be "RSA". Checking is case-sensitive.
      * <p>
-     * If the <code>socket</code> parameter is an instance of
+     * If the {@code socket} parameter is an instance of
      * {@link javax.net.ssl.SSLSocket}, and the endpoint identification
-     * algorithm of the <code>SSLParameters</code> is non-empty, to prevent
-     * man-in-the-middle attacks, the address that the <code>socket</code>
+     * algorithm of the {@code SSLParameters} is non-empty, to prevent
+     * man-in-the-middle attacks, the address that the {@code socket}
      * connected to should be checked against the peer's identity presented
      * in the end-entity X509 certificate, as specified in the endpoint
      * identification algorithm.
      * <p>
-     * If the <code>socket</code> parameter is an instance of
+     * If the {@code socket} parameter is an instance of
      * {@link javax.net.ssl.SSLSocket}, and the algorithm constraints of the
-     * <code>SSLParameters</code> is non-null, for every certificate in the
+     * {@code SSLParameters} is non-null, for every certificate in the
      * certification path, fields such as subject public key, the signature
      * algorithm, key usage, extended key usage, etc. need to conform to the
      * algorithm constraints in place on this socket.
@@ -83,8 +84,8 @@
      *        can be null, which indicates that implementations need not check
      *        the ssl parameters
      * @throws IllegalArgumentException if null or zero-length array is passed
-     *        in for the <code>chain</code> parameter or if null or zero-length
-     *        string is passed in for the <code>authType</code> parameter
+     *        in for the {@code chain} parameter or if null or zero-length
+     *        string is passed in for the {@code authType} parameter
      * @throws CertificateException if the certificate chain is not trusted
      *        by this TrustManager
      *
@@ -110,17 +111,17 @@
      * used for the key exchange, and RSA when the key from the server
      * certificate is used. Checking is case-sensitive.
      * <p>
-     * If the <code>socket</code> parameter is an instance of
+     * If the {@code socket} parameter is an instance of
      * {@link javax.net.ssl.SSLSocket}, and the endpoint identification
-     * algorithm of the <code>SSLParameters</code> is non-empty, to prevent
-     * man-in-the-middle attacks, the address that the <code>socket</code>
+     * algorithm of the {@code SSLParameters} is non-empty, to prevent
+     * man-in-the-middle attacks, the address that the {@code socket}
      * connected to should be checked against the peer's identity presented
      * in the end-entity X509 certificate, as specified in the endpoint
      * identification algorithm.
      * <p>
-     * If the <code>socket</code> parameter is an instance of
+     * If the {@code socket} parameter is an instance of
      * {@link javax.net.ssl.SSLSocket}, and the algorithm constraints of the
-     *  <code>SSLParameters</code> is non-null, for every certificate in the
+     *  {@code SSLParameters} is non-null, for every certificate in the
      * certification path, fields such as subject public key, the signature
      * algorithm, key usage, extended key usage, etc. need to conform to the
      * algorithm constraints in place on this socket.
@@ -131,8 +132,8 @@
      *        can be null, which indicates that implementations need not check
      *        the ssl parameters
      * @throws IllegalArgumentException if null or zero-length array is passed
-     *        in for the <code>chain</code> parameter or if null or zero-length
-     *        string is passed in for the <code>authType</code> parameter
+     *        in for the {@code chain} parameter or if null or zero-length
+     *        string is passed in for the {@code authType} parameter
      * @throws CertificateException if the certificate chain is not trusted
      *        by this TrustManager
      *
@@ -153,15 +154,15 @@
      * used. For instance, if RSAPublicKey is used, the authType
      * should be "RSA". Checking is case-sensitive.
      * <p>
-     * If the <code>engine</code> parameter is available, and the endpoint
-     * identification algorithm of the <code>SSLParameters</code> is
+     * If the {@code engine} parameter is available, and the endpoint
+     * identification algorithm of the {@code SSLParameters} is
      * non-empty, to prevent man-in-the-middle attacks, the address that
-     * the <code>engine</code> connected to should be checked against
+     * the {@code engine} connected to should be checked against
      * the peer's identity presented in the end-entity X509 certificate,
      * as specified in the endpoint identification algorithm.
      * <p>
-     * If the <code>engine</code> parameter is available, and the algorithm
-     * constraints of the <code>SSLParameters</code> is non-null, for every
+     * If the {@code engine} parameter is available, and the algorithm
+     * constraints of the {@code SSLParameters} is non-null, for every
      * certificate in the certification path, fields such as subject public
      * key, the signature algorithm, key usage, extended key usage, etc.
      * need to conform to the algorithm constraints in place on this engine.
@@ -172,8 +173,8 @@
      *        can be null, which indicates that implementations need not check
      *        the ssl parameters
      * @throws IllegalArgumentException if null or zero-length array is passed
-     *        in for the <code>chain</code> parameter or if null or zero-length
-     *        string is passed in for the <code>authType</code> parameter
+     *        in for the {@code chain} parameter or if null or zero-length
+     *        string is passed in for the {@code authType} parameter
      * @throws CertificateException if the certificate chain is not trusted
      *        by this TrustManager
      *
@@ -199,15 +200,15 @@
      * used for the key exchange, and RSA when the key from the server
      * certificate is used. Checking is case-sensitive.
      * <p>
-     * If the <code>engine</code> parameter is available, and the endpoint
-     * identification algorithm of the <code>SSLParameters</code> is
+     * If the {@code engine} parameter is available, and the endpoint
+     * identification algorithm of the {@code SSLParameters} is
      * non-empty, to prevent man-in-the-middle attacks, the address that
-     * the <code>engine</code> connected to should be checked against
+     * the {@code engine} connected to should be checked against
      * the peer's identity presented in the end-entity X509 certificate,
      * as specified in the endpoint identification algorithm.
      * <p>
-     * If the <code>engine</code> parameter is available, and the algorithm
-     * constraints of the <code>SSLParameters</code> is non-null, for every
+     * If the {@code engine} parameter is available, and the algorithm
+     * constraints of the {@code SSLParameters} is non-null, for every
      * certificate in the certification path, fields such as subject public
      * key, the signature algorithm, key usage, extended key usage, etc.
      * need to conform to the algorithm constraints in place on this engine.
@@ -218,8 +219,8 @@
      *        can be null, which indicates that implementations need not check
      *        the ssl parameters
      * @throws IllegalArgumentException if null or zero-length array is passed
-     *        in for the <code>chain</code> parameter or if null or zero-length
-     *        string is passed in for the <code>authType</code> parameter
+     *        in for the {@code chain} parameter or if null or zero-length
+     *        string is passed in for the {@code authType} parameter
      * @throws CertificateException if the certificate chain is not trusted
      *        by this TrustManager
      *
--- a/jdk/src/java.base/share/classes/sun/invoke/anon/ConstantPoolPatch.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/invoke/anon/ConstantPoolPatch.java	Wed Jul 05 20:37:09 2017 +0200
@@ -417,7 +417,7 @@
             | CONSTANT_InterfaceMethodref;
 
     private static final Map<Class<?>, Byte> CONSTANT_VALUE_CLASS_TAG
-        = new IdentityHashMap<Class<?>, Byte>();
+        = new IdentityHashMap<Class<?>, Byte>(6);
     private static final Class<?>[] CONSTANT_VALUE_CLASS = new Class<?>[16];
     static {
         Object[][] values = {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/misc/JavaBeansAccess.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014, 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.misc;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+public interface JavaBeansAccess {
+    /**
+     * Returns the getter method for a property of the given name
+     * @param clazz The JavaBeans class
+     * @param property The property name
+     * @return The resolved property getter method
+     * @throws Exception
+     */
+    Method getReadMethod(Class<?> clazz, String property) throws Exception;
+
+    /**
+     * Return the <b>value</b> attribute of the associated
+     * <code>@ConstructorProperties</code> annotation if that is present.
+     * @param ctr The constructor to extract the annotation value from
+     * @return The {@code value} attribute of the <code>@ConstructorProperties</code>
+     *         annotation or {@code null} if the constructor is not annotated by
+     *         this annotation or the annotation is not accessible.
+     */
+    String[] getConstructorPropertiesValue(Constructor<?> ctr);
+}
--- a/jdk/src/java.base/share/classes/sun/misc/JavaBeansIntrospectorAccess.java	Thu Jun 04 18:50:30 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 2014, 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.misc;
-
-import java.lang.reflect.Method;
-
-public interface JavaBeansIntrospectorAccess {
-    Method getReadMethod(Class<?> clazz, String property) throws Exception;
-}
--- a/jdk/src/java.base/share/classes/sun/misc/SharedSecrets.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/misc/SharedSecrets.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -56,7 +56,7 @@
     private static JavaUtilZipFileAccess javaUtilZipFileAccess;
     private static JavaAWTAccess javaAWTAccess;
     private static JavaAWTFontAccess javaAWTFontAccess;
-    private static JavaBeansIntrospectorAccess javaBeansIntrospectorAccess;
+    private static JavaBeansAccess javaBeansAccess;
 
     public static JavaUtilJarAccess javaUtilJarAccess() {
         if (javaUtilJarAccess == null) {
@@ -194,11 +194,11 @@
         return javaAWTFontAccess;
     }
 
-    public static JavaBeansIntrospectorAccess getJavaBeansIntrospectorAccess() {
-        return javaBeansIntrospectorAccess;
+    public static JavaBeansAccess getJavaBeansAccess() {
+        return javaBeansAccess;
     }
 
-    public static void setJavaBeansIntrospectorAccess(JavaBeansIntrospectorAccess access) {
-        javaBeansIntrospectorAccess = access;
+    public static void setJavaBeansAccess(JavaBeansAccess access) {
+        javaBeansAccess = access;
     }
 }
--- a/jdk/src/java.base/share/classes/sun/nio/cs/AbstractCharsetProvider.java	Thu Jun 04 18:50:30 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,206 +0,0 @@
-/*
- * Copyright (c) 2000, 2011, 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.nio.cs;
-
-import java.lang.ref.SoftReference;
-import java.nio.charset.Charset;
-import java.nio.charset.spi.CharsetProvider;
-import java.util.ArrayList;
-import java.util.TreeMap;
-import java.util.Iterator;
-import java.util.Locale;
-import java.util.Map;
-import sun.misc.ASCIICaseInsensitiveComparator;
-
-
-/**
- * Abstract base class for charset providers.
- *
- * @author Mark Reinhold
- */
-
-public class AbstractCharsetProvider
-    extends CharsetProvider
-{
-
-    /* Maps canonical names to class names
-     */
-    private Map<String,String> classMap
-        = new TreeMap<>(ASCIICaseInsensitiveComparator.CASE_INSENSITIVE_ORDER);
-
-    /* Maps alias names to canonical names
-     */
-    private Map<String,String> aliasMap
-        = new TreeMap<>(ASCIICaseInsensitiveComparator.CASE_INSENSITIVE_ORDER);
-
-    /* Maps canonical names to alias-name arrays
-     */
-    private Map<String,String[]> aliasNameMap
-        = new TreeMap<>(ASCIICaseInsensitiveComparator.CASE_INSENSITIVE_ORDER);
-
-    /* Maps canonical names to soft references that hold cached instances
-     */
-    private Map<String,SoftReference<Charset>> cache
-        = new TreeMap<>(ASCIICaseInsensitiveComparator.CASE_INSENSITIVE_ORDER);
-
-    private String packagePrefix;
-
-    protected AbstractCharsetProvider() {
-        packagePrefix = "sun.nio.cs";
-    }
-
-    protected AbstractCharsetProvider(String pkgPrefixName) {
-        packagePrefix = pkgPrefixName;
-    }
-
-    /* Add an entry to the given map, but only if no mapping yet exists
-     * for the given name.
-     */
-    private static <K,V> void put(Map<K,V> m, K name, V value) {
-        if (!m.containsKey(name))
-            m.put(name, value);
-    }
-
-    private static <K,V> void remove(Map<K,V> m, K name) {
-        V x  = m.remove(name);
-        assert (x != null);
-    }
-
-    /* Declare support for the given charset
-     */
-    protected void charset(String name, String className, String[] aliases) {
-        synchronized (this) {
-            put(classMap, name, className);
-            for (int i = 0; i < aliases.length; i++)
-                put(aliasMap, aliases[i], name);
-            put(aliasNameMap, name, aliases);
-            cache.clear();
-        }
-    }
-
-    protected void deleteCharset(String name, String[] aliases) {
-        synchronized (this) {
-            remove(classMap, name);
-            for (int i = 0; i < aliases.length; i++)
-                remove(aliasMap, aliases[i]);
-            remove(aliasNameMap, name);
-            cache.clear();
-        }
-    }
-
-    protected boolean hasCharset(String name) {
-        synchronized (this) {
-            return classMap.containsKey(name);
-        }
-    }
-
-    /* Late initialization hook, needed by some providers
-     */
-    protected void init() { }
-
-    private String canonicalize(String charsetName) {
-        String acn = aliasMap.get(charsetName);
-        return (acn != null) ? acn : charsetName;
-    }
-
-    private Charset lookup(String csn) {
-
-        // Check cache first
-        SoftReference<Charset> sr = cache.get(csn);
-        if (sr != null) {
-            Charset cs = sr.get();
-            if (cs != null)
-                return cs;
-        }
-
-        // Do we even support this charset?
-        String cln = classMap.get(csn);
-
-        if (cln == null)
-            return null;
-
-        // Instantiate the charset and cache it
-        try {
-
-            Class<?> c = Class.forName(packagePrefix + "." + cln,
-                                       true,
-                                       this.getClass().getClassLoader());
-
-            Charset cs = (Charset)c.newInstance();
-            cache.put(csn, new SoftReference<Charset>(cs));
-            return cs;
-        } catch (ClassNotFoundException x) {
-            return null;
-        } catch (IllegalAccessException x) {
-            return null;
-        } catch (InstantiationException x) {
-            return null;
-        }
-    }
-
-    public final Charset charsetForName(String charsetName) {
-        synchronized (this) {
-            init();
-            return lookup(canonicalize(charsetName));
-        }
-    }
-
-    public final Iterator<Charset> charsets() {
-
-        final ArrayList<String> ks;
-        synchronized (this) {
-            init();
-            ks = new ArrayList<>(classMap.keySet());
-        }
-
-        return new Iterator<Charset>() {
-                Iterator<String> i = ks.iterator();
-
-                public boolean hasNext() {
-                    return i.hasNext();
-                }
-
-                public Charset next() {
-                    String csn = i.next();
-                    synchronized (AbstractCharsetProvider.this) {
-                        return lookup(csn);
-                    }
-                }
-
-                public void remove() {
-                    throw new UnsupportedOperationException();
-                }
-            };
-    }
-
-    public final String[] aliases(String charsetName) {
-        synchronized (this) {
-            init();
-            return aliasNameMap.get(charsetName);
-        }
-    }
-
-}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/AppInputStream.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/AppInputStream.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,41 +26,54 @@
 
 package sun.security.ssl;
 
-import java.io.*;
+import java.io.InputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import javax.net.ssl.SSLProtocolException;
 
 /**
  * InputStream for application data as returned by SSLSocket.getInputStream().
- * It uses an InputRecord as internal buffer that is refilled on demand
- * whenever it runs out of data.
  *
  * @author David Brownell
  */
-class AppInputStream extends InputStream {
+final class AppInputStream extends InputStream {
+    // the buffer size for each read of network data
+    private static final int READ_BUFFER_SIZE = 4096;
 
     // static dummy array we use to implement skip()
-    private final static byte[] SKIP_ARRAY = new byte[1024];
+    private static final byte[] SKIP_ARRAY = new byte[256];
+
+    // the related socket of the input stream
+    private final SSLSocketImpl socket;
 
-    private SSLSocketImpl c;
-    InputRecord r;
+    // the temporary buffer used to read network
+    private ByteBuffer buffer;
+
+    // Is application data available in the stream?
+    private boolean appDataIsAvailable;
 
     // One element array used to implement the single byte read() method
     private final byte[] oneByte = new byte[1];
 
     AppInputStream(SSLSocketImpl conn) {
-        r = new InputRecord();
-        c = conn;
+        this.buffer = ByteBuffer.allocate(READ_BUFFER_SIZE);
+        this.socket = conn;
+        this.appDataIsAvailable = false;
     }
 
     /**
      * Return the minimum number of bytes that can be read without blocking.
+     *
      * Currently not synchronized.
      */
     @Override
     public int available() throws IOException {
-        if (c.checkEOF() || (r.isAppDataValid() == false)) {
+        if ((!appDataIsAvailable) || socket.checkEOF()) {
             return 0;
         }
-        return r.available();
+
+        return buffer.remaining();
     }
 
     /**
@@ -72,17 +85,21 @@
         if (n <= 0) { // EOF
             return -1;
         }
-        return oneByte[0] & 0xff;
+        return oneByte[0] & 0xFF;
     }
 
     /**
-     * Read up to "len" bytes into this buffer, starting at "off".
+     * Reads up to {@code len} bytes of data from the input stream into an
+     * array of bytes. An attempt is made to read as many as {@code len} bytes,
+     * but a smaller number may be read. The number of bytes actually read
+     * is returned as an integer.
+     *
      * If the layer above needs more data, it asks for more, so we
      * are responsible only for blocking to fill at most one buffer,
      * and returning "-1" on non-fault EOF status.
      */
     @Override
-    public synchronized int read(byte b[], int off, int len)
+    public synchronized int read(byte[] b, int off, int len)
             throws IOException {
         if (b == null) {
             throw new NullPointerException();
@@ -92,28 +109,69 @@
             return 0;
         }
 
-        if (c.checkEOF()) {
+        if (socket.checkEOF()) {
             return -1;
         }
+
+        // Read the available bytes at first.
+        int remains = available();
+        if (remains > 0) {
+            int howmany = Math.min(remains, len);
+            buffer.get(b, off, howmany);
+
+            return howmany;
+        }
+
+        appDataIsAvailable = false;
+        int volume = 0;
+
         try {
             /*
              * Read data if needed ... notice that the connection guarantees
              * that handshake, alert, and change cipher spec data streams are
              * handled as they arrive, so we never see them here.
              */
-            while (r.available() == 0) {
-                c.readDataRecord(r);
-                if (c.checkEOF()) {
+            while(volume == 0) {
+                // Clear the buffer for a new record reading.
+                buffer.clear();
+
+                //
+                // grow the buffer if needed
+                //
+
+                // Read the header of a record into the buffer, and return
+                // the packet size.
+                int packetLen = socket.bytesInCompletePacket();
+                if (packetLen < 0) {    // EOF
                     return -1;
                 }
+
+                // Is this packet bigger than SSL/TLS normally allows?
+                if (packetLen > SSLRecord.maxLargeRecordSize) {
+                    throw new SSLProtocolException(
+                        "Illegal packet size: " + packetLen);
+                }
+
+                if (packetLen > buffer.remaining()) {
+                    buffer = ByteBuffer.allocate(packetLen);
+                }
+
+                volume = socket.readRecord(buffer);
+                if (volume < 0) {    // EOF
+                    return -1;
+                } else if (volume > 0) {
+                    appDataIsAvailable = true;
+                    break;
+                }
             }
 
-            int howmany = Math.min(len, r.available());
-            howmany = r.read(b, off, howmany);
+            int howmany = Math.min(len, volume);
+            buffer.get(b, off, howmany);
             return howmany;
         } catch (Exception e) {
             // shutdown and rethrow (wrapped) exception as appropriate
-            c.handleException(e);
+            socket.handleException(e);
+
             // dummy for compiler
             return -1;
         }
@@ -147,9 +205,8 @@
      */
     @Override
     public void close() throws IOException {
-        c.close();
+        socket.close();
     }
 
     // inherit default mark/reset behavior (throw Exceptions) from InputStream
-
 }
--- a/jdk/src/java.base/share/classes/sun/security/ssl/AppOutputStream.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/AppOutputStream.java	Wed Jul 05 20:37:09 2017 +0200
@@ -23,41 +23,33 @@
  * questions.
  */
 
-
 package sun.security.ssl;
 
 import java.io.OutputStream;
 import java.io.IOException;
+import java.nio.ByteBuffer;
 
 /*
- * Output stream for application data. This is the kind of stream
- * that's handed out via SSLSocket.getOutputStream(). It's all the application
- * ever sees.
- *
- * Once the initial handshake has completed, application data may be
- * interleaved with handshake data. That is handled internally and remains
- * transparent to the application.
+ * OutputStream for application data as returned by SSLSocket.getOutputStream().
  *
  * @author  David Brownell
  */
 class AppOutputStream extends OutputStream {
 
-    private SSLSocketImpl c;
-    OutputRecord r;
+    private SSLSocketImpl socket;
 
     // One element array used to implement the write(byte) method
     private final byte[] oneByte = new byte[1];
 
     AppOutputStream(SSLSocketImpl conn) {
-        r = new OutputRecord(Record.ct_application_data);
-        c = conn;
+        this.socket = conn;
     }
 
     /**
      * Write the data out, NOW.
      */
     @Override
-    synchronized public void write(byte b[], int off, int len)
+    synchronized public void write(byte[] b, int off, int len)
             throws IOException {
         if (b == null) {
             throw new NullPointerException();
@@ -68,64 +60,15 @@
         }
 
         // check if the Socket is invalid (error or closed)
-        c.checkWrite();
+        socket.checkWrite();
 
-        /*
-         * By default, we counter chosen plaintext issues on CBC mode
-         * ciphersuites in SSLv3/TLS1.0 by sending one byte of application
-         * data in the first record of every payload, and the rest in
-         * subsequent record(s). Note that the issues have been solved in
-         * TLS 1.1 or later.
-         *
-         * It is not necessary to split the very first application record of
-         * a freshly negotiated TLS session, as there is no previous
-         * application data to guess.  To improve compatibility, we will not
-         * split such records.
-         *
-         * This avoids issues in the outbound direction.  For a full fix,
-         * the peer must have similar protections.
-         */
-        boolean isFirstRecordOfThePayload = true;
-
-        // Always flush at the end of each application level record.
-        // This lets application synchronize read and write streams
-        // however they like; if we buffered here, they couldn't.
+        // Delegate the writing to the underlying socket.
         try {
-            do {
-                boolean holdRecord = false;
-                int howmuch;
-                if (isFirstRecordOfThePayload && c.needToSplitPayload()) {
-                    howmuch = Math.min(0x01, r.availableDataBytes());
-                     /*
-                      * Nagle's algorithm (TCP_NODELAY) was coming into
-                      * play here when writing short (split) packets.
-                      * Signal to the OutputRecord code to internally
-                      * buffer this small packet until the next outbound
-                      * packet (of any type) is written.
-                      */
-                     if ((len != 1) && (howmuch == 1)) {
-                         holdRecord = true;
-                     }
-                } else {
-                    howmuch = Math.min(len, r.availableDataBytes());
-                }
-
-                if (isFirstRecordOfThePayload && howmuch != 0) {
-                    isFirstRecordOfThePayload = false;
-                }
-
-                // NOTE: *must* call c.writeRecord() even for howmuch == 0
-                if (howmuch > 0) {
-                    r.write(b, off, howmuch);
-                    off += howmuch;
-                    len -= howmuch;
-                }
-                c.writeRecord(r, holdRecord);
-                c.checkWrite();
-            } while (len > 0);
+            socket.writeRecord(b, off, len);
+            socket.checkWrite();
         } catch (Exception e) {
             // shutdown and rethrow (wrapped) exception as appropriate
-            c.handleException(e);
+            socket.handleException(e);
         }
     }
 
@@ -143,7 +86,7 @@
      */
     @Override
     public void close() throws IOException {
-        c.close();
+        socket.close();
     }
 
     // inherit no-op flush()
--- a/jdk/src/java.base/share/classes/sun/security/ssl/Authenticator.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/Authenticator.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,19 +28,26 @@
 import java.util.Arrays;
 
 /**
- * This class represents an SSL/TLS message authentication token,
+ * This class represents an SSL/TLS/DTLS message authentication token,
  * which encapsulates a sequence number and ensures that attempts to
  * delete or reorder messages can be detected.
  *
- * Each SSL/TLS connection state contains a sequence number, which
- * is maintained separately for read and write states.  The sequence
- * number MUST be set to zero whenever a connection state is made the
- * active state.  Sequence numbers are of type uint64 and may not
- * exceed 2^64-1.  Sequence numbers do not wrap.  If a SSL/TLS
- * implementation would need to wrap a sequence number, it must
- * renegotiate instead.  A sequence number is incremented after each
- * record: specifically, the first record transmitted under a
- * particular connection state MUST use sequence number 0.
+ * Each connection state contains a sequence number, which is maintained
+ * separately for read and write states.
+ *
+ * For SSL/TLS protocols, the sequence number MUST be set to zero
+ * whenever a connection state is made the active state.
+ *
+ * DTLS uses an explicit sequence number, rather than an implicit one.
+ * Sequence numbers are maintained separately for each epoch, with
+ * each sequence number initially being 0 for each epoch.  The sequence
+ * number used to compute the DTLS MAC is the 64-bit value formed by
+ * concatenating the epoch and the sequence number.
+ *
+ * Sequence numbers do not wrap.  If an implementation would need to wrap
+ * a sequence number, it must renegotiate instead.  A sequence number is
+ * incremented after each record: specifically, the first record transmitted
+ * under a particular connection state MUST use sequence number 0.
  */
 class Authenticator {
 
@@ -56,13 +63,30 @@
     // sequence number + record type + protocol version + record length
     private static final int BLOCK_SIZE_TLS = 8 + 1 + 2 + 2;
 
+    // the block size of DTLS v1.0 and later:
+    // epoch + sequence number + record type + protocol version + record length
+    private static final int BLOCK_SIZE_DTLS = 2 + 6 + 1 + 2 + 2;
+
+    private final boolean isDTLS;
+
     /**
      * Default construct, no message authentication token is initialized.
      *
      * Note that this construct can only be called for null MAC
      */
-    Authenticator() {
-        block = new byte[0];
+    protected Authenticator(boolean isDTLS) {
+        if (isDTLS) {
+            // For DTLS protocols, plaintexts use explicit epoch and
+            // sequence number in each record.  The first 8 byte of
+            // the block is initialized for null MAC so that the
+            // epoch and sequence number can be acquired to generate
+            // plaintext records.
+            block = new byte[8];
+        } else {
+            block = new byte[0];
+        }
+
+        this.isDTLS = isDTLS;
     }
 
     /**
@@ -70,12 +94,22 @@
      * SSL/TLS protocol.
      */
     Authenticator(ProtocolVersion protocolVersion) {
-        if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
+        if (protocolVersion.isDTLSProtocol()) {
+            block = new byte[BLOCK_SIZE_DTLS];
+            block[9] = protocolVersion.major;
+            block[10] = protocolVersion.minor;
+
+            this.isDTLS = true;
+        } else if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
             block = new byte[BLOCK_SIZE_TLS];
             block[9] = protocolVersion.major;
             block[10] = protocolVersion.minor;
+
+            this.isDTLS = false;
         } else {
             block = new byte[BLOCK_SIZE_SSL];
+
+            this.isDTLS = false;
         }
     }
 
@@ -93,11 +127,19 @@
          * Conservatively, we don't allow more records to be generated
          * when there are only 2^8 sequence numbers left.
          */
-        return (block.length != 0 &&
+        if (isDTLS) {
+            return (block.length != 0 &&
+                // no epoch bytes, block[0] and block[1]
+                block[2] == (byte)0xFF && block[3] == (byte)0xFF &&
+                block[4] == (byte)0xFF && block[5] == (byte)0xFF &&
+                block[6] == (byte)0xFF);
+        } else {
+            return (block.length != 0 &&
                 block[0] == (byte)0xFF && block[1] == (byte)0xFF &&
                 block[2] == (byte)0xFF && block[3] == (byte)0xFF &&
                 block[4] == (byte)0xFF && block[5] == (byte)0xFF &&
                 block[6] == (byte)0xFF);
+        }
     }
 
     /**
@@ -113,14 +155,22 @@
     final boolean seqNumIsHuge() {
         /*
          * Conservatively, we should ask for renegotiation when there are
-         * only 2^48 sequence numbers left.
+         * only 2^32 sequence numbers left.
          */
-        return (block.length != 0 &&
-                block[0] == (byte)0xFF && block[1] == (byte)0xFF);
+        if (isDTLS) {
+            return (block.length != 0 &&
+                // no epoch bytes, block[0] and block[1]
+                block[2] == (byte)0xFF && block[3] == (byte)0xFF);
+        } else {
+            return (block.length != 0 &&
+                block[0] == (byte)0xFF && block[1] == (byte)0xFF &&
+                block[2] == (byte)0xFF && block[3] == (byte)0xFF);
+        }
     }
 
     /**
-     * Gets the current sequence number.
+     * Gets the current sequence number, including the epoch number for
+     * DTLS protocols.
      *
      * @return the byte array of the current sequence number
      */
@@ -129,33 +179,83 @@
     }
 
     /**
+     * Sets the epoch number (only apply to DTLS protocols).
+     */
+    final void setEpochNumber(int epoch) {
+        if (!isDTLS) {
+            throw new RuntimeException(
+                "Epoch numbers apply to DTLS protocols only");
+        }
+
+        block[0] = (byte)((epoch >> 8) & 0xFF);
+        block[1] = (byte)(epoch & 0xFF);
+    }
+
+    /**
+     * Increase the sequence number.
+     */
+    final void increaseSequenceNumber() {
+        /*
+         * The sequence number in the block array is a 64-bit
+         * number stored in big-endian format.
+         */
+        int k = 7;
+        while ((k >= 0) && (++block[k] == 0)) {
+            k--;
+        }
+    }
+
+    /**
      * Acquires the current message authentication information with the
      * specified record type and fragment length, and then increases the
      * sequence number.
      *
      * @param  type the record type
      * @param  length the fragment of the record
+     * @param  sequence the explicit sequence number of the record
+     *
      * @return the byte array of the current message authentication information
      */
-    final byte[] acquireAuthenticationBytes(byte type, int length) {
+    final byte[] acquireAuthenticationBytes(
+            byte type, int length, byte[] sequence) {
+
         byte[] copy = block.clone();
+        if (sequence != null) {
+            if (sequence.length != 8) {
+                throw new RuntimeException(
+                        "Insufficient explicit sequence number bytes");
+            }
+
+            System.arraycopy(sequence, 0, copy, 0, sequence.length);
+        }   // Otherwise, use the implicit sequence number.
 
         if (block.length != 0) {
             copy[8] = type;
+
             copy[copy.length - 2] = (byte)(length >> 8);
             copy[copy.length - 1] = (byte)(length);
 
-            /*
-             * Increase the sequence number in the block array
-             * it is a 64-bit number stored in big-endian format
-             */
-            int k = 7;
-            while ((k >= 0) && (++block[k] == 0)) {
-                k--;
+            if (sequence == null || sequence.length != 0) {
+                // Increase the implicit sequence number in the block array.
+                increaseSequenceNumber();
             }
         }
 
         return copy;
     }
 
+    final static long toLong(byte[] recordEnS) {
+        if (recordEnS != null && recordEnS.length == 8) {
+            return ((recordEnS[0] & 0xFFL) << 56) |
+                   ((recordEnS[1] & 0xFFL) << 48) |
+                   ((recordEnS[2] & 0xFFL) << 40) |
+                   ((recordEnS[3] & 0xFFL) << 32) |
+                   ((recordEnS[4] & 0xFFL) << 24) |
+                   ((recordEnS[5] & 0xFFL) << 16) |
+                   ((recordEnS[6] & 0xFFL) <<  8) |
+                    (recordEnS[7] & 0xFFL);
+        }
+
+        return -1L;
+    }
 }
--- a/jdk/src/java.base/share/classes/sun/security/ssl/CipherBox.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/CipherBox.java	Wed Jul 05 20:37:09 2017 +0200
@@ -154,9 +154,9 @@
      * NULL cipherbox. Identity operation, no encryption.
      */
     private CipherBox() {
-        this.protocolVersion = ProtocolVersion.DEFAULT;
+        this.protocolVersion = ProtocolVersion.DEFAULT_TLS;
         this.cipher = null;
-        this.cipherType = STREAM_CIPHER;
+        this.cipherType = NULL_CIPHER;
         this.fixedIv = new byte[0];
         this.key = null;
         this.mode = Cipher.ENCRYPT_MODE;    // choose at random
@@ -197,7 +197,7 @@
              */
             if (iv == null && bulkCipher.ivSize != 0 &&
                     mode == Cipher.DECRYPT_MODE &&
-                    protocolVersion.v >= ProtocolVersion.TLS11.v) {
+                    protocolVersion.useTLS11PlusSpec()) {
                 iv = getFixedMask(bulkCipher.ivSize);
             }
 
@@ -491,7 +491,7 @@
                 newLen = removePadding(
                     buf, offset, newLen, tagLen, blockSize, protocolVersion);
 
-                if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
+                if (protocolVersion.useTLS11PlusSpec()) {
                     if (newLen < blockSize) {
                         throw new BadPaddingException("invalid explicit IV");
                     }
@@ -573,7 +573,7 @@
                 newLen = removePadding(bb, tagLen, blockSize, protocolVersion);
 
                 // check the explicit IV of TLS v1.1 or later
-                if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
+                if (protocolVersion.useTLS11PlusSpec()) {
                     if (newLen < blockSize) {
                         throw new BadPaddingException("invalid explicit IV");
                     }
@@ -746,7 +746,7 @@
         // The padding data should be filled with the padding length value.
         int[] results = checkPadding(buf, offset + newLen,
                         padLen + 1, (byte)(padLen & 0xFF));
-        if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
+        if (protocolVersion.useTLS10PlusSpec()) {
             if (results[0] != 0) {          // padding data has invalid bytes
                 throw new BadPaddingException("Invalid TLS padding data");
             }
@@ -792,7 +792,7 @@
         int[] results = checkPadding(
                 bb.duplicate().position(offset + newLen),
                 (byte)(padLen & 0xFF));
-        if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
+        if (protocolVersion.useTLS10PlusSpec()) {
             if (results[0] != 0) {          // padding data has invalid bytes
                 throw new BadPaddingException("Invalid TLS padding data");
             }
@@ -873,7 +873,7 @@
                 // For block ciphers, the explicit IV length is of length
                 // SecurityParameters.record_iv_length, which is equal to
                 // the SecurityParameters.block_size.
-                if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
+                if (protocolVersion.useTLS11PlusSpec()) {
                     return cipher.getBlockSize();
                 }
                 break;
@@ -902,7 +902,7 @@
      * @return the explicit nonce size of the cipher.
      */
     int applyExplicitNonce(Authenticator authenticator, byte contentType,
-            ByteBuffer bb) throws BadPaddingException {
+            ByteBuffer bb, byte[] sequence) throws BadPaddingException {
         switch (cipherType) {
             case BLOCK_CIPHER:
                 // sanity check length of the ciphertext
@@ -918,7 +918,7 @@
                 // For block ciphers, the explicit IV length is of length
                 // SecurityParameters.record_iv_length, which is equal to
                 // the SecurityParameters.block_size.
-                if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
+                if (protocolVersion.useTLS11PlusSpec()) {
                     return cipher.getBlockSize();
                 }
                 break;
@@ -945,7 +945,8 @@
 
                 // update the additional authentication data
                 byte[] aad = authenticator.acquireAuthenticationBytes(
-                        contentType, bb.remaining() - recordIvSize - tagSize);
+                        contentType, bb.remaining() - recordIvSize - tagSize,
+                        sequence);
                 cipher.updateAAD(aad);
 
                 return recordIvSize;
@@ -957,33 +958,6 @@
     }
 
     /*
-     * Applies the explicit nonce/IV to this cipher. This method is used to
-     * decrypt an SSL/TLS input record.
-     *
-     * The returned value is the SecurityParameters.record_iv_length in
-     * RFC 4346/5246.  It is the size of explicit IV for CBC mode, and the
-     * size of explicit nonce for AEAD mode.
-     *
-     * @param  authenticator the authenticator to get the additional
-     *         authentication data
-     * @param  contentType the content type of the input record
-     * @param  buf the byte array to get the explicit nonce from
-     * @param  offset the offset of the byte buffer
-     * @param  cipheredLength the ciphered fragment length of the output
-     *         record, it is the TLSCiphertext.length in RFC 4346/5246.
-     *
-     * @return the explicit nonce size of the cipher.
-     */
-    int applyExplicitNonce(Authenticator authenticator,
-            byte contentType, byte[] buf, int offset,
-            int cipheredLength) throws BadPaddingException {
-
-        ByteBuffer bb = ByteBuffer.wrap(buf, offset, cipheredLength);
-
-        return applyExplicitNonce(authenticator, contentType, bb);
-    }
-
-    /*
      * Creates the explicit nonce/IV to this cipher. This method is used to
      * encrypt an SSL/TLS output record.
      *
@@ -1005,7 +979,7 @@
         byte[] nonce = new byte[0];
         switch (cipherType) {
             case BLOCK_CIPHER:
-                if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
+                if (protocolVersion.useTLS11PlusSpec()) {
                     // For block ciphers, the explicit IV length is of length
                     // SecurityParameters.record_iv_length, which is equal to
                     // the SecurityParameters.block_size.
@@ -1034,9 +1008,10 @@
                                 "invalid key or spec in GCM mode", ikae);
                 }
 
-                // update the additional authentication data
+                // Update the additional authentication data, using the
+                // implicit sequence number of the authenticator.
                 byte[] aad = authenticator.acquireAuthenticationBytes(
-                                                contentType, fragmentLength);
+                                        contentType, fragmentLength, null);
                 cipher.updateAAD(aad);
                 break;
         }
@@ -1044,6 +1019,93 @@
         return nonce;
     }
 
+    // See also CipherSuite.calculatePacketSize().
+    int calculatePacketSize(int fragmentSize, int macLen, int headerSize) {
+        int packetSize = fragmentSize;
+        if (cipher != null) {
+            int blockSize = cipher.getBlockSize();
+            switch (cipherType) {
+                case BLOCK_CIPHER:
+                    packetSize += macLen;
+                    packetSize += 1;        // 1 byte padding length field
+                    packetSize +=           // use the minimal padding
+                            (blockSize - (packetSize % blockSize)) % blockSize;
+                    if (protocolVersion.useTLS11PlusSpec()) {
+                        packetSize += blockSize;        // explicit IV
+                    }
+
+                    break;
+                case AEAD_CIPHER:
+                    packetSize += recordIvSize;
+                    packetSize += tagSize;
+
+                    break;
+                default:    // NULL_CIPHER or STREAM_CIPHER
+                    packetSize += macLen;
+            }
+        }
+
+        return packetSize + headerSize;
+    }
+
+    // See also CipherSuite.calculateFragSize().
+    int calculateFragmentSize(int packetLimit, int macLen, int headerSize) {
+        int fragLen = packetLimit - headerSize;
+        if (cipher != null) {
+            int blockSize = cipher.getBlockSize();
+            switch (cipherType) {
+                case BLOCK_CIPHER:
+                    if (protocolVersion.useTLS11PlusSpec()) {
+                        fragLen -= blockSize;           // explicit IV
+                    }
+                    fragLen -= (fragLen % blockSize);   // cannot hold a block
+                    // No padding for a maximum fragment.
+                    fragLen -= 1;       // 1 byte padding length field: 0x00
+                    fragLen -= macLen;
+
+                    break;
+                case AEAD_CIPHER:
+                    fragLen -= recordIvSize;
+                    fragLen -= tagSize;
+
+                    break;
+                default:    // NULL_CIPHER or STREAM_CIPHER
+                    fragLen -= macLen;
+            }
+        }
+
+        return fragLen;
+    }
+
+    // Estimate the maximum fragment size of a received packet.
+    int estimateFragmentSize(int packetSize, int macLen, int headerSize) {
+        int fragLen = packetSize - headerSize;
+        if (cipher != null) {
+            int blockSize = cipher.getBlockSize();
+            switch (cipherType) {
+                case BLOCK_CIPHER:
+                    if (protocolVersion.useTLS11PlusSpec()) {
+                        fragLen -= blockSize;       // explicit IV
+                    }
+                    // No padding for a maximum fragment.
+                    fragLen -= 1;       // 1 byte padding length field: 0x00
+                    fragLen -= macLen;
+
+                    break;
+                case AEAD_CIPHER:
+                    fragLen -= recordIvSize;
+                    fragLen -= tagSize;
+
+                    break;
+                default:    // NULL_CIPHER or STREAM_CIPHER
+                    fragLen -= macLen;
+            }
+        }
+
+        return fragLen;
+    }
+
+
     /*
      * Is this cipher available?
      *
@@ -1100,7 +1162,7 @@
         if ((fragmentLen % blockSize) == 0) {
             int minimal = tagLen + 1;
             minimal = (minimal >= blockSize) ? minimal : blockSize;
-            if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
+            if (protocolVersion.useTLS11PlusSpec()) {
                 minimal += blockSize;   // plus the size of the explicit IV
             }
 
--- a/jdk/src/java.base/share/classes/sun/security/ssl/CipherSuite.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/CipherSuite.java	Wed Jul 05 20:37:09 2017 +0200
@@ -122,9 +122,15 @@
     final boolean allowed;
 
     // obsoleted since protocol version
+    //
+    // TLS version is used.  If checking DTLS versions, please map to
+    // TLS version firstly.  See ProtocolVersion.mapToTLSProtocol().
     final int obsoleted;
 
-    // supported since protocol version
+    // supported since protocol version (TLS version is used)
+    //
+    // TLS version is used.  If checking DTLS versions, please map to
+    // TLS version firstly.  See ProtocolVersion.mapToTLSProtocol().
     final int supported;
 
     /**
@@ -182,6 +188,70 @@
         return this != C_SCSV && isAvailable();
     }
 
+    // See also CipherBox.calculatePacketSize().
+    int calculatePacketSize(int fragmentSize,
+            ProtocolVersion protocolVersion, boolean isDTLS) {
+
+        int packetSize = fragmentSize;
+        if (cipher != B_NULL) {
+            int blockSize = cipher.ivSize;
+            switch (cipher.cipherType) {
+                case BLOCK_CIPHER:
+                    packetSize += macAlg.size;
+                    packetSize += 1;        // 1 byte padding length field
+                    packetSize +=           // use the minimal padding
+                            (blockSize - (packetSize % blockSize)) % blockSize;
+                    if (protocolVersion.useTLS11PlusSpec()) {
+                        packetSize += blockSize;        // explicit IV
+                    }
+
+                    break;
+            case AEAD_CIPHER:
+                packetSize += cipher.ivSize - cipher.fixedIvSize;   // record IV
+                packetSize += cipher.tagSize;
+
+                break;
+            default:    // NULL_CIPHER or STREAM_CIPHER
+                packetSize += macAlg.size;
+            }
+        }
+
+        return packetSize +
+            (isDTLS ? DTLSRecord.headerSize : SSLRecord.headerSize);
+    }
+
+    // See also CipherBox.calculateFragmentSize().
+    int calculateFragSize(int packetLimit,
+            ProtocolVersion protocolVersion, boolean isDTLS) {
+
+        int fragSize = packetLimit -
+                (isDTLS ? DTLSRecord.headerSize : SSLRecord.headerSize);
+        if (cipher != B_NULL) {
+            int blockSize = cipher.ivSize;
+            switch (cipher.cipherType) {
+            case BLOCK_CIPHER:
+                if (protocolVersion.useTLS11PlusSpec()) {
+                    fragSize -= blockSize;              // explicit IV
+                }
+                fragSize -= (fragSize % blockSize);     // cannot hold a block
+                // No padding for a maximum fragment.
+                fragSize -= 1;        // 1 byte padding length field: 0x00
+                fragSize -= macAlg.size;
+
+                break;
+            case AEAD_CIPHER:
+                fragSize -= cipher.tagSize;
+                fragSize -= cipher.ivSize - cipher.fixedIvSize;     // record IV
+
+                break;
+            default:    // NULL_CIPHER or STREAM_CIPHER
+                fragSize -= macAlg.size;
+            }
+        }
+
+        return fragSize;
+    }
+
     /**
      * Compares CipherSuites based on their priority. Has the effect of
      * sorting CipherSuites when put in a sorted collection, which is
@@ -242,7 +312,7 @@
         return c;
     }
 
-    // for use by CipherSuiteList only
+    // for use by SSLContextImpl only
     static Collection<CipherSuite> allowedCipherSuites() {
         return nameMap.values();
     }
@@ -372,7 +442,8 @@
     }
 
     static enum CipherType {
-        STREAM_CIPHER,         // null or stream cipher
+        NULL_CIPHER,           // null cipher
+        STREAM_CIPHER,         // stream cipher
         BLOCK_CIPHER,          // block cipher in CBC mode
         AEAD_CIPHER            // AEAD cipher
     }
@@ -387,7 +458,7 @@
     static enum BulkCipher {
 
         // export strength ciphers
-        B_NULL("NULL", STREAM_CIPHER, 0, 0, 0, 0, true),
+        B_NULL("NULL", NULL_CIPHER, 0, 0, 0, 0, true),
         B_RC4_40(CIPHER_RC4, STREAM_CIPHER, 5, 16, 0, 0, true),
         B_RC2_40("RC2", BLOCK_CIPHER, 5, 16, 8, 0, false),
         B_DES_40(CIPHER_DES,  BLOCK_CIPHER, 5, 8, 8, 0, true),
@@ -568,7 +639,7 @@
                             iv = new IvParameterSpec(new byte[cipher.ivSize]);
                         }
                         temporary = cipher.newCipher(
-                                            ProtocolVersion.DEFAULT,
+                                            ProtocolVersion.DEFAULT_TLS,
                                             key, iv, secureRandom, true);
                         b = temporary.isAvailable();
                     } catch (NoSuchAlgorithmException e) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/Ciphertext.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.security.ssl;
+
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import static sun.security.ssl.HandshakeMessage.*;
+
+/*
+ * enumeration of record type
+ */
+final class Ciphertext {
+    final static Ciphertext CIPHERTEXT_NULL = new Ciphertext();
+
+    RecordType recordType;
+    long recordSN;
+
+    HandshakeStatus handshakeStatus;    // null if not used or not handshaking
+
+    Ciphertext() {
+        this.recordType = null;
+        this.recordSN = -1L;
+        this.handshakeStatus = null;
+    }
+
+    Ciphertext(RecordType recordType, long recordSN) {
+        this.recordType = recordType;
+        this.recordSN = recordSN;
+        this.handshakeStatus = null;
+    }
+
+    static enum RecordType {
+        RECORD_CHANGE_CIPHER_SPEC (
+                Record.ct_change_cipher_spec, ht_not_applicable),
+        RECORD_ALERT (
+                Record.ct_alert, ht_not_applicable),
+        RECORD_HELLO_REQUEST (
+                Record.ct_handshake, ht_hello_request),
+        RECORD_CLIENT_HELLO (
+                Record.ct_handshake, ht_client_hello),
+        RECORD_SERVER_HELLO (
+                Record.ct_handshake, ht_server_hello),
+        RECORD_HELLO_VERIFY_REQUEST (
+                Record.ct_handshake, ht_hello_verify_request),
+        RECORD_NEW_SESSION_TICKET (
+                Record.ct_handshake, ht_new_session_ticket),
+        RECORD_CERTIFICATE (
+                Record.ct_handshake, ht_certificate),
+        RECORD_SERVER_KEY_EXCHANGE (
+                Record.ct_handshake, ht_server_key_exchange),
+        RECORD_CERTIFICATE_REQUEST (
+                Record.ct_handshake, ht_certificate_request),
+        RECORD_SERVER_HELLO_DONE (
+                Record.ct_handshake, ht_server_hello_done),
+        RECORD_CERTIFICATE_VERIFY (
+                Record.ct_handshake, ht_certificate_verify),
+        RECORD_CLIENT_KEY_EXCHANGE (
+                Record.ct_handshake, ht_client_key_exchange),
+        RECORD_FINISHED (
+                Record.ct_handshake, ht_finished),
+        RECORD_CERTIFICATE_URL (
+                Record.ct_handshake, ht_certificate_url),
+        RECORD_CERTIFICATE_STATUS (
+                Record.ct_handshake, ht_certificate_status),
+        RECORD_SUPPLIEMENTAL_DATA (
+                Record.ct_handshake, ht_supplemental_data),
+        RECORD_APPLICATION_DATA (
+                Record.ct_application_data, ht_not_applicable);
+
+        byte contentType;
+        byte handshakeType;
+
+        private RecordType(byte contentType, byte handshakeType) {
+            this.contentType = contentType;
+            this.handshakeType = handshakeType;
+        }
+
+        static RecordType valueOf(byte contentType, byte handshakeType) {
+            if (contentType == Record.ct_change_cipher_spec) {
+                return RECORD_CHANGE_CIPHER_SPEC;
+            } else if (contentType == Record.ct_alert) {
+                return RECORD_ALERT;
+            } else if (contentType == Record.ct_application_data) {
+                return RECORD_APPLICATION_DATA;
+            } else if (handshakeType == ht_hello_request) {
+                return RECORD_HELLO_REQUEST;
+            } else if (handshakeType == ht_client_hello) {
+                return RECORD_CLIENT_HELLO;
+            } else if (handshakeType == ht_server_hello) {
+                return RECORD_SERVER_HELLO;
+            } else if (handshakeType == ht_hello_verify_request) {
+                return RECORD_HELLO_VERIFY_REQUEST;
+            } else if (handshakeType == ht_new_session_ticket) {
+                return RECORD_NEW_SESSION_TICKET;
+            } else if (handshakeType == ht_certificate) {
+                return RECORD_CERTIFICATE;
+            } else if (handshakeType == ht_server_key_exchange) {
+                return RECORD_SERVER_KEY_EXCHANGE;
+            } else if (handshakeType == ht_certificate_request) {
+                return RECORD_CERTIFICATE_REQUEST;
+            } else if (handshakeType == ht_server_hello_done) {
+                return RECORD_SERVER_HELLO_DONE;
+            } else if (handshakeType == ht_certificate_verify) {
+                return RECORD_CERTIFICATE_VERIFY;
+            } else if (handshakeType == ht_client_key_exchange) {
+                return RECORD_CLIENT_KEY_EXCHANGE;
+            } else if (handshakeType == ht_finished) {
+                return RECORD_FINISHED;
+            } else if (handshakeType == ht_certificate_url) {
+                return RECORD_CERTIFICATE_URL;
+            } else if (handshakeType == ht_certificate_status) {
+                return RECORD_CERTIFICATE_STATUS;
+            } else if (handshakeType == ht_supplemental_data) {
+                return RECORD_SUPPLIEMENTAL_DATA;
+            }
+
+            // otherwise, invalid record type
+            throw new IllegalArgumentException(
+                    "Invalid record type (ContentType:" + contentType +
+                    ", HandshakeType:" + handshakeType + ")");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ClientAuthType.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.security.ssl;
+
+/**
+ * Client authentication type.
+ */
+enum ClientAuthType {
+    CLIENT_AUTH_NONE,           // turn off client authentication
+    CLIENT_AUTH_REQUESTED,      // need to request client authentication
+    CLIENT_AUTH_REQUIRED        // require client authentication
+}
+
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java	Wed Jul 05 20:37:09 2017 +0200
@@ -44,8 +44,6 @@
 
 import javax.net.ssl.*;
 
-import javax.security.auth.Subject;
-
 import sun.security.ssl.HandshakeMessage.*;
 import static sun.security.ssl.CipherSuite.KeyExchange.*;
 
@@ -141,11 +139,20 @@
     private final static boolean allowUnsafeServerCertChange =
         Debug.getBooleanProperty("jdk.tls.allowUnsafeServerCertChange", false);
 
+    // To switch off the max_fragment_length extension.
+    private final static boolean enableMFLExtension =
+            Debug.getBooleanProperty("jsse.enableMFLExtension", false);
+
     private List<SNIServerName> requestedServerNames =
             Collections.<SNIServerName>emptyList();
 
+    // maximum fragment length
+    private int requestedMFLength = -1;     // -1: no fragment length limit
+
     private boolean serverNamesAccepted = false;
 
+    private ClientHello initialClientHelloMsg = null;   // DTLS only
+
     /*
      * the reserved server certificate chain in previous handshaking
      *
@@ -172,11 +179,12 @@
             ProtocolList enabledProtocols,
             ProtocolVersion activeProtocolVersion,
             boolean isInitialHandshake, boolean secureRenegotiation,
-            byte[] clientVerifyData, byte[] serverVerifyData) {
+            byte[] clientVerifyData, byte[] serverVerifyData,
+            boolean isDTLS) {
 
         super(engine, context, enabledProtocols, true, true,
             activeProtocolVersion, isInitialHandshake, secureRenegotiation,
-            clientVerifyData, serverVerifyData);
+            clientVerifyData, serverVerifyData, isDTLS);
     }
 
     /*
@@ -191,29 +199,48 @@
      */
     @Override
     void processMessage(byte type, int messageLen) throws IOException {
-        if (state >= type
-                && (type != HandshakeMessage.ht_hello_request)) {
-            throw new SSLProtocolException(
-                    "Handshake message sequence violation, " + type);
-        }
+        // check the handshake state
+        handshakeState.check(type);
 
         switch (type) {
         case HandshakeMessage.ht_hello_request:
-            this.serverHelloRequest(new HelloRequest(input));
+            HelloRequest helloRequest = new HelloRequest(input);
+            handshakeState.update(helloRequest, resumingSession);
+            this.serverHelloRequest(helloRequest);
+            break;
+
+        case HandshakeMessage.ht_hello_verify_request:
+            if (!isDTLS) {
+                throw new SSLProtocolException(
+                    "hello_verify_request is not a SSL/TLS handshake message");
+            }
+
+            HelloVerifyRequest helloVerifyRequest =
+                        new HelloVerifyRequest(input, messageLen);
+            handshakeState.update(helloVerifyRequest, resumingSession);
+            this.helloVerifyRequest(helloVerifyRequest);
             break;
 
         case HandshakeMessage.ht_server_hello:
-            this.serverHello(new ServerHello(input, messageLen));
+            ServerHello serverHello = new ServerHello(input, messageLen);
+            this.serverHello(serverHello);
+
+            // This handshake state update needs the resumingSession value
+            // set by serverHello().
+            handshakeState.update(serverHello, resumingSession);
             break;
 
         case HandshakeMessage.ht_certificate:
             if (keyExchange == K_DH_ANON || keyExchange == K_ECDH_ANON
-                    || keyExchange == K_KRB5 || keyExchange == K_KRB5_EXPORT) {
+                    || ClientKeyExchangeService.find(keyExchange.name) != null) {
+                // No external key exchange provider needs a cert now.
                 fatalSE(Alerts.alert_unexpected_message,
                     "unexpected server cert chain");
                 // NOTREACHED
             }
-            this.serverCertificate(new CertificateMsg(input));
+            CertificateMsg certificateMsg = new CertificateMsg(input);
+            handshakeState.update(certificateMsg, resumingSession);
+            this.serverCertificate(certificateMsg);
             serverKey =
                 session.getPeerCertificates()[0].getPublicKey();
             break;
@@ -249,41 +276,52 @@
                 }
 
                 try {
-                    this.serverKeyExchange(new RSA_ServerKeyExchange(input));
+                    RSA_ServerKeyExchange rsaSrvKeyExchange =
+                                    new RSA_ServerKeyExchange(input);
+                    handshakeState.update(rsaSrvKeyExchange, resumingSession);
+                    this.serverKeyExchange(rsaSrvKeyExchange);
                 } catch (GeneralSecurityException e) {
-                    throwSSLException("Server key", e);
+                    throw new SSLException("Server key", e);
                 }
                 break;
             case K_DH_ANON:
                 try {
-                    this.serverKeyExchange(new DH_ServerKeyExchange(
-                                                input, protocolVersion));
+                    DH_ServerKeyExchange dhSrvKeyExchange =
+                            new DH_ServerKeyExchange(input, protocolVersion);
+                    handshakeState.update(dhSrvKeyExchange, resumingSession);
+                    this.serverKeyExchange(dhSrvKeyExchange);
                 } catch (GeneralSecurityException e) {
-                    throwSSLException("Server key", e);
+                    throw new SSLException("Server key", e);
                 }
                 break;
             case K_DHE_DSS:
             case K_DHE_RSA:
                 try {
-                    this.serverKeyExchange(new DH_ServerKeyExchange(
-                        input, serverKey,
-                        clnt_random.random_bytes, svr_random.random_bytes,
-                        messageLen,
-                        localSupportedSignAlgs, protocolVersion));
+                    DH_ServerKeyExchange dhSrvKeyExchange =
+                        new DH_ServerKeyExchange(
+                            input, serverKey,
+                            clnt_random.random_bytes, svr_random.random_bytes,
+                            messageLen,
+                            localSupportedSignAlgs, protocolVersion);
+                    handshakeState.update(dhSrvKeyExchange, resumingSession);
+                    this.serverKeyExchange(dhSrvKeyExchange);
                 } catch (GeneralSecurityException e) {
-                    throwSSLException("Server key", e);
+                    throw new SSLException("Server key", e);
                 }
                 break;
             case K_ECDHE_ECDSA:
             case K_ECDHE_RSA:
             case K_ECDH_ANON:
                 try {
-                    this.serverKeyExchange(new ECDH_ServerKeyExchange
-                        (input, serverKey, clnt_random.random_bytes,
-                        svr_random.random_bytes,
-                        localSupportedSignAlgs, protocolVersion));
+                    ECDH_ServerKeyExchange ecdhSrvKeyExchange =
+                        new ECDH_ServerKeyExchange
+                            (input, serverKey, clnt_random.random_bytes,
+                            svr_random.random_bytes,
+                            localSupportedSignAlgs, protocolVersion);
+                    handshakeState.update(ecdhSrvKeyExchange, resumingSession);
+                    this.serverKeyExchange(ecdhSrvKeyExchange);
                 } catch (GeneralSecurityException e) {
-                    throwSSLException("Server key", e);
+                    throw new SSLException("Server key", e);
                 }
                 break;
             case K_RSA:
@@ -294,13 +332,9 @@
                 throw new SSLProtocolException(
                     "Protocol violation: server sent a server key exchange"
                     + " message for key exchange " + keyExchange);
-            case K_KRB5:
-            case K_KRB5_EXPORT:
-                throw new SSLProtocolException(
-                    "unexpected receipt of server key exchange algorithm");
             default:
                 throw new SSLProtocolException(
-                    "unsupported key exchange algorithm = "
+                    "unsupported or unexpected key exchange algorithm = "
                     + keyExchange);
             }
             break;
@@ -311,17 +345,19 @@
                 throw new SSLHandshakeException(
                     "Client authentication requested for "+
                     "anonymous cipher suite.");
-            } else if (keyExchange == K_KRB5 || keyExchange == K_KRB5_EXPORT) {
+            } else if (ClientKeyExchangeService.find(keyExchange.name) != null) {
+                // No external key exchange provider needs a cert now.
                 throw new SSLHandshakeException(
                     "Client certificate requested for "+
-                    "kerberos cipher suite.");
+                    "external cipher suite: " + keyExchange);
             }
             certRequest = new CertificateRequest(input, protocolVersion);
             if (debug != null && Debug.isOn("handshake")) {
                 certRequest.print(System.out);
             }
+            handshakeState.update(certRequest, resumingSession);
 
-            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (protocolVersion.useTLS12PlusSpec()) {
                 Collection<SignatureAndHashAlgorithm> peerSignAlgs =
                                         certRequest.getSignAlgorithms();
                 if (peerSignAlgs == null || peerSignAlgs.isEmpty()) {
@@ -345,33 +381,24 @@
             break;
 
         case HandshakeMessage.ht_server_hello_done:
-            this.serverHelloDone(new ServerHelloDone(input));
+            ServerHelloDone serverHelloDone = new ServerHelloDone(input);
+            handshakeState.update(serverHelloDone, resumingSession);
+            this.serverHelloDone(serverHelloDone);
+
             break;
 
         case HandshakeMessage.ht_finished:
-            // A ChangeCipherSpec record must have been received prior to
-            // reception of the Finished message (RFC 5246, 7.4.9).
-            if (!receivedChangeCipherSpec()) {
-                fatalSE(Alerts.alert_handshake_failure,
-                    "Received Finished message before ChangeCipherSpec");
-            }
+            Finished serverFinished =
+                    new Finished(protocolVersion, input, cipherSuite);
+            handshakeState.update(serverFinished, resumingSession);
+            this.serverFinished(serverFinished);
 
-            this.serverFinished(
-                new Finished(protocolVersion, input, cipherSuite));
             break;
 
         default:
             throw new SSLProtocolException(
                 "Illegal client handshake msg, " + type);
         }
-
-        //
-        // Move state machine forward if the message handling
-        // code didn't already do so
-        //
-        if (state < type) {
-            state = type;
-        }
     }
 
     /*
@@ -389,10 +416,10 @@
         // Could be (e.g. at connection setup) that we already
         // sent the "client hello" but the server's not seen it.
         //
-        if (state < HandshakeMessage.ht_client_hello) {
+        if (!clientHelloDelivered) {
             if (!secureRenegotiation && !allowUnsafeRenegotiation) {
                 // renegotiation is not allowed.
-                if (activeProtocolVersion.v >= ProtocolVersion.TLS10.v) {
+                if (activeProtocolVersion.useTLS10PlusSpec()) {
                     // response with a no_renegotiation warning,
                     warningSE(Alerts.alert_no_renegotiation);
 
@@ -428,6 +455,29 @@
         }
     }
 
+    private void helloVerifyRequest(
+            HelloVerifyRequest mesg) throws IOException {
+
+        if (debug != null && Debug.isOn("handshake")) {
+            mesg.print(System.out);
+        }
+
+        //
+        // Note that HelloVerifyRequest.server_version is used solely to
+        // indicate packet formatting, and not as part of version negotiation.
+        // Need not to check version values match for HelloVerifyRequest
+        // message.
+        //
+        initialClientHelloMsg.cookie = mesg.cookie.clone();
+
+        if (debug != null && Debug.isOn("handshake")) {
+            initialClientHelloMsg.print(System.out);
+        }
+
+        // deliver the ClientHello message with cookie
+        initialClientHelloMsg.write(output);
+        handshakeState.update(initialClientHelloMsg, resumingSession);
+    }
 
     /*
      * Server chooses session parameters given options created by the
@@ -441,6 +491,9 @@
      * probably authentication getting done.
      */
     private void serverHello(ServerHello mesg) throws IOException {
+        // Dispose the reserved ClientHello message (if exists).
+        initialClientHelloMsg = null;
+
         serverKeyExchangeReceived = false;
         if (debug != null && Debug.isOn("handshake")) {
             mesg.print(System.out);
@@ -536,7 +589,7 @@
         }
 
         setCipherSuite(mesg.cipherSuite);
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             handshakeHash.setFinishedAlg(cipherSuite.prfAlg.getPRFHashAlg());
         }
 
@@ -569,51 +622,22 @@
                 }
 
                 // validate subject identity
-                if (sessionSuite.keyExchange == K_KRB5 ||
-                    sessionSuite.keyExchange == K_KRB5_EXPORT) {
+                ClientKeyExchangeService p =
+                        ClientKeyExchangeService.find(sessionSuite.keyExchange.name);
+                if (p != null) {
                     Principal localPrincipal = session.getLocalPrincipal();
 
-                    Subject subject = null;
-                    try {
-                        subject = AccessController.doPrivileged(
-                            new PrivilegedExceptionAction<Subject>() {
-                            @Override
-                            public Subject run() throws Exception {
-                                return Krb5Helper.getClientSubject(getAccSE());
-                            }});
-                    } catch (PrivilegedActionException e) {
-                        subject = null;
-                        if (debug != null && Debug.isOn("session")) {
-                            System.out.println("Attempt to obtain" +
-                                        " subject failed!");
-                        }
-                    }
-
-                    if (subject != null) {
-                        // Eliminate dependency on KerberosPrincipal
-                        Set<Principal> principals =
-                            subject.getPrincipals(Principal.class);
-                        if (!principals.contains(localPrincipal)) {
-                            throw new SSLProtocolException("Server resumed" +
-                                " session with wrong subject identity");
-                        } else {
-                            if (debug != null && Debug.isOn("session"))
-                                System.out.println("Subject identity is same");
-                        }
+                    if (p.isRelated(true, getAccSE(), localPrincipal)) {
+                        if (debug != null && Debug.isOn("session"))
+                            System.out.println("Subject identity is same");
                     } else {
-                        if (debug != null && Debug.isOn("session"))
-                            System.out.println("Kerberos credentials are not" +
-                                " present in the current Subject; check if " +
-                                " javax.security.auth.useSubjectAsCreds" +
-                                " system property has been set to false");
-                        throw new SSLProtocolException
-                            ("Server resumed session with no subject");
+                        throw new SSLProtocolException("Server resumed" +
+                                " session with wrong subject identity or no subject");
                     }
                 }
 
-                // looks fine; resume it, and update the state machine.
+                // looks fine; resume it.
                 resumingSession = true;
-                state = HandshakeMessage.ht_finished - 1;
                 calculateConnectionKeys(session.getMasterSecret());
                 if (debug != null && Debug.isOn("session")) {
                     System.out.println("%% Server resumed " + session);
@@ -627,6 +651,24 @@
             }
         }
 
+        // check the "max_fragment_length" extension
+        MaxFragmentLengthExtension maxFragLenExt = (MaxFragmentLengthExtension)
+                mesg.extensions.get(ExtensionType.EXT_MAX_FRAGMENT_LENGTH);
+        if (maxFragLenExt != null) {
+            if ((requestedMFLength == -1) ||
+                    maxFragLenExt.getMaxFragLen() != requestedMFLength) {
+                // If the client did not request this extension, or the
+                // response value is different from the length it requested,
+                // abort the handshake with a fatal illegal_parameter alert.
+                fatalSE(Alerts.alert_illegal_parameter,
+                        "Failed to negotiate the max_fragment_length");
+            }
+        } else if (!resumingSession) {
+            // no "max_fragment_length" extension
+            requestedMFLength = -1;
+        }   // Otherwise, using the value negotiated during the original
+            // session initiation
+
         if (resumingSession && session != null) {
             setHandshakeSessionSE(session);
             // Reserve the handshake state if this is a session-resumption
@@ -657,6 +699,8 @@
                             getLocalSupportedSignAlgs(),
                             mesg.sessionId, getHostSE(), getPortSE());
         session.setRequestedServerNames(requestedServerNames);
+        session.setNegotiatedMaxFragSize(requestedMFLength);
+        session.setMaximumPacketSize(maximumPacketSize);
         setHandshakeSessionSE(session);
         if (debug != null && Debug.isOn("handshake")) {
             System.out.println("** " + cipherSuite);
@@ -681,7 +725,6 @@
         ephemeralServerKey = mesg.getPublicKey();
     }
 
-
     /*
      * Diffie-Hellman key exchange.  We save the server public key and
      * our own D-H algorithm object so we can defer key calculations
@@ -716,13 +759,6 @@
         if (debug != null && Debug.isOn("handshake")) {
             mesg.print(System.out);
         }
-        /*
-         * Always make sure the input has been digested before we
-         * start emitting data, to ensure the hashes are correctly
-         * computed for the Finished and CertificateVerify messages
-         * which we send (here).
-         */
-        input.digestNow();
 
         /*
          * FIRST ... if requested, send an appropriate Certificate chain
@@ -817,7 +853,7 @@
                 // server.  For SSLv3, send the no_certificate alert;
                 // TLS uses an empty cert chain instead.
                 //
-                if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
+                if (protocolVersion.useTLS10PlusSpec()) {
                     m1 = new CertificateMsg(new X509Certificate [0]);
                 } else {
                     warningSE(Alerts.alert_no_certificate);
@@ -837,6 +873,7 @@
                     m1.print(System.out);
                 }
                 m1.write(output);
+                handshakeState.update(m1, resumingSession);
             }
         }
 
@@ -943,8 +980,14 @@
             ecdh = new ECDHCrypt(params, sslContext.getSecureRandom());
             m2 = new ECDHClientKeyExchange(ecdh.getPublicKey());
             break;
-        case K_KRB5:
-        case K_KRB5_EXPORT:
+        default:
+            ClientKeyExchangeService p =
+                    ClientKeyExchangeService.find(keyExchange.name);
+            if (p == null) {
+                // somethings very wrong
+                throw new RuntimeException
+                        ("Unsupported key exchange: " + keyExchange);
+            }
             String sniHostname = null;
             for (SNIServerName serverName : requestedServerNames) {
                 if (serverName instanceof SNIHostName) {
@@ -953,13 +996,13 @@
                 }
             }
 
-            KerberosClientKeyExchange kerberosMsg = null;
+            ClientKeyExchange exMsg = null;
             if (sniHostname != null) {
                 // use first requested SNI hostname
                 try {
-                    kerberosMsg = new KerberosClientKeyExchange(
-                        sniHostname, getAccSE(), protocolVersion,
-                        sslContext.getSecureRandom());
+                    exMsg = p.createClientExchange(
+                            sniHostname, getAccSE(), protocolVersion,
+                            sslContext.getSecureRandom());
                 } catch(IOException e) {
                     if (serverNamesAccepted) {
                         // server accepted requested SNI hostname,
@@ -975,32 +1018,28 @@
                 }
             }
 
-            if (kerberosMsg == null) {
+            if (exMsg == null) {
                 String hostname = getHostSE();
                 if (hostname == null) {
                     throw new IOException("Hostname is required" +
-                        " to use Kerberos cipher suites");
+                        " to use " + keyExchange + " key exchange");
                 }
-                kerberosMsg = new KerberosClientKeyExchange(
-                     hostname, getAccSE(), protocolVersion,
-                     sslContext.getSecureRandom());
+                exMsg = p.createClientExchange(
+                        hostname, getAccSE(), protocolVersion,
+                        sslContext.getSecureRandom());
             }
 
             // Record the principals involved in exchange
-            session.setPeerPrincipal(kerberosMsg.getPeerPrincipal());
-            session.setLocalPrincipal(kerberosMsg.getLocalPrincipal());
-            m2 = kerberosMsg;
+            session.setPeerPrincipal(exMsg.getPeerPrincipal());
+            session.setLocalPrincipal(exMsg.getLocalPrincipal());
+            m2 = exMsg;
             break;
-        default:
-            // somethings very wrong
-            throw new RuntimeException
-                                ("Unsupported key exchange: " + keyExchange);
         }
         if (debug != null && Debug.isOn("handshake")) {
             m2.print(System.out);
         }
         m2.write(output);
-
+        handshakeState.update(m2, resumingSession);
 
         /*
          * THIRD, send a "change_cipher_spec" record followed by the
@@ -1010,8 +1049,6 @@
          * to compute the "Finished" message, and to compute the keys used
          * to protect all records following the change_cipher_spec.
          */
-
-        output.doHashes();
         output.flush();
 
         /*
@@ -1027,13 +1064,6 @@
         case K_RSA_EXPORT:
             preMasterSecret = ((RSAClientKeyExchange)m2).preMaster;
             break;
-        case K_KRB5:
-        case K_KRB5_EXPORT:
-            byte[] secretBytes =
-                ((KerberosClientKeyExchange)m2).getUnencryptedPreMasterSecret();
-            preMasterSecret = new SecretKeySpec(secretBytes,
-                "TlsPremasterSecret");
-            break;
         case K_DHE_RSA:
         case K_DHE_DSS:
         case K_DH_ANON:
@@ -1049,8 +1079,13 @@
             preMasterSecret = ecdh.getAgreedSecret(serverKey);
             break;
         default:
-            throw new IOException("Internal error: unknown key exchange "
-                + keyExchange);
+            if (ClientKeyExchangeService.find(keyExchange.name) != null) {
+                preMasterSecret =
+                        ((ClientKeyExchange) m2).clientKeyExchange();
+            } else {
+                throw new IOException("Internal error: unknown key exchange "
+                        + keyExchange);
+            }
         }
 
         calculateKeys(preMasterSecret, null);
@@ -1069,7 +1104,7 @@
             CertificateVerify m3;
             try {
                 SignatureAndHashAlgorithm preferableSignatureAlgorithm = null;
-                if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                if (protocolVersion.useTLS12PlusSpec()) {
                     preferableSignatureAlgorithm =
                         SignatureAndHashAlgorithm.getPreferableAlgorithm(
                             peerSupportedSignAlgs, signingKey.getAlgorithm(),
@@ -1103,13 +1138,17 @@
                 m3.print(System.out);
             }
             m3.write(output);
-            output.doHashes();
+            handshakeState.update(m3, resumingSession);
+            output.flush();
         }
 
         /*
          * OK, that's that!
          */
         sendChangeCipherAndFinish(false);
+
+        // expecting the final ChangeCipherSpec and Finished messages
+        expectingFinishFlightSE();
     }
 
 
@@ -1158,8 +1197,9 @@
          * completed handshakes.
          */
         if (resumingSession) {
-            input.digestNow();
             sendChangeCipherAndFinish(true);
+        } else {
+            handshakeFinished = true;
         }
         session.setLastAccessedTime(System.currentTimeMillis());
 
@@ -1188,6 +1228,10 @@
      */
     private void sendChangeCipherAndFinish(boolean finishedTag)
             throws IOException {
+
+        // Reload if this message has been reserved.
+        handshakeHash.reload();
+
         Finished mesg = new Finished(protocolVersion, handshakeHash,
             Finished.CLIENT, session.getMasterSecret(), cipherSuite);
 
@@ -1205,13 +1249,6 @@
         if (secureRenegotiation) {
             clientVerifyData = mesg.getVerifyData();
         }
-
-        /*
-         * Update state machine so server MUST send 'finished' next.
-         * (In "long" handshake case; in short case, we're responding
-         * to its message.)
-         */
-        state = HandshakeMessage.ht_finished - 1;
     }
 
 
@@ -1361,10 +1398,10 @@
         // create the ClientHello message
         ClientHello clientHelloMessage = new ClientHello(
                 sslContext.getSecureRandom(), maxProtocolVersion,
-                sessionId, cipherSuites);
+                sessionId, cipherSuites, isDTLS);
 
         // add signature_algorithm extension
-        if (maxProtocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (maxProtocolVersion.useTLS12PlusSpec()) {
             // we will always send the signature_algorithm extension
             Collection<SignatureAndHashAlgorithm> localSignAlgs =
                                                 getLocalSupportedSignAlgs();
@@ -1389,6 +1426,37 @@
             }
         }
 
+        // add max_fragment_length extension
+        if (enableMFLExtension) {
+            if (session != null) {
+                // The same extension should be sent for resumption.
+                requestedMFLength = session.getNegotiatedMaxFragSize();
+            } else if (maximumPacketSize != 0) {
+                // Maybe we can calculate the fragment size more accurate
+                // by condering the enabled cipher suites in the future.
+                requestedMFLength = maximumPacketSize;
+                if (isDTLS) {
+                    requestedMFLength -= DTLSRecord.maxPlaintextPlusSize;
+                } else {
+                    requestedMFLength -= SSLRecord.maxPlaintextPlusSize;
+                }
+            } else {
+                // Need no max_fragment_length extension.
+                requestedMFLength = -1;
+            }
+
+            if ((requestedMFLength > 0) &&
+                MaxFragmentLengthExtension.needFragLenNego(requestedMFLength)) {
+
+                requestedMFLength =
+                        MaxFragmentLengthExtension.getValidMaxFragLen(
+                                                        requestedMFLength);
+                clientHelloMessage.addMFLExtension(requestedMFLength);
+            } else {
+                requestedMFLength = -1;
+            }
+        }
+
         // reset the client random cookie
         clnt_random = clientHelloMessage.clnt_random;
 
@@ -1403,6 +1471,11 @@
             clientHelloMessage.addRenegotiationInfoExtension(clientVerifyData);
         }
 
+        if (isDTLS) {
+            // Cookie exchange need to reserve the initial ClientHello message.
+            initialClientHelloMsg = clientHelloMessage;
+        }
+
         return clientHelloMessage;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ClientKeyExchange.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,60 @@
+/*
+ * 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
+ * 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.security.ssl;
+
+import javax.crypto.SecretKey;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.security.Principal;
+
+/**
+ * Models a non-certificate based ClientKeyExchange
+ */
+public abstract class ClientKeyExchange extends HandshakeMessage {
+
+    public ClientKeyExchange() {
+    }
+
+    @Override
+    int messageType() {
+        return ht_client_key_exchange;
+    }
+
+    @Override
+    abstract public int messageLength();
+
+    @Override
+    abstract public void send(HandshakeOutStream s) throws IOException;
+
+    @Override
+    abstract public void print(PrintStream s) throws IOException;
+
+    abstract public SecretKey clientKeyExchange();
+
+    abstract public Principal getPeerPrincipal();
+
+    abstract public Principal getLocalPrincipal();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ClientKeyExchangeService.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.security.ssl;
+
+import sun.security.action.GetPropertyAction;
+
+import java.io.File;
+import java.io.FilePermission;
+import java.io.IOException;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.Principal;
+import java.security.PrivilegedAction;
+import java.security.SecureRandom;
+import java.util.*;
+
+/**
+ * Models a service that provides support for a particular client key exchange
+ * mode. Currently used to implement Kerberos-related cipher suites.
+ *
+ * @since 1.9
+ */
+public interface ClientKeyExchangeService {
+
+    static class Loader {
+        private static final Map<String,ClientKeyExchangeService>
+                providers = new HashMap<>();
+
+        static {
+            final String key = "java.home";
+            String path = AccessController.doPrivileged(
+                    new GetPropertyAction(key), null,
+                    new PropertyPermission(key, "read"));
+            ServiceLoader<ClientKeyExchangeService> sc =
+                    AccessController.doPrivileged(
+                            (PrivilegedAction<ServiceLoader<ClientKeyExchangeService>>)
+                                    () -> ServiceLoader.loadInstalled(ClientKeyExchangeService.class),
+                            null,
+                            new FilePermission(new File(path, "-").toString(), "read"));
+            Iterator<ClientKeyExchangeService> iter = sc.iterator();
+            while (iter.hasNext()) {
+                ClientKeyExchangeService cs = iter.next();
+                for (String ex: cs.supported()) {
+                    providers.put(ex, cs);
+                }
+            }
+        }
+
+    }
+
+    public static ClientKeyExchangeService find(String ex) {
+        return Loader.providers.get(ex);
+    }
+
+
+    /**
+     * Returns the supported key exchange modes by this provider.
+     * @return the supported key exchange modes
+     */
+    String[] supported();
+
+    /**
+     * Returns a generalized credential object on the server side. The server
+     * side can use the info to determine if a cipher suite can be enabled.
+     * @param acc the AccessControlContext of the SSL session
+     * @return the credential object
+     */
+    Object getServiceCreds(AccessControlContext acc);
+
+    /**
+     * Returns the host name for a service principal. The info can be used in
+     * SNI or host name verifier.
+     * @param principal the principal of a service
+     * @return the string formed host name
+     */
+    String getServiceHostName(Principal principal);
+
+    /**
+     * Returns whether the specified principal is related to the current
+     * SSLSession. The info can be used to verify a SSL resume.
+     * @param isClient if true called from client side, otherwise from server
+     * @param acc the AccessControlContext of the SSL session
+     * @param p the specified principal
+     * @return true if related
+     */
+    boolean isRelated(boolean isClient, AccessControlContext acc, Principal p);
+
+    /**
+     * Creates the ClientKeyExchange object on the client side.
+     * @param serverName the intented peer name
+     * @param acc the AccessControlContext of the SSL session
+     * @param protocolVersion the TLS protocol version
+     * @param rand the SecureRandom that will used to generate the premaster
+     * @return the new Exchanger object
+     * @throws IOException if there is an error
+     */
+    ClientKeyExchange createClientExchange(String serverName, AccessControlContext acc,
+            ProtocolVersion protocolVersion, SecureRandom rand) throws IOException;
+
+    /**
+     * Create the ClientKeyExchange on the server side.
+     * @param protocolVersion the protocol version
+     * @param clientVersion the input protocol version
+     * @param rand a SecureRandom object used to generate premaster
+     *             (if the server has to create one)
+     * @param encodedTicket the ticket from client
+     * @param encrypted the encrypted premaster secret from client
+     * @param acc the AccessControlContext of the SSL session
+     * @param ServiceCreds the service side credentials object as retrived from
+     *                     {@link #getServiceCreds}
+     * @return the new Exchanger object
+     * @throws IOException if there is an error
+     */
+    ClientKeyExchange createServerExchange(
+            ProtocolVersion protocolVersion, ProtocolVersion clientVersion,
+            SecureRandom rand, byte[] encodedTicket, byte[] encrypted,
+            AccessControlContext acc, Object ServiceCreds) throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,1265 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.security.ssl;
+
+import java.io.*;
+import java.nio.*;
+import java.util.*;
+import javax.crypto.BadPaddingException;
+
+import javax.net.ssl.*;
+
+import sun.misc.HexDumpEncoder;
+import static sun.security.ssl.HandshakeMessage.*;
+
+/**
+ * DTLS {@code InputRecord} implementation for {@code SSLEngine}.
+ */
+final class DTLSInputRecord extends InputRecord implements DTLSRecord {
+
+    private DTLSReassembler reassembler = null;
+
+    // Cache the session identifier for the detection of session-resuming
+    // handshake.
+    byte[]              prevSessionID = new byte[0];
+
+    int                 readEpoch;
+
+    int                 prevReadEpoch;
+    Authenticator       prevReadAuthenticator;
+    CipherBox           prevReadCipher;
+
+    DTLSInputRecord() {
+        this.readEpoch = 0;
+        this.readAuthenticator = new MAC(true);
+
+        this.prevReadEpoch = 0;
+        this.prevReadCipher = CipherBox.NULL;
+        this.prevReadAuthenticator = new MAC(true);
+    }
+
+    @Override
+    void changeReadCiphers(Authenticator readAuthenticator,
+            CipherBox readCipher) {
+
+        prevReadCipher.dispose();
+
+        this.prevReadAuthenticator = this.readAuthenticator;
+        this.prevReadCipher = this.readCipher;
+        this.prevReadEpoch = this.readEpoch;
+
+        this.readAuthenticator = readAuthenticator;
+        this.readCipher = readCipher;
+        this.readEpoch++;
+    }
+
+    @Override
+    synchronized public void close() throws IOException {
+        if (!isClosed) {
+            prevReadCipher.dispose();
+            super.close();
+        }
+    }
+
+    @Override
+    boolean isEmpty() {
+        return ((reassembler == null) || reassembler.isEmpty());
+    }
+
+    @Override
+    int estimateFragmentSize(int packetSize) {
+        int macLen = 0;
+        if (readAuthenticator instanceof MAC) {
+            macLen = ((MAC)readAuthenticator).MAClen();
+        }
+
+        if (packetSize > 0) {
+            return readCipher.estimateFragmentSize(
+                    packetSize, macLen, headerSize);
+        } else {
+            return Record.maxDataSize;
+        }
+    }
+
+    @Override
+    void expectingFinishFlight() {
+        if (reassembler != null) {
+            reassembler.expectingFinishFlight();
+        }
+    }
+
+    @Override
+    Plaintext acquirePlaintext() {
+        if (reassembler != null) {
+            Plaintext plaintext = reassembler.acquirePlaintext();
+            if (reassembler.finished()) {
+                // discard all buffered unused message.
+                reassembler = null;
+            }
+
+            return plaintext;
+        }
+
+        return null;
+    }
+
+    @Override
+    Plaintext decode(ByteBuffer packet) {
+
+        if (isClosed) {
+            return null;
+        }
+
+        if (debug != null && Debug.isOn("packet")) {
+             Debug.printHex(
+                    "[Raw read]: length = " + packet.remaining(), packet);
+        }
+
+        // The caller should have validated the record.
+        int srcPos = packet.position();
+        int srcLim = packet.limit();
+
+        byte contentType = packet.get();                   // pos: 0
+        byte majorVersion = packet.get();                  // pos: 1
+        byte minorVersion = packet.get();                  // pos: 2
+        byte[] recordEnS = new byte[8];                    // epoch + seqence
+        packet.get(recordEnS);
+        int recordEpoch = ((recordEnS[0] & 0xFF) << 8) |
+                           (recordEnS[1] & 0xFF);          // pos: 3, 4
+        long recordSeq  = Authenticator.toLong(recordEnS);
+        int contentLen = ((packet.get() & 0xFF) << 8) |
+                          (packet.get() & 0xFF);            // pos: 11, 12
+
+        if (debug != null && Debug.isOn("record")) {
+             System.out.println(Thread.currentThread().getName() +
+                    ", READ: " +
+                    ProtocolVersion.valueOf(majorVersion, minorVersion) +
+                    " " + Record.contentName(contentType) + ", length = " +
+                    contentLen);
+        }
+
+        int recLim = srcPos + DTLSRecord.headerSize + contentLen;
+        if (this.readEpoch > recordEpoch) {
+            // Discard old records delivered before this epoch.
+
+            // Reset the position of the packet buffer.
+            packet.position(recLim);
+            return null;
+        }
+
+        if (this.readEpoch < recordEpoch) {
+            if (contentType != Record.ct_handshake) {
+                // just discard it if not a handshake message
+                packet.position(recLim);
+                return null;
+            }
+
+            // Not ready to decrypt this record, may be encrypted Finished
+            // message, need to buffer it.
+            if (reassembler == null) {
+               reassembler = new DTLSReassembler();
+            }
+
+            byte[] fragment = new byte[contentLen];
+            packet.get(fragment);              // copy the fragment
+            RecordFragment buffered = new RecordFragment(fragment, contentType,
+                    majorVersion, minorVersion,
+                    recordEnS, recordEpoch, recordSeq, true);
+
+            reassembler.queueUpFragment(buffered);
+
+            // consume the full record in the packet buffer.
+            packet.position(recLim);
+
+            Plaintext plaintext = reassembler.acquirePlaintext();
+            if (reassembler.finished()) {
+                // discard all buffered unused message.
+                reassembler = null;
+            }
+
+            return plaintext;
+        }
+
+        if (this.readEpoch == recordEpoch) {
+            // decrypt the fragment
+            packet.limit(recLim);
+            packet.position(srcPos + DTLSRecord.headerSize);
+
+            ByteBuffer plaintextFragment;
+            try {
+                plaintextFragment = decrypt(readAuthenticator,
+                        readCipher, contentType, packet, recordEnS);
+            } catch (BadPaddingException bpe) {
+                if (debug != null && Debug.isOn("ssl")) {
+                    System.out.println(Thread.currentThread().getName() +
+                            " discard invalid record: " + bpe);
+                }
+
+                // invalid, discard this record [section 4.1.2.7, RFC 6347]
+                return null;
+            } finally {
+                // comsume a complete record
+                packet.limit(srcLim);
+                packet.position(recLim);
+            }
+
+            if (contentType != Record.ct_change_cipher_spec &&
+                contentType != Record.ct_handshake) {   // app data or alert
+                                                        // no retransmission
+               return new Plaintext(contentType, majorVersion, minorVersion,
+                        recordEpoch, recordSeq, plaintextFragment);
+            }
+
+            if (contentType == Record.ct_change_cipher_spec) {
+                if (reassembler == null) {
+                    // handshake has not started, should be an
+                    // old handshake message, discard it.
+                    return null;
+                }
+
+                reassembler.queueUpFragment(
+                        new RecordFragment(plaintextFragment, contentType,
+                                majorVersion, minorVersion,
+                                recordEnS, recordEpoch, recordSeq, false));
+            } else {    // handshake record
+                // One record may contain 1+ more handshake messages.
+                while (plaintextFragment.remaining() > 0) {
+
+                    HandshakeFragment hsFrag = parseHandshakeMessage(
+                        contentType, majorVersion, minorVersion,
+                        recordEnS, recordEpoch, recordSeq, plaintextFragment);
+
+                    if (hsFrag == null) {
+                        // invalid, discard this record
+                        return null;
+                    }
+
+                    if ((reassembler == null) &&
+                            isKickstart(hsFrag.handshakeType)) {
+                       reassembler = new DTLSReassembler();
+                    }
+
+                    if (reassembler != null) {
+                        reassembler.queueUpHandshake(hsFrag);
+                    }   // else, just ignore the message.
+                }
+            }
+
+            // Completed the read of the full record. Acquire the reassembled
+            // messages.
+            if (reassembler != null) {
+                Plaintext plaintext = reassembler.acquirePlaintext();
+                if (reassembler.finished()) {
+                    // discard all buffered unused message.
+                    reassembler = null;
+                }
+
+                return plaintext;
+            }
+        }
+
+        return null;    // make the complier happy
+    }
+
+    @Override
+    int bytesInCompletePacket(ByteBuffer packet) throws SSLException {
+
+        // DTLS length field is in bytes 11/12
+        if (packet.remaining() < headerSize) {
+            return -1;
+        }
+
+        // Last sanity check that it's not a wild record
+        int pos = packet.position();
+
+        // Check the content type of the record.
+        byte contentType = packet.get(pos);
+        if (!Record.isValidContentType(contentType)) {
+            throw new SSLException(
+                    "Unrecognized SSL message, plaintext connection?");
+        }
+
+        // Check the protocol version of the record.
+        ProtocolVersion recordVersion =
+            ProtocolVersion.valueOf(packet.get(pos + 1), packet.get(pos + 2));
+        checkRecordVersion(recordVersion, false);
+
+        // Get the fragment length of the record.
+        int fragLen = ((packet.get(pos + 11) & 0xFF) << 8) +
+                       (packet.get(pos + 12) & 0xFF) + headerSize;
+        if (fragLen > Record.maxFragmentSize) {
+            throw new SSLException(
+                    "Record overflow, fragment length (" + fragLen +
+                    ") MUST not exceed " + Record.maxFragmentSize);
+        }
+
+        return fragLen;
+    }
+
+    @Override
+    void checkRecordVersion(ProtocolVersion recordVersion,
+            boolean allowSSL20Hello) throws SSLException {
+
+        if (!recordVersion.maybeDTLSProtocol()) {
+            throw new SSLException(
+                    "Unrecognized record version " + recordVersion +
+                    " , plaintext connection?");
+        }
+    }
+
+    private static boolean isKickstart(byte handshakeType) {
+        return (handshakeType == HandshakeMessage.ht_client_hello) ||
+               (handshakeType == HandshakeMessage.ht_hello_request) ||
+               (handshakeType == HandshakeMessage.ht_hello_verify_request);
+    }
+
+    private static HandshakeFragment parseHandshakeMessage(
+            byte contentType, byte majorVersion, byte minorVersion,
+            byte[] recordEnS, int recordEpoch, long recordSeq,
+            ByteBuffer plaintextFragment) {
+
+        int remaining = plaintextFragment.remaining();
+        if (remaining < handshakeHeaderSize) {
+            if (debug != null && Debug.isOn("ssl")) {
+                System.out.println(
+                        Thread.currentThread().getName() +
+                        " discard invalid record: " +
+                        "too small record to hold a handshake fragment");
+            }
+
+            // invalid, discard this record [section 4.1.2.7, RFC 6347]
+            return null;
+        }
+
+        byte handshakeType = plaintextFragment.get();       // pos: 0
+        int messageLength =
+                ((plaintextFragment.get() & 0xFF) << 16) |
+                ((plaintextFragment.get() & 0xFF) << 8) |
+                 (plaintextFragment.get() & 0xFF);          // pos: 1-3
+        int messageSeq =
+                ((plaintextFragment.get() & 0xFF) << 8) |
+                 (plaintextFragment.get() & 0xFF);          // pos: 4/5
+        int fragmentOffset =
+                ((plaintextFragment.get() & 0xFF) << 16) |
+                ((plaintextFragment.get() & 0xFF) << 8) |
+                 (plaintextFragment.get() & 0xFF);          // pos: 6-8
+        int fragmentLength =
+                ((plaintextFragment.get() & 0xFF) << 16) |
+                ((plaintextFragment.get() & 0xFF) << 8) |
+                 (plaintextFragment.get() & 0xFF);          // pos: 9-11
+        if ((remaining - handshakeHeaderSize) < fragmentLength) {
+            if (debug != null && Debug.isOn("ssl")) {
+                System.out.println(
+                        Thread.currentThread().getName() +
+                        " discard invalid record: " +
+                        "not a complete handshake fragment in the record");
+            }
+
+            // invalid, discard this record [section 4.1.2.7, RFC 6347]
+            return null;
+        }
+
+        byte[] fragment = new byte[fragmentLength];
+        plaintextFragment.get(fragment);
+
+        return new HandshakeFragment(fragment, contentType,
+                majorVersion, minorVersion,
+                recordEnS, recordEpoch, recordSeq,
+                handshakeType, messageLength,
+                messageSeq, fragmentOffset, fragmentLength);
+    }
+
+    // buffered record fragment
+    private static class RecordFragment implements Comparable<RecordFragment> {
+        boolean         isCiphertext;
+
+        byte            contentType;
+        byte            majorVersion;
+        byte            minorVersion;
+        int             recordEpoch;
+        long            recordSeq;
+        byte[]          recordEnS;
+        byte[]          fragment;
+
+        RecordFragment(ByteBuffer fragBuf, byte contentType,
+                byte majorVersion, byte minorVersion, byte[] recordEnS,
+                int recordEpoch, long recordSeq, boolean isCiphertext) {
+            this((byte[])null, contentType, majorVersion, minorVersion,
+                    recordEnS, recordEpoch, recordSeq, isCiphertext);
+
+            this.fragment = new byte[fragBuf.remaining()];
+            fragBuf.get(this.fragment);
+        }
+
+        RecordFragment(byte[] fragment, byte contentType,
+                byte majorVersion, byte minorVersion, byte[] recordEnS,
+                int recordEpoch, long recordSeq, boolean isCiphertext) {
+            this.isCiphertext = isCiphertext;
+
+            this.contentType = contentType;
+            this.majorVersion = majorVersion;
+            this.minorVersion = minorVersion;
+            this.recordEpoch = recordEpoch;
+            this.recordSeq = recordSeq;
+            this.recordEnS = recordEnS;
+            this.fragment = fragment;       // The caller should have cloned
+                                            // the buffer if necessary.
+        }
+
+        @Override
+        public int compareTo(RecordFragment o) {
+            return Long.compareUnsigned(this.recordSeq, o.recordSeq);
+        }
+    }
+
+    // buffered handshake message
+    private static final class HandshakeFragment extends RecordFragment {
+
+        byte            handshakeType;     // handshake msg_type
+        int             messageSeq;        // message_seq
+        int             messageLength;     // Handshake body length
+        int             fragmentOffset;    // fragment_offset
+        int             fragmentLength;    // fragment_length
+
+        HandshakeFragment(byte[] fragment, byte contentType,
+                byte majorVersion, byte minorVersion, byte[] recordEnS,
+                int recordEpoch, long recordSeq,
+                byte handshakeType, int messageLength,
+                int messageSeq, int fragmentOffset, int fragmentLength) {
+
+            super(fragment, contentType, majorVersion, minorVersion,
+                    recordEnS, recordEpoch , recordSeq, false);
+
+            this.handshakeType = handshakeType;
+            this.messageSeq = messageSeq;
+            this.messageLength = messageLength;
+            this.fragmentOffset = fragmentOffset;
+            this.fragmentLength = fragmentLength;
+        }
+
+        @Override
+        public int compareTo(RecordFragment o) {
+            if (o instanceof HandshakeFragment) {
+                HandshakeFragment other = (HandshakeFragment)o;
+                if (this.messageSeq != other.messageSeq) {
+                    // keep the insertion order for the same message
+                    return this.messageSeq - other.messageSeq;
+                }
+            }
+
+            return Long.compareUnsigned(this.recordSeq, o.recordSeq);
+        }
+    }
+
+    private static final class HoleDescriptor {
+        int offset;             // fragment_offset
+        int limit;              // fragment_offset + fragment_length
+
+        HoleDescriptor(int offset, int limit) {
+            this.offset = offset;
+            this.limit = limit;
+        }
+    }
+
+    final class DTLSReassembler {
+        TreeSet<RecordFragment> bufferedFragments = new TreeSet<>();
+
+        HashMap<Byte, List<HoleDescriptor>> holesMap = new HashMap<>(5);
+
+        // Epoch, sequence number and handshake message sequence of the
+        // beginning message of a flight.
+        byte        flightType = (byte)0xFF;
+
+        int         flightTopEpoch = 0;
+        long        flightTopRecordSeq = -1;
+        int         flightTopMessageSeq = 0;
+
+        // Epoch, sequence number and handshake message sequence of the
+        // next message acquisition of a flight.
+        int         nextRecordEpoch = 0;    // next record epoch
+        long        nextRecordSeq = 0;      // next record sequence number
+        int         nextMessageSeq = 0;     // next handshake message number
+
+        // Expect ChangeCipherSpec and Finished messages for the final flight.
+        boolean     expectCCSFlight = false;
+
+        // Ready to process this flight if received all messages of the flight.
+        boolean     flightIsReady = false;
+        boolean     needToCheckFlight = false;
+
+        // Is it a session-resuming abbreviated handshake.?
+        boolean     isAbbreviatedHandshake = false;
+
+        // The handshke fragment with the biggest record sequence number
+        // in a flight, not counting the Finished message.
+        HandshakeFragment lastHandshakeFragment = null;
+
+        // Is handshake (intput) finished?
+        boolean handshakeFinished = false;
+
+        DTLSReassembler() {
+            // blank
+        }
+
+        boolean finished() {
+            return handshakeFinished;
+        }
+
+        void expectingFinishFlight() {
+            expectCCSFlight = true;
+        }
+
+        void queueUpHandshake(HandshakeFragment hsf) {
+
+            if ((nextRecordEpoch > hsf.recordEpoch) ||
+                    (nextRecordSeq > hsf.recordSeq) ||
+                    (nextMessageSeq > hsf.messageSeq)) {
+                // too old, discard this record
+                return;
+            }
+
+            // Is it the first message of next flight?
+            if ((flightTopMessageSeq == hsf.messageSeq) &&
+                    (hsf.fragmentOffset == 0) && (flightTopRecordSeq == -1)) {
+
+                flightType = hsf.handshakeType;
+                flightTopEpoch = hsf.recordEpoch;
+                flightTopRecordSeq = hsf.recordSeq;
+
+                if (hsf.handshakeType == HandshakeMessage.ht_server_hello) {
+                    // Is it a session-resuming handshake?
+                    try {
+                        isAbbreviatedHandshake =
+                                isSessionResuming(hsf.fragment, prevSessionID);
+                    } catch (SSLException ssle) {
+                        if (debug != null && Debug.isOn("ssl")) {
+                            System.out.println(
+                                    Thread.currentThread().getName() +
+                                    " discard invalid record: " + ssle);
+                        }
+
+                        // invalid, discard it [section 4.1.2.7, RFC 6347]
+                        return;
+                    }
+
+                    if (!isAbbreviatedHandshake) {
+                        prevSessionID = getSessionID(hsf.fragment);
+                    }
+                }
+            }
+
+            boolean fragmented = false;
+            if ((hsf.fragmentOffset) != 0 ||
+                (hsf.fragmentLength != hsf.messageLength)) {
+
+                fragmented = true;
+            }
+
+            List<HoleDescriptor> holes = holesMap.get(hsf.handshakeType);
+            if (holes == null) {
+                if (!fragmented) {
+                    holes = Collections.emptyList();
+                } else {
+                    holes = new LinkedList<HoleDescriptor>();
+                    holes.add(new HoleDescriptor(0, hsf.messageLength));
+                }
+                holesMap.put(hsf.handshakeType, holes);
+            } else if (holes.isEmpty()) {
+                // Have got the full handshake message.  This record may be
+                // a handshake message retransmission.  Discard this record.
+                //
+                // It's OK to discard retransmission as the handshake hash
+                // is computed as if each handshake message had been sent
+                // as a single fragment.
+                //
+                // Note that ClientHello messages are delivered twice in
+                // DTLS handshaking.
+                if ((hsf.handshakeType != HandshakeMessage.ht_client_hello &&
+                     hsf.handshakeType != ht_hello_verify_request) ||
+                        (nextMessageSeq != hsf.messageSeq)) {
+                    return;
+                }
+
+                if (fragmented) {
+                    holes = new LinkedList<HoleDescriptor>();
+                    holes.add(new HoleDescriptor(0, hsf.messageLength));
+                }
+                holesMap.put(hsf.handshakeType, holes);
+            }
+
+            if (fragmented) {
+                int fragmentLimit = hsf.fragmentOffset + hsf.fragmentLength;
+                for (int i = 0; i < holes.size(); i++) {
+
+                    HoleDescriptor hole = holes.get(i);
+                    if ((hole.limit <= hsf.fragmentOffset) ||
+                        (hole.offset >= fragmentLimit)) {
+                        // Also discard overlapping handshake retransmissions.
+                        continue;
+                    }
+
+                    // The ranges SHOULD NOT overlap.
+                    if (((hole.offset > hsf.fragmentOffset) &&
+                         (hole.offset < fragmentLimit)) ||
+                        ((hole.limit > hsf.fragmentOffset) &&
+                         (hole.limit < fragmentLimit))) {
+
+                        if (debug != null && Debug.isOn("ssl")) {
+                            System.out.println(
+                                Thread.currentThread().getName() +
+                                " discard invalid record: " +
+                                "handshake fragment ranges are overlapping");
+                        }
+
+                        // invalid, discard it [section 4.1.2.7, RFC 6347]
+                        return;
+                    }
+
+                    // This record interacts with this hole, fill the hole.
+                    holes.remove(i);
+                    // i--;
+
+                    if (hsf.fragmentOffset > hole.offset) {
+                        holes.add(new HoleDescriptor(
+                                hole.offset, hsf.fragmentOffset));
+                        // i++;
+                    }
+
+                    if (fragmentLimit < hole.limit) {
+                        holes.add(new HoleDescriptor(
+                                fragmentLimit, hole.limit));
+                        // i++;
+                    }
+
+                    // As no ranges overlap, no interact with other holes.
+                    break;
+                }
+            }
+
+            // append this fragment
+            bufferedFragments.add(hsf);
+
+            if ((lastHandshakeFragment == null) ||
+                (lastHandshakeFragment.compareTo(hsf) < 0)) {
+
+                lastHandshakeFragment = hsf;
+            }
+
+            if (flightIsReady) {
+                flightIsReady = false;
+            }
+            needToCheckFlight = true;
+        }
+
+        // queue up change_cipher_spec or encrypted message
+        void queueUpFragment(RecordFragment rf) {
+            if ((nextRecordEpoch > rf.recordEpoch) ||
+                    (nextRecordSeq > rf.recordSeq)) {
+                // too old, discard this record
+                return;
+            }
+
+            // Is it the first message of next flight?
+            if (expectCCSFlight &&
+                    (rf.contentType == Record.ct_change_cipher_spec)) {
+
+                flightType = (byte)0xFE;
+                flightTopEpoch = rf.recordEpoch;
+                flightTopRecordSeq = rf.recordSeq;
+            }
+
+            // append this fragment
+            bufferedFragments.add(rf);
+
+            if (flightIsReady) {
+                flightIsReady = false;
+            }
+            needToCheckFlight = true;
+        }
+
+        boolean isEmpty() {
+            return (bufferedFragments.isEmpty() ||
+                    (!flightIsReady && !needToCheckFlight) ||
+                    (needToCheckFlight && !flightIsReady()));
+        }
+
+        Plaintext acquirePlaintext() {
+            if (bufferedFragments.isEmpty()) {
+                // reset the flight
+                if (flightIsReady) {
+                    flightIsReady = false;
+                    needToCheckFlight = false;
+                }
+
+                return null;
+            }
+
+            if (!flightIsReady && needToCheckFlight) {
+                // check the fligth status
+                flightIsReady = flightIsReady();
+
+                // set for next flight
+                if (flightIsReady) {
+                    flightTopMessageSeq = lastHandshakeFragment.messageSeq + 1;
+                    flightTopRecordSeq = -1;
+                }
+
+                needToCheckFlight = false;
+            }
+
+            if (!flightIsReady) {
+                return null;
+            }
+
+            RecordFragment rFrag = bufferedFragments.first();
+            if (!rFrag.isCiphertext) {
+                // handshake message, or ChangeCipherSpec message
+                return acquireHandshakeMessage();
+            } else {
+                // a Finished message or other ciphertexts
+                return acquireCachedMessage();
+            }
+        }
+
+        private Plaintext acquireCachedMessage() {
+
+            RecordFragment rFrag = bufferedFragments.first();
+            if (readEpoch != rFrag.recordEpoch) {
+                if (readEpoch > rFrag.recordEpoch) {
+                    // discard old records
+                    bufferedFragments.remove(rFrag);    // popup the fragment
+                }
+
+                // reset the flight
+                if (flightIsReady) {
+                    flightIsReady = false;
+                }
+                return null;
+            }
+
+            bufferedFragments.remove(rFrag);    // popup the fragment
+
+            ByteBuffer fragment = ByteBuffer.wrap(rFrag.fragment);
+            ByteBuffer plaintextFragment = null;
+            try {
+                plaintextFragment = decrypt(readAuthenticator, readCipher,
+                        rFrag.contentType, fragment, rFrag.recordEnS);
+            } catch (BadPaddingException bpe) {
+                if (debug != null && Debug.isOn("ssl")) {
+                    System.out.println(Thread.currentThread().getName() +
+                            " discard invalid record: " + bpe);
+                }
+
+                // invalid, discard this record [section 4.1.2.7, RFC 6347]
+                return null;
+            }
+
+            // The ciphtext handshake message can only be Finished (the
+            // end of this flight), ClinetHello or HelloRequest (the
+            // beginning of the next flight) message.  Need not to check
+            // any ChangeCipherSpec message.
+            if (rFrag.contentType == Record.ct_handshake) {
+                HandshakeFragment finFrag = null;
+                while (plaintextFragment.remaining() > 0) {
+                    HandshakeFragment hsFrag = parseHandshakeMessage(
+                            rFrag.contentType,
+                            rFrag.majorVersion, rFrag.minorVersion,
+                            rFrag.recordEnS, rFrag.recordEpoch, rFrag.recordSeq,
+                            plaintextFragment);
+
+                    if (hsFrag == null) {
+                        // invalid, discard this record
+                        return null;
+                    }
+
+                    if (hsFrag.handshakeType == HandshakeMessage.ht_finished) {
+                        finFrag = hsFrag;
+
+                        // reset for the next flight
+                        this.flightType = (byte)0xFF;
+                        this.flightTopEpoch = rFrag.recordEpoch;
+                        this.flightTopMessageSeq = hsFrag.messageSeq + 1;
+                        this.flightTopRecordSeq = -1;
+                    } else {
+                        // reset the flight
+                        if (flightIsReady) {
+                            flightIsReady = false;
+                        }
+                        queueUpHandshake(hsFrag);
+                    }
+                }
+
+                this.nextRecordSeq = rFrag.recordSeq + 1;
+                this.nextMessageSeq = 0;
+
+                if (finFrag != null) {
+                    this.nextRecordEpoch = finFrag.recordEpoch;
+                    this.nextRecordSeq = finFrag.recordSeq + 1;
+                    this.nextMessageSeq = finFrag.messageSeq + 1;
+
+                    // Finished message does not fragment.
+                    byte[] recordFrag = new byte[finFrag.messageLength + 4];
+                    Plaintext plaintext = new Plaintext(finFrag.contentType,
+                            finFrag.majorVersion, finFrag.minorVersion,
+                            finFrag.recordEpoch, finFrag.recordSeq,
+                            ByteBuffer.wrap(recordFrag));
+
+                    // fill the handshake fragment of the record
+                    recordFrag[0] = finFrag.handshakeType;
+                    recordFrag[1] =
+                            (byte)((finFrag.messageLength >>> 16) & 0xFF);
+                    recordFrag[2] =
+                            (byte)((finFrag.messageLength >>> 8) & 0xFF);
+                    recordFrag[3] = (byte)(finFrag.messageLength & 0xFF);
+
+                    System.arraycopy(finFrag.fragment, 0,
+                            recordFrag, 4, finFrag.fragmentLength);
+
+                    // handshake hashing
+                    handshakeHashing(finFrag, plaintext);
+
+                    // input handshake finished
+                    handshakeFinished = true;
+
+                    return plaintext;
+                } else {
+                    return acquirePlaintext();
+                }
+            } else {
+                return new Plaintext(rFrag.contentType,
+                        rFrag.majorVersion, rFrag.minorVersion,
+                        rFrag.recordEpoch, rFrag.recordSeq,
+                        plaintextFragment);
+            }
+        }
+
+        private Plaintext acquireHandshakeMessage() {
+
+            RecordFragment rFrag = bufferedFragments.first();
+            if (rFrag.contentType == Record.ct_change_cipher_spec) {
+                this.nextRecordEpoch = rFrag.recordEpoch + 1;
+                this.nextRecordSeq = 0;
+                // no change on next handshake message sequence number
+
+                bufferedFragments.remove(rFrag);        // popup the fragment
+
+                // Reload if this message has been reserved for handshake hash.
+                handshakeHash.reload();
+
+                return new Plaintext(rFrag.contentType,
+                        rFrag.majorVersion, rFrag.minorVersion,
+                        rFrag.recordEpoch, rFrag.recordSeq,
+                        ByteBuffer.wrap(rFrag.fragment));
+            } else {    // rFrag.contentType == Record.ct_handshake
+                HandshakeFragment hsFrag = (HandshakeFragment)rFrag;
+                if ((hsFrag.messageLength == hsFrag.fragmentLength) &&
+                    (hsFrag.fragmentOffset == 0)) {     // no fragmentation
+
+                    bufferedFragments.remove(rFrag);    // popup the fragment
+
+                    // this.nextRecordEpoch = hsFrag.recordEpoch;
+                    this.nextRecordSeq = hsFrag.recordSeq + 1;
+                    this.nextMessageSeq = hsFrag.messageSeq + 1;
+
+                    // Note: may try to avoid byte array copy in the future.
+                    byte[] recordFrag = new byte[hsFrag.messageLength + 4];
+                    Plaintext plaintext = new Plaintext(hsFrag.contentType,
+                            hsFrag.majorVersion, hsFrag.minorVersion,
+                            hsFrag.recordEpoch, hsFrag.recordSeq,
+                            ByteBuffer.wrap(recordFrag));
+
+                    // fill the handshake fragment of the record
+                    recordFrag[0] = hsFrag.handshakeType;
+                    recordFrag[1] =
+                            (byte)((hsFrag.messageLength >>> 16) & 0xFF);
+                    recordFrag[2] =
+                            (byte)((hsFrag.messageLength >>> 8) & 0xFF);
+                    recordFrag[3] = (byte)(hsFrag.messageLength & 0xFF);
+
+                    System.arraycopy(hsFrag.fragment, 0,
+                            recordFrag, 4, hsFrag.fragmentLength);
+
+                    // handshake hashing
+                    handshakeHashing(hsFrag, plaintext);
+
+                    return plaintext;
+                } else {                // fragmented handshake message
+                    // the first record
+                    //
+                    // Note: may try to avoid byte array copy in the future.
+                    byte[] recordFrag = new byte[hsFrag.messageLength + 4];
+                    Plaintext plaintext = new Plaintext(hsFrag.contentType,
+                            hsFrag.majorVersion, hsFrag.minorVersion,
+                            hsFrag.recordEpoch, hsFrag.recordSeq,
+                            ByteBuffer.wrap(recordFrag));
+
+                    // fill the handshake fragment of the record
+                    recordFrag[0] = hsFrag.handshakeType;
+                    recordFrag[1] =
+                            (byte)((hsFrag.messageLength >>> 16) & 0xFF);
+                    recordFrag[2] =
+                            (byte)((hsFrag.messageLength >>> 8) & 0xFF);
+                    recordFrag[3] = (byte)(hsFrag.messageLength & 0xFF);
+
+                    int msgSeq = hsFrag.messageSeq;
+                    long maxRecodeSN = hsFrag.recordSeq;
+                    HandshakeFragment hmFrag = hsFrag;
+                    do {
+                        System.arraycopy(hmFrag.fragment, 0,
+                                recordFrag, hmFrag.fragmentOffset + 4,
+                                hmFrag.fragmentLength);
+                        // popup the fragment
+                        bufferedFragments.remove(rFrag);
+
+                        if (maxRecodeSN < hmFrag.recordSeq) {
+                            maxRecodeSN = hmFrag.recordSeq;
+                        }
+
+                        // Note: may buffer retransmitted fragments in order to
+                        // speed up the reassembly in the future.
+
+                        // read the next buffered record
+                        if (!bufferedFragments.isEmpty()) {
+                            rFrag = bufferedFragments.first();
+                            if (rFrag.contentType != Record.ct_handshake) {
+                                break;
+                            } else {
+                                hmFrag = (HandshakeFragment)rFrag;
+                            }
+                        }
+                    } while (!bufferedFragments.isEmpty() &&
+                            (msgSeq == hmFrag.messageSeq));
+
+                    // handshake hashing
+                    handshakeHashing(hsFrag, plaintext);
+
+                    this.nextRecordSeq = maxRecodeSN + 1;
+                    this.nextMessageSeq = msgSeq + 1;
+
+                    return plaintext;
+                }
+            }
+        }
+
+        boolean flightIsReady() {
+
+            //
+            // the ChangeCipherSpec/Finished flight
+            //
+            if (expectCCSFlight) {
+                // Have the ChangeCipherSpec/Finished messages been received?
+                return hasFinisedMessage(bufferedFragments);
+            }
+
+            if (flightType == (byte)0xFF) {
+                return false;
+            }
+
+            if ((flightType == HandshakeMessage.ht_client_hello) ||
+                (flightType == HandshakeMessage.ht_hello_request) ||
+                (flightType == HandshakeMessage.ht_hello_verify_request)) {
+
+                // single handshake message flight
+                return hasCompleted(holesMap.get(flightType));
+            }
+
+            //
+            // the ServerHello flight
+            //
+            if (flightType == HandshakeMessage.ht_server_hello) {
+                // Firstly, check the first flight handshake message.
+                if (!hasCompleted(holesMap.get(flightType))) {
+                    return false;
+                }
+
+                //
+                // an abbreviated handshake
+                //
+                if (isAbbreviatedHandshake) {
+                    // Ready to use the flight if received the
+                    // ChangeCipherSpec and Finished messages.
+                    return hasFinisedMessage(bufferedFragments);
+                }
+
+                //
+                // a full handshake
+                //
+                if (lastHandshakeFragment.handshakeType !=
+                        HandshakeMessage.ht_server_hello_done) {
+                    // Not yet got the final message of the flight.
+                    return false;
+                }
+
+                // Have all handshake message been received?
+                return hasCompleted(bufferedFragments,
+                    flightTopMessageSeq, lastHandshakeFragment.messageSeq);
+            }
+
+            //
+            // the ClientKeyExchange flight
+            //
+            // Note: need to consider more messages in this flight if
+            //       ht_supplemental_data and ht_certificate_url are
+            //       suppported in the future.
+            //
+            if ((flightType == HandshakeMessage.ht_certificate) ||
+                (flightType == HandshakeMessage.ht_client_key_exchange)) {
+
+                // Firstly, check the first flight handshake message.
+                if (!hasCompleted(holesMap.get(flightType))) {
+                    return false;
+                }
+
+                if (!hasFinisedMessage(bufferedFragments)) {
+                    // not yet got the ChangeCipherSpec/Finished messages
+                    return false;
+                }
+
+                if (flightType == HandshakeMessage.ht_client_key_exchange) {
+                    // single handshake message flight
+                    return true;
+                }
+
+                //
+                // flightType == HandshakeMessage.ht_certificate
+                //
+                // We don't support certificates containing fixed
+                // Diffie-Hellman parameters.  Therefore, CertificateVerify
+                // message is required if client Certificate message presents.
+                //
+                if (lastHandshakeFragment.handshakeType !=
+                        HandshakeMessage.ht_certificate_verify) {
+                    // Not yet got the final message of the flight.
+                    return false;
+                }
+
+                // Have all handshake message been received?
+                return hasCompleted(bufferedFragments,
+                    flightTopMessageSeq, lastHandshakeFragment.messageSeq);
+            }
+
+            //
+            // Otherwise, need to receive more handshake messages.
+            //
+            return false;
+        }
+
+        private boolean isSessionResuming(
+                byte[] fragment, byte[] prevSid) throws SSLException {
+
+            // As the first fragment of ServerHello should be big enough
+            // to hold the session_id field, need not to worry about the
+            // fragmentation here.
+            if ((fragment == null) || (fragment.length < 38)) {
+                                    // 38: the minimal ServerHello body length
+                throw new SSLException(
+                        "Invalid ServerHello message: no sufficient data");
+            }
+
+            int sidLen = fragment[34];          // 34: the length field
+            if (sidLen > 32) {                  // opaque SessionID<0..32>
+                throw new SSLException(
+                        "Invalid ServerHello message: invalid session id");
+            }
+
+            if (fragment.length < 38 + sidLen) {
+                throw new SSLException(
+                        "Invalid ServerHello message: no sufficient data");
+            }
+
+            if (sidLen != 0 && (prevSid.length == sidLen)) {
+                // may be a session-resuming handshake
+                for (int i = 0; i < sidLen; i++) {
+                    if (prevSid[i] != fragment[35 + i]) {
+                                                // 35: the session identifier
+                        return false;
+                    }
+                }
+
+                return true;
+            }
+
+            return false;
+        }
+
+        private byte[] getSessionID(byte[] fragment) {
+            // The validity has been checked in the call to isSessionResuming().
+            int sidLen = fragment[34];      // 34: the sessionID length field
+
+            byte[] temporary = new byte[sidLen];
+            System.arraycopy(fragment, 35, temporary, 0, sidLen);
+
+            return temporary;
+        }
+
+        // Looking for the ChangeCipherSpec and Finished messages.
+        //
+        // As the cached Finished message should be a ciphertext, we don't
+        // exactly know a ciphertext is a Finished message or not.  According
+        // to the spec of TLS/DTLS handshaking, a Finished message is always
+        // sent immediately after a ChangeCipherSpec message.  The first
+        // ciphertext handshake message should be the expected Finished message.
+        private boolean hasFinisedMessage(
+                Set<RecordFragment> fragments) {
+
+            boolean hasCCS = false;
+            boolean hasFin = false;
+            for (RecordFragment fragment : fragments) {
+                if (fragment.contentType == Record.ct_change_cipher_spec) {
+                    if (hasFin) {
+                        return true;
+                    }
+                    hasCCS = true;
+                } else if (fragment.contentType == Record.ct_handshake) {
+                    // Finished is the first expected message of a new epoch.
+                    if (fragment.isCiphertext) {
+                        if (hasCCS) {
+                            return true;
+                        }
+                        hasFin = true;
+                    }
+                }
+            }
+
+            return hasFin && hasCCS;
+        }
+
+        private boolean hasCompleted(List<HoleDescriptor> holes) {
+            if (holes == null) {
+                // not yet received this kind of handshake message
+                return false;
+            }
+
+            return holes.isEmpty();  // no fragment hole for complete message
+        }
+
+        private boolean hasCompleted(
+                Set<RecordFragment> fragments,
+                int presentMsgSeq, int endMsgSeq) {
+
+            // The caller should have checked the completion of the first
+            // present handshake message.  Need not to check it again.
+            for (RecordFragment rFrag : fragments) {
+                if ((rFrag.contentType != Record.ct_handshake) ||
+                        rFrag.isCiphertext) {
+                    break;
+                }
+
+                HandshakeFragment hsFrag = (HandshakeFragment)rFrag;
+                if (hsFrag.messageSeq == presentMsgSeq) {
+                    continue;
+                } else if (hsFrag.messageSeq == (presentMsgSeq + 1)) {
+                    // check the completion of the handshake message
+                    if (!hasCompleted(holesMap.get(hsFrag.handshakeType))) {
+                        return false;
+                    }
+
+                    presentMsgSeq = hsFrag.messageSeq;
+                } else {
+                    // not yet got handshake message next to presentMsgSeq
+                    break;
+                }
+            }
+
+            return (presentMsgSeq >= endMsgSeq);
+                        // false: if not yet got all messages of the flight.
+        }
+
+        private void handshakeHashing(
+                HandshakeFragment hsFrag, Plaintext plaintext) {
+
+            byte hsType = hsFrag.handshakeType;
+            if ((hsType == HandshakeMessage.ht_hello_request) ||
+                (hsType == HandshakeMessage.ht_hello_verify_request)) {
+
+                // omitted from handshake hash computation
+                return;
+            }
+
+            if ((hsFrag.messageSeq == 0) &&
+                (hsType == HandshakeMessage.ht_client_hello)) {
+
+                // omit initial ClientHello message
+                //
+                //  4: handshake header
+                //  2: ClientHello.client_version
+                // 32: ClientHello.random
+                int sidLen = plaintext.fragment.get(38);
+
+                if (sidLen == 0) {      // empty session_id, initial handshake
+                    return;
+                }
+            }
+
+            // calculate the DTLS header
+            byte[] temporary = new byte[12];    // 12: handshake header size
+
+            // Handshake.msg_type
+            temporary[0] = hsFrag.handshakeType;
+
+            // Handshake.length
+            temporary[1] = (byte)((hsFrag.messageLength >> 16) & 0xFF);
+            temporary[2] = (byte)((hsFrag.messageLength >> 8) & 0xFF);
+            temporary[3] = (byte)(hsFrag.messageLength & 0xFF);
+
+            // Handshake.message_seq
+            temporary[4] = (byte)((hsFrag.messageSeq >> 8) & 0xFF);
+            temporary[5] = (byte)(hsFrag.messageSeq & 0xFF);
+
+            // Handshake.fragment_offset
+            temporary[6] = 0;
+            temporary[7] = 0;
+            temporary[8] = 0;
+
+            // Handshake.fragment_length
+            temporary[9] = temporary[1];
+            temporary[10] = temporary[2];
+            temporary[11] = temporary[3];
+
+            plaintext.fragment.position(4);     // ignore the TLS header
+            if ((hsType != HandshakeMessage.ht_finished) &&
+                (hsType != HandshakeMessage.ht_certificate_verify)) {
+
+                if (handshakeHash == null) {
+                    // used for cache only
+                    handshakeHash = new HandshakeHash(false);
+                }
+                handshakeHash.update(temporary, 0, 12);
+                handshakeHash.update(plaintext.fragment);
+            } else {
+                // Reserve until this handshake message has been processed.
+                if (handshakeHash == null) {
+                    // used for cache only
+                    handshakeHash = new HandshakeHash(false);
+                }
+                handshakeHash.reserve(temporary, 0, 12);
+                handshakeHash.reserve(plaintext.fragment);
+            }
+            plaintext.fragment.position(0);     // restore the position
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,597 @@
+/*
+ * Copyright (c) 1996, 2014, 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.security.ssl;
+
+import java.io.*;
+import java.nio.*;
+import java.util.*;
+
+import javax.crypto.BadPaddingException;
+
+import javax.net.ssl.*;
+
+import sun.misc.HexDumpEncoder;
+import static sun.security.ssl.Ciphertext.RecordType;
+
+/**
+ * DTLS {@code OutputRecord} implementation for {@code SSLEngine}.
+ */
+final class DTLSOutputRecord extends OutputRecord implements DTLSRecord {
+
+    private DTLSFragmenter fragmenter = null;
+
+    int                 writeEpoch;
+
+    int                 prevWriteEpoch;
+    Authenticator       prevWriteAuthenticator;
+    CipherBox           prevWriteCipher;
+
+    private LinkedList<RecordMemo> alertMemos = new LinkedList<>();
+
+    DTLSOutputRecord() {
+        this.writeAuthenticator = new MAC(true);
+
+        this.writeEpoch = 0;
+        this.prevWriteEpoch = 0;
+        this.prevWriteCipher = CipherBox.NULL;
+        this.prevWriteAuthenticator = new MAC(true);
+
+        this.packetSize = DTLSRecord.maxRecordSize;
+        this.protocolVersion = ProtocolVersion.DEFAULT_DTLS;
+    }
+
+    @Override
+    void changeWriteCiphers(Authenticator writeAuthenticator,
+            CipherBox writeCipher) throws IOException {
+
+        encodeChangeCipherSpec();
+
+        prevWriteCipher.dispose();
+
+        this.prevWriteAuthenticator = this.writeAuthenticator;
+        this.prevWriteCipher = this.writeCipher;
+        this.prevWriteEpoch = this.writeEpoch;
+
+        this.writeAuthenticator = writeAuthenticator;
+        this.writeCipher = writeCipher;
+        this.writeEpoch++;
+
+        this.isFirstAppOutputRecord = true;
+
+        // set the epoch number
+        this.writeAuthenticator.setEpochNumber(this.writeEpoch);
+    }
+
+    @Override
+    void encodeAlert(byte level, byte description) throws IOException {
+        RecordMemo memo = new RecordMemo();
+
+        memo.contentType = Record.ct_alert;
+        memo.majorVersion = protocolVersion.major;
+        memo.minorVersion = protocolVersion.minor;
+        memo.encodeEpoch = writeEpoch;
+        memo.encodeCipher = writeCipher;
+        memo.encodeAuthenticator = writeAuthenticator;
+
+        memo.fragment = new byte[2];
+        memo.fragment[0] = level;
+        memo.fragment[1] = description;
+
+        alertMemos.add(memo);
+    }
+
+    @Override
+    void encodeChangeCipherSpec() throws IOException {
+        if (fragmenter == null) {
+           fragmenter = new DTLSFragmenter();
+        }
+        fragmenter.queueUpChangeCipherSpec();
+    }
+
+    @Override
+    void encodeHandshake(byte[] source,
+            int offset, int length) throws IOException {
+
+        if (firstMessage) {
+            firstMessage = false;
+        }
+
+        if (fragmenter == null) {
+           fragmenter = new DTLSFragmenter();
+        }
+
+        fragmenter.queueUpHandshake(source, offset, length);
+    }
+
+    @Override
+    Ciphertext encode(ByteBuffer[] sources, int offset, int length,
+            ByteBuffer destination) throws IOException {
+
+        if (writeAuthenticator.seqNumOverflow()) {
+            if (debug != null && Debug.isOn("ssl")) {
+                System.out.println(Thread.currentThread().getName() +
+                    ", sequence number extremely close to overflow " +
+                    "(2^64-1 packets). Closing connection.");
+            }
+
+            throw new SSLHandshakeException("sequence number overflow");
+        }
+
+        // not apply to handshake message
+        int macLen = 0;
+        if (writeAuthenticator instanceof MAC) {
+            macLen = ((MAC)writeAuthenticator).MAClen();
+        }
+
+        int fragLen;
+        if (packetSize > 0) {
+            fragLen = Math.min(maxRecordSize, packetSize);
+            fragLen = writeCipher.calculateFragmentSize(
+                    fragLen, macLen, headerSize);
+
+            fragLen = Math.min(fragLen, Record.maxDataSize);
+        } else {
+            fragLen = Record.maxDataSize;
+        }
+
+        if (fragmentSize > 0) {
+            fragLen = Math.min(fragLen, fragmentSize);
+        }
+
+        int dstPos = destination.position();
+        int dstLim = destination.limit();
+        int dstContent = dstPos + headerSize +
+                                writeCipher.getExplicitNonceSize();
+        destination.position(dstContent);
+
+        int remains = Math.min(fragLen, destination.remaining());
+        fragLen = 0;
+        int srcsLen = offset + length;
+        for (int i = offset; (i < srcsLen) && (remains > 0); i++) {
+            int amount = Math.min(sources[i].remaining(), remains);
+            int srcLimit = sources[i].limit();
+            sources[i].limit(sources[i].position() + amount);
+            destination.put(sources[i]);
+            sources[i].limit(srcLimit);         // restore the limit
+            remains -= amount;
+            fragLen += amount;
+        }
+
+        destination.limit(destination.position());
+        destination.position(dstContent);
+
+        if ((debug != null) && Debug.isOn("record")) {
+            System.out.println(Thread.currentThread().getName() +
+                    ", WRITE: " + protocolVersion + " " +
+                    Record.contentName(Record.ct_application_data) +
+                    ", length = " + destination.remaining());
+        }
+
+        // Encrypt the fragment and wrap up a record.
+        long recordSN = encrypt(writeAuthenticator, writeCipher,
+                Record.ct_application_data, destination,
+                dstPos, dstLim, headerSize,
+                protocolVersion, true);
+
+        if ((debug != null) && Debug.isOn("packet")) {
+            ByteBuffer temporary = destination.duplicate();
+            temporary.limit(temporary.position());
+            temporary.position(dstPos);
+            Debug.printHex(
+                    "[Raw write]: length = " + temporary.remaining(),
+                    temporary);
+        }
+
+        // remain the limit unchanged
+        destination.limit(dstLim);
+
+        return new Ciphertext(RecordType.RECORD_APPLICATION_DATA, recordSN);
+    }
+
+    @Override
+    Ciphertext acquireCiphertext(ByteBuffer destination) throws IOException {
+        if (alertMemos != null && !alertMemos.isEmpty()) {
+            RecordMemo memo = alertMemos.pop();
+
+            int macLen = 0;
+            if (memo.encodeAuthenticator instanceof MAC) {
+                macLen = ((MAC)memo.encodeAuthenticator).MAClen();
+            }
+
+            int dstPos = destination.position();
+            int dstLim = destination.limit();
+            int dstContent = dstPos + headerSize +
+                                writeCipher.getExplicitNonceSize();
+            destination.position(dstContent);
+
+            destination.put(memo.fragment);
+
+            destination.limit(destination.position());
+            destination.position(dstContent);
+
+            if ((debug != null) && Debug.isOn("record")) {
+                System.out.println(Thread.currentThread().getName() +
+                        ", WRITE: " + protocolVersion + " " +
+                        Record.contentName(Record.ct_alert) +
+                        ", length = " + destination.remaining());
+            }
+
+            // Encrypt the fragment and wrap up a record.
+            long recordSN = encrypt(memo.encodeAuthenticator, memo.encodeCipher,
+                    Record.ct_alert, destination, dstPos, dstLim, headerSize,
+                    ProtocolVersion.valueOf(memo.majorVersion,
+                            memo.minorVersion), true);
+
+            if ((debug != null) && Debug.isOn("packet")) {
+                ByteBuffer temporary = destination.duplicate();
+                temporary.limit(temporary.position());
+                temporary.position(dstPos);
+                Debug.printHex(
+                        "[Raw write]: length = " + temporary.remaining(),
+                        temporary);
+            }
+
+            // remain the limit unchanged
+            destination.limit(dstLim);
+
+            return new Ciphertext(RecordType.RECORD_ALERT, recordSN);
+        }
+
+        if (fragmenter != null) {
+            return fragmenter.acquireCiphertext(destination);
+        }
+
+        return null;
+    }
+
+    @Override
+    boolean isEmpty() {
+        return ((fragmenter == null) || fragmenter.isEmpty()) &&
+               ((alertMemos == null) || alertMemos.isEmpty());
+    }
+
+    @Override
+    void initHandshaker() {
+        // clean up
+        fragmenter = null;
+    }
+
+    // buffered record fragment
+    private static class RecordMemo {
+        byte            contentType;
+        byte            majorVersion;
+        byte            minorVersion;
+        int             encodeEpoch;
+        CipherBox       encodeCipher;
+        Authenticator   encodeAuthenticator;
+
+        byte[]          fragment;
+    }
+
+    private static class HandshakeMemo extends RecordMemo {
+        byte            handshakeType;
+        int             messageSequence;
+        int             acquireOffset;
+    }
+
+    private final class DTLSFragmenter {
+        private LinkedList<RecordMemo> handshakeMemos = new LinkedList<>();
+        private int acquireIndex = 0;
+        private int messageSequence = 0;
+        private boolean flightIsReady = false;
+
+        // Per section 4.1.1, RFC 6347:
+        //
+        // If repeated retransmissions do not result in a response, and the
+        // PMTU is unknown, subsequent retransmissions SHOULD back off to a
+        // smaller record size, fragmenting the handshake message as
+        // appropriate.
+        //
+        // In this implementation, two times of retransmits would be attempted
+        // before backing off.  The back off is supported only if the packet
+        // size is bigger than 256 bytes.
+        private int retransmits = 2;            // attemps of retransmits
+
+        void queueUpChangeCipherSpec() {
+
+            // Cleanup if a new flight starts.
+            if (flightIsReady) {
+                handshakeMemos.clear();
+                acquireIndex = 0;
+                flightIsReady = false;
+            }
+
+            RecordMemo memo = new RecordMemo();
+
+            memo.contentType = Record.ct_change_cipher_spec;
+            memo.majorVersion = protocolVersion.major;
+            memo.minorVersion = protocolVersion.minor;
+            memo.encodeEpoch = writeEpoch;
+            memo.encodeCipher = writeCipher;
+            memo.encodeAuthenticator = writeAuthenticator;
+
+            memo.fragment = new byte[1];
+            memo.fragment[0] = 1;
+
+            handshakeMemos.add(memo);
+        }
+
+        void queueUpHandshake(byte[] buf,
+                int offset, int length) throws IOException {
+
+            // Cleanup if a new flight starts.
+            if (flightIsReady) {
+                handshakeMemos.clear();
+                acquireIndex = 0;
+                flightIsReady = false;
+            }
+
+            HandshakeMemo memo = new HandshakeMemo();
+
+            memo.contentType = Record.ct_handshake;
+            memo.majorVersion = protocolVersion.major;
+            memo.minorVersion = protocolVersion.minor;
+            memo.encodeEpoch = writeEpoch;
+            memo.encodeCipher = writeCipher;
+            memo.encodeAuthenticator = writeAuthenticator;
+
+            memo.handshakeType = buf[offset];
+            memo.messageSequence = messageSequence++;
+            memo.acquireOffset = 0;
+            memo.fragment = new byte[length - 4];       // 4: header size
+                                                        //    1: HandshakeType
+                                                        //    3: message length
+            System.arraycopy(buf, offset + 4, memo.fragment, 0, length - 4);
+
+            handshakeHashing(memo, memo.fragment);
+            handshakeMemos.add(memo);
+
+            if ((memo.handshakeType == HandshakeMessage.ht_client_hello) ||
+                (memo.handshakeType == HandshakeMessage.ht_hello_request) ||
+                (memo.handshakeType ==
+                        HandshakeMessage.ht_hello_verify_request) ||
+                (memo.handshakeType == HandshakeMessage.ht_server_hello_done) ||
+                (memo.handshakeType == HandshakeMessage.ht_finished)) {
+
+                flightIsReady = true;
+            }
+        }
+
+        Ciphertext acquireCiphertext(ByteBuffer dstBuf) throws IOException {
+            if (isEmpty()) {
+                if (isRetransmittable()) {
+                    setRetransmission();    // configure for retransmission
+                } else {
+                    return null;
+                }
+            }
+
+            RecordMemo memo = handshakeMemos.get(acquireIndex);
+            HandshakeMemo hsMemo = null;
+            if (memo.contentType == Record.ct_handshake) {
+                hsMemo = (HandshakeMemo)memo;
+            }
+
+            int macLen = 0;
+            if (memo.encodeAuthenticator instanceof MAC) {
+                macLen = ((MAC)memo.encodeAuthenticator).MAClen();
+            }
+
+            // ChangeCipherSpec message is pretty small.  Don't worry about
+            // the fragmentation of ChangeCipherSpec record.
+            int fragLen;
+            if (packetSize > 0) {
+                fragLen = Math.min(maxRecordSize, packetSize);
+                fragLen = memo.encodeCipher.calculateFragmentSize(
+                        fragLen, macLen, 25);   // 25: header size
+                                                //   13: DTLS record
+                                                //   12: DTLS handshake message
+                fragLen = Math.min(fragLen, Record.maxDataSize);
+            } else {
+                fragLen = Record.maxDataSize;
+            }
+
+            if (fragmentSize > 0) {
+                fragLen = Math.min(fragLen, fragmentSize);
+            }
+
+            int dstPos = dstBuf.position();
+            int dstLim = dstBuf.limit();
+            int dstContent = dstPos + headerSize +
+                                    memo.encodeCipher.getExplicitNonceSize();
+            dstBuf.position(dstContent);
+
+            if (hsMemo != null) {
+                fragLen = Math.min(fragLen,
+                        (hsMemo.fragment.length - hsMemo.acquireOffset));
+
+                dstBuf.put(hsMemo.handshakeType);
+                dstBuf.put((byte)((hsMemo.fragment.length >> 16) & 0xFF));
+                dstBuf.put((byte)((hsMemo.fragment.length >> 8) & 0xFF));
+                dstBuf.put((byte)(hsMemo.fragment.length & 0xFF));
+                dstBuf.put((byte)((hsMemo.messageSequence >> 8) & 0xFF));
+                dstBuf.put((byte)(hsMemo.messageSequence & 0xFF));
+                dstBuf.put((byte)((hsMemo.acquireOffset >> 16) & 0xFF));
+                dstBuf.put((byte)((hsMemo.acquireOffset >> 8) & 0xFF));
+                dstBuf.put((byte)(hsMemo.acquireOffset & 0xFF));
+                dstBuf.put((byte)((fragLen >> 16) & 0xFF));
+                dstBuf.put((byte)((fragLen >> 8) & 0xFF));
+                dstBuf.put((byte)(fragLen & 0xFF));
+                dstBuf.put(hsMemo.fragment, hsMemo.acquireOffset, fragLen);
+            } else {
+                fragLen = Math.min(fragLen, memo.fragment.length);
+                dstBuf.put(memo.fragment, 0, fragLen);
+            }
+
+            dstBuf.limit(dstBuf.position());
+            dstBuf.position(dstContent);
+
+            if ((debug != null) && Debug.isOn("record")) {
+                System.out.println(Thread.currentThread().getName() +
+                        ", WRITE: " + protocolVersion + " " +
+                        Record.contentName(memo.contentType) +
+                        ", length = " + dstBuf.remaining());
+            }
+
+            // Encrypt the fragment and wrap up a record.
+            long recordSN = encrypt(memo.encodeAuthenticator, memo.encodeCipher,
+                    memo.contentType, dstBuf,
+                    dstPos, dstLim, headerSize,
+                    ProtocolVersion.valueOf(memo.majorVersion,
+                            memo.minorVersion), true);
+
+            if ((debug != null) && Debug.isOn("packet")) {
+                ByteBuffer temporary = dstBuf.duplicate();
+                temporary.limit(temporary.position());
+                temporary.position(dstPos);
+                Debug.printHex(
+                        "[Raw write]: length = " + temporary.remaining(),
+                        temporary);
+            }
+
+            // remain the limit unchanged
+            dstBuf.limit(dstLim);
+
+            // Reset the fragmentation offset.
+            if (hsMemo != null) {
+                hsMemo.acquireOffset += fragLen;
+                if (hsMemo.acquireOffset == hsMemo.fragment.length) {
+                    acquireIndex++;
+                }
+
+                return new Ciphertext(RecordType.valueOf(
+                        hsMemo.contentType, hsMemo.handshakeType), recordSN);
+            } else {
+                acquireIndex++;
+                return new Ciphertext(
+                        RecordType.RECORD_CHANGE_CIPHER_SPEC, recordSN);
+            }
+        }
+
+        private void handshakeHashing(HandshakeMemo hsFrag, byte[] hsBody) {
+
+            byte hsType = hsFrag.handshakeType;
+            if ((hsType == HandshakeMessage.ht_hello_request) ||
+                (hsType == HandshakeMessage.ht_hello_verify_request)) {
+
+                // omitted from handshake hash computation
+                return;
+            }
+
+            if ((hsFrag.messageSequence == 0) &&
+                (hsType == HandshakeMessage.ht_client_hello)) {
+
+                // omit initial ClientHello message
+                //
+                //  2: ClientHello.client_version
+                // 32: ClientHello.random
+                int sidLen = hsBody[34];
+
+                if (sidLen == 0) {      // empty session_id, initial handshake
+                    return;
+                }
+            }
+
+            // calculate the DTLS header
+            byte[] temporary = new byte[12];    // 12: handshake header size
+
+            // Handshake.msg_type
+            temporary[0] = hsFrag.handshakeType;
+
+            // Handshake.length
+            temporary[1] = (byte)((hsBody.length >> 16) & 0xFF);
+            temporary[2] = (byte)((hsBody.length >> 8) & 0xFF);
+            temporary[3] = (byte)(hsBody.length & 0xFF);
+
+            // Handshake.message_seq
+            temporary[4] = (byte)((hsFrag.messageSequence >> 8) & 0xFF);
+            temporary[5] = (byte)(hsFrag.messageSequence & 0xFF);
+
+            // Handshake.fragment_offset
+            temporary[6] = 0;
+            temporary[7] = 0;
+            temporary[8] = 0;
+
+            // Handshake.fragment_length
+            temporary[9] = temporary[1];
+            temporary[10] = temporary[2];
+            temporary[11] = temporary[3];
+
+            if ((hsType != HandshakeMessage.ht_finished) &&
+                (hsType != HandshakeMessage.ht_certificate_verify)) {
+
+                handshakeHash.update(temporary, 0, 12);
+                handshakeHash.update(hsBody, 0, hsBody.length);
+            } else {
+                // Reserve until this handshake message has been processed.
+                handshakeHash.reserve(temporary, 0, 12);
+                handshakeHash.reserve(hsBody, 0, hsBody.length);
+            }
+
+        }
+
+        boolean isEmpty() {
+            if (!flightIsReady || handshakeMemos.isEmpty() ||
+                    acquireIndex >= handshakeMemos.size()) {
+                return true;
+            }
+
+            return false;
+        }
+
+        boolean isRetransmittable() {
+            return (flightIsReady && !handshakeMemos.isEmpty() &&
+                                (acquireIndex >= handshakeMemos.size()));
+        }
+
+        private void setRetransmission() {
+            acquireIndex = 0;
+            for (RecordMemo memo : handshakeMemos) {
+                if (memo instanceof HandshakeMemo) {
+                    HandshakeMemo hmemo = (HandshakeMemo)memo;
+                    hmemo.acquireOffset = 0;
+                }
+            }
+
+            // Shrink packet size if:
+            // 1. maximum fragment size is allowed, in which case the packet
+            //    size is configured bigger than maxRecordSize;
+            // 2. maximum packet is bigger than 256 bytes;
+            // 3. two times of retransmits have been attempted.
+            if ((packetSize <= maxRecordSize) &&
+                    (packetSize > 256) && ((retransmits--) <= 0)) {
+
+                // shrink packet size
+                shrinkPacketSize();
+                retransmits = 2;        // attemps of retransmits
+            }
+        }
+
+        private void shrinkPacketSize() {
+            packetSize = Math.max(256, packetSize / 2);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/DTLSRecord.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.security.ssl;
+
+/**
+ * DTLS record
+ */
+interface DTLSRecord extends Record {
+
+    static final int    headerSize = 13;            // DTLS record header
+
+    static final int    handshakeHeaderSize = 12;   // DTLS handshake header
+
+    /*
+     * The size of the header plus the max IV length
+     */
+    static final int    headerPlusMaxIVSize =
+                                      headerSize        // header
+                                    + maxIVLength;      // iv
+
+    /*
+     * The maximum size that may be increased when translating plaintext to
+     * ciphertext fragment.
+     */
+    static final int    maxPlaintextPlusSize =
+                                      headerSize        // header
+                                    + maxIVLength       // iv
+                                    + maxMacSize        // MAC or AEAD tag
+                                    + maxPadding;       // block cipher padding
+
+    /*
+     * the maximum record size
+     */
+    static final int    maxRecordSize =
+                                      headerPlusMaxIVSize   // header + iv
+                                    + maxDataSize           // data
+                                    + maxPadding            // padding
+                                    + maxMacSize;           // MAC or AEAD tag
+
+    /*
+     * For CBC protection in SSL3/TLS1, we break some plaintext into two
+     * packets.  Max application data size for the second packet.
+     */
+    static final int    maxDataSizeMinusOneByteRecord =
+                                  maxDataSize       // max data size
+                                - (                 // max one byte record size
+                                      headerPlusMaxIVSize   // header + iv
+                                    + 1             // one byte data
+                                    + maxPadding    // padding
+                                    + maxMacSize    // MAC
+                                  );
+
+    /*
+     * Maximum record size for alert and change cipher spec records.
+     * They only contain 2 and 1 bytes of data, respectively.
+     * Allocate a smaller array.
+     */
+    static final int    maxAlertRecordSize =
+                                      headerPlusMaxIVSize   // header + iv
+                                    + 2                     // alert
+                                    + maxPadding            // padding
+                                    + maxMacSize;           // MAC
+
+}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/Debug.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/Debug.java	Wed Jul 05 20:37:09 2017 +0200
@@ -29,6 +29,9 @@
 import java.security.AccessController;
 import java.util.Locale;
 
+import sun.misc.HexDumpEncoder;
+import java.nio.ByteBuffer;
+
 import sun.security.action.GetPropertyAction;
 
 /**
@@ -198,4 +201,47 @@
     static String toString(byte[] b) {
         return sun.security.util.Debug.toString(b);
     }
+
+    static void printHex(String prefix, byte[] bytes) {
+        HexDumpEncoder dump = new HexDumpEncoder();
+
+        synchronized (System.out) {
+            System.out.println(prefix);
+            try {
+                dump.encodeBuffer(bytes, System.out);
+            } catch (Exception e) {
+                // ignore
+            }
+            System.out.flush();
+        }
+    }
+
+    static void printHex(String prefix, ByteBuffer bb) {
+        HexDumpEncoder dump = new HexDumpEncoder();
+
+        synchronized (System.out) {
+            System.out.println(prefix);
+            try {
+                dump.encodeBuffer(bb.slice(), System.out);
+            } catch (Exception e) {
+                // ignore
+            }
+            System.out.flush();
+        }
+    }
+
+    static void printHex(String prefix, byte[] bytes, int offset, int length) {
+        HexDumpEncoder dump = new HexDumpEncoder();
+
+        synchronized (System.out) {
+            System.out.println(prefix);
+            try {
+                ByteBuffer bb = ByteBuffer.wrap(bytes, offset, length);
+                dump.encodeBuffer(bb, System.out);
+            } catch (Exception e) {
+                // ignore
+            }
+            System.out.flush();
+        }
+    }
 }
--- a/jdk/src/java.base/share/classes/sun/security/ssl/EngineArgs.java	Thu Jun 04 18:50:30 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,238 +0,0 @@
-/*
- * Copyright (c) 2004, 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.  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.security.ssl;
-
-import java.nio.*;
-
-/*
- * A multi-purpose class which handles all of the SSLEngine arguments.
- * It validates arguments, checks for RO conditions, does space
- * calculations, performs scatter/gather, etc.
- *
- * @author Brad R. Wetmore
- */
-class EngineArgs {
-
-    /*
-     * Keep track of the input parameters.
-     */
-    ByteBuffer netData;
-    ByteBuffer [] appData;
-
-    private int offset;         // offset/len for the appData array.
-    private int len;
-
-    /*
-     * The initial pos/limit conditions.  This is useful because we can
-     * quickly calculate the amount consumed/produced in successful
-     * operations, or easily return the buffers to their pre-error
-     * conditions.
-     */
-    private int netPos;
-    private int netLim;
-
-    private int [] appPoss;
-    private int [] appLims;
-
-    /*
-     * Sum total of the space remaining in all of the appData buffers
-     */
-    private int appRemaining = 0;
-
-    private boolean wrapMethod;
-
-    /*
-     * Called by the SSLEngine.wrap() method.
-     */
-    EngineArgs(ByteBuffer [] appData, int offset, int len,
-            ByteBuffer netData) {
-        this.wrapMethod = true;
-        init(netData, appData, offset, len);
-    }
-
-    /*
-     * Called by the SSLEngine.unwrap() method.
-     */
-    EngineArgs(ByteBuffer netData, ByteBuffer [] appData, int offset,
-            int len) {
-        this.wrapMethod = false;
-        init(netData, appData, offset, len);
-    }
-
-    /*
-     * The main initialization method for the arguments.  Most
-     * of them are pretty obvious as to what they do.
-     *
-     * Since we're already iterating over appData array for validity
-     * checking, we also keep track of how much remainging space is
-     * available.  Info is used in both unwrap (to see if there is
-     * enough space available in the destination), and in wrap (to
-     * determine how much more we can copy into the outgoing data
-     * buffer.
-     */
-    private void init(ByteBuffer netData, ByteBuffer [] appData,
-            int offset, int len) {
-
-        if ((netData == null) || (appData == null)) {
-            throw new IllegalArgumentException("src/dst is null");
-        }
-
-        if ((offset < 0) || (len < 0) || (offset > appData.length - len)) {
-            throw new IndexOutOfBoundsException();
-        }
-
-        if (wrapMethod && netData.isReadOnly()) {
-            throw new ReadOnlyBufferException();
-        }
-
-        netPos = netData.position();
-        netLim = netData.limit();
-
-        appPoss = new int [appData.length];
-        appLims = new int [appData.length];
-
-        for (int i = offset; i < offset + len; i++) {
-            if (appData[i] == null) {
-                throw new IllegalArgumentException(
-                    "appData[" + i + "] == null");
-            }
-
-            /*
-             * If we're unwrapping, then check to make sure our
-             * destination bufffers are writable.
-             */
-            if (!wrapMethod && appData[i].isReadOnly()) {
-                throw new ReadOnlyBufferException();
-            }
-
-            appRemaining += appData[i].remaining();
-
-            appPoss[i] = appData[i].position();
-            appLims[i] = appData[i].limit();
-        }
-
-        /*
-         * Ok, looks like we have a good set of args, let's
-         * store the rest of this stuff.
-         */
-        this.netData = netData;
-        this.appData = appData;
-        this.offset = offset;
-        this.len = len;
-    }
-
-    /*
-     * Given spaceLeft bytes to transfer, gather up that much data
-     * from the appData buffers (starting at offset in the array),
-     * and transfer it into the netData buffer.
-     *
-     * The user has already ensured there is enough room.
-     */
-    void gather(int spaceLeft) {
-        for (int i = offset; (i < (offset + len)) && (spaceLeft > 0); i++) {
-            int amount = Math.min(appData[i].remaining(), spaceLeft);
-            appData[i].limit(appData[i].position() + amount);
-            netData.put(appData[i]);
-            appRemaining -= amount;
-            spaceLeft -= amount;
-        }
-    }
-
-    /*
-     * Using the supplied buffer, scatter the data into the appData buffers
-     * (starting at offset in the array).
-     *
-     * The user has already ensured there is enough room.
-     */
-    void scatter(ByteBuffer readyData) {
-        int amountLeft = readyData.remaining();
-
-        for (int i = offset; (i < (offset + len)) && (amountLeft > 0);
-                i++) {
-            int amount = Math.min(appData[i].remaining(), amountLeft);
-            readyData.limit(readyData.position() + amount);
-            appData[i].put(readyData);
-            amountLeft -= amount;
-        }
-        assert(readyData.remaining() == 0);
-    }
-
-    int getAppRemaining() {
-        return appRemaining;
-    }
-
-    /*
-     * Calculate the bytesConsumed/byteProduced.  Aren't you glad
-     * we saved this off earlier?
-     */
-    int deltaNet() {
-        return (netData.position() - netPos);
-    }
-
-    /*
-     * Calculate the bytesConsumed/byteProduced.  Aren't you glad
-     * we saved this off earlier?
-     */
-    int deltaApp() {
-        int sum = 0;    // Only calculating 2^14 here, don't need a long.
-
-        for (int i = offset; i < offset + len; i++) {
-            sum += appData[i].position() - appPoss[i];
-        }
-
-        return sum;
-    }
-
-    /*
-     * In the case of Exception, we want to reset the positions
-     * to appear as though no data has been consumed or produced.
-     *
-     * Currently, this method is only called as we are preparing to
-     * fail out, and thus we don't need to actually recalculate
-     * appRemaining.  If that assumption changes, that variable should
-     * be updated here.
-     */
-    void resetPos() {
-        netData.position(netPos);
-        for (int i = offset; i < offset + len; i++) {
-            // See comment above about recalculating appRemaining.
-            appData[i].position(appPoss[i]);
-        }
-    }
-
-    /*
-     * We are doing lots of ByteBuffer manipulations, in which case
-     * we need to make sure that the limits get set back correctly.
-     * This is one of the last things to get done before returning to
-     * the user.
-     */
-    void resetLim() {
-        netData.limit(netLim);
-        for (int i = offset; i < offset + len; i++) {
-            appData[i].limit(appLims[i]);
-        }
-    }
-}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/EngineInputRecord.java	Thu Jun 04 18:50:30 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,427 +0,0 @@
-/*
- * Copyright (c) 2003, 2014, 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.security.ssl;
-
-import java.io.*;
-import java.nio.*;
-import javax.net.ssl.*;
-import javax.crypto.BadPaddingException;
-import sun.misc.HexDumpEncoder;
-
-
-/**
- * Wrapper class around InputRecord.
- *
- * Application data is kept external to the InputRecord,
- * but handshake data (alert/change_cipher_spec/handshake) will
- * be kept internally in the ByteArrayInputStream.
- *
- * @author Brad Wetmore
- */
-final class EngineInputRecord extends InputRecord {
-
-    private SSLEngineImpl engine;
-
-    /*
-     * A dummy ByteBuffer we'll pass back even when the data
-     * is stored internally.  It'll never actually be used.
-     */
-    static private ByteBuffer tmpBB = ByteBuffer.allocate(0);
-
-    /*
-     * Flag to tell whether the last read/parsed data resides
-     * internal in the ByteArrayInputStream, or in the external
-     * buffers.
-     */
-    private boolean internalData;
-
-    EngineInputRecord(SSLEngineImpl engine) {
-        super();
-        this.engine = engine;
-    }
-
-    @Override
-    byte contentType() {
-        if (internalData) {
-            return super.contentType();
-        } else {
-            return ct_application_data;
-        }
-    }
-
-    /*
-     * Check if there is enough inbound data in the ByteBuffer
-     * to make a inbound packet.  Look for both SSLv2 and SSLv3.
-     *
-     * @return -1 if there are not enough bytes to tell (small header),
-     */
-    int bytesInCompletePacket(ByteBuffer buf) throws SSLException {
-
-        /*
-         * SSLv2 length field is in bytes 0/1
-         * SSLv3/TLS length field is in bytes 3/4
-         */
-        if (buf.remaining() < 5) {
-            return -1;
-        }
-
-        int pos = buf.position();
-        byte byteZero = buf.get(pos);
-
-        int len = 0;
-
-        /*
-         * If we have already verified previous packets, we can
-         * ignore the verifications steps, and jump right to the
-         * determination.  Otherwise, try one last hueristic to
-         * see if it's SSL/TLS.
-         */
-        if (formatVerified ||
-                (byteZero == ct_handshake) ||
-                (byteZero == ct_alert)) {
-            /*
-             * Last sanity check that it's not a wild record
-             */
-            ProtocolVersion recordVersion =
-                ProtocolVersion.valueOf(buf.get(pos + 1), buf.get(pos + 2));
-
-            // check the record version
-            checkRecordVersion(recordVersion, false);
-
-            /*
-             * Reasonably sure this is a V3, disable further checks.
-             * We can't do the same in the v2 check below, because
-             * read still needs to parse/handle the v2 clientHello.
-             */
-            formatVerified = true;
-
-            /*
-             * One of the SSLv3/TLS message types.
-             */
-            len = ((buf.get(pos + 3) & 0xff) << 8) +
-                (buf.get(pos + 4) & 0xff) + headerSize;
-
-        } else {
-            /*
-             * Must be SSLv2 or something unknown.
-             * Check if it's short (2 bytes) or
-             * long (3) header.
-             *
-             * Internals can warn about unsupported SSLv2
-             */
-            boolean isShort = ((byteZero & 0x80) != 0);
-
-            if (isShort &&
-                    ((buf.get(pos + 2) == 1) || buf.get(pos + 2) == 4)) {
-
-                ProtocolVersion recordVersion =
-                    ProtocolVersion.valueOf(buf.get(pos + 3), buf.get(pos + 4));
-
-                // check the record version
-                checkRecordVersion(recordVersion, true);
-
-                /*
-                 * Client or Server Hello
-                 */
-                int mask = (isShort ? 0x7f : 0x3f);
-                len = ((byteZero & mask) << 8) + (buf.get(pos + 1) & 0xff) +
-                    (isShort ? 2 : 3);
-
-            } else {
-                // Gobblygook!
-                throw new SSLException(
-                    "Unrecognized SSL message, plaintext connection?");
-            }
-        }
-
-        return len;
-    }
-
-    /*
-     * Pass the data down if it's internally cached, otherwise
-     * do it here.
-     *
-     * If internal data, data is decrypted internally.
-     *
-     * If external data(app), return a new ByteBuffer with data to
-     * process.
-     */
-    ByteBuffer decrypt(Authenticator authenticator,
-            CipherBox box, ByteBuffer bb) throws BadPaddingException {
-
-        if (internalData) {
-            decrypt(authenticator, box);   // MAC is checked during decryption
-            return tmpBB;
-        }
-
-        BadPaddingException reservedBPE = null;
-        int tagLen =
-            (authenticator instanceof MAC) ? ((MAC)authenticator).MAClen() : 0;
-        int cipheredLength = bb.remaining();
-
-        if (!box.isNullCipher()) {
-            try {
-                // apply explicit nonce for AEAD/CBC cipher suites if needed
-                int nonceSize =
-                    box.applyExplicitNonce(authenticator, contentType(), bb);
-
-                // decrypt the content
-                if (box.isAEADMode()) {
-                    // DON'T encrypt the nonce_explicit for AEAD mode
-                    bb.position(bb.position() + nonceSize);
-                }   // The explicit IV for CBC mode can be decrypted.
-
-                // Note that the CipherBox.decrypt() does not change
-                // the capacity of the buffer.
-                box.decrypt(bb, tagLen);
-                bb.position(nonceSize); // We don't actually remove the nonce.
-            } catch (BadPaddingException bpe) {
-                // RFC 2246 states that decryption_failed should be used
-                // for this purpose. However, that allows certain attacks,
-                // so we just send bad record MAC. We also need to make
-                // sure to always check the MAC to avoid a timing attack
-                // for the same issue. See paper by Vaudenay et al and the
-                // update in RFC 4346/5246.
-                //
-                // Failover to message authentication code checking.
-                reservedBPE = bpe;
-            }
-        }
-
-        // Requires message authentication code for null, stream and block
-        // cipher suites.
-        if ((authenticator instanceof MAC) && (tagLen != 0)) {
-            MAC signer = (MAC)authenticator;
-            int macOffset = bb.limit() - tagLen;
-
-            // Note that although it is not necessary, we run the same MAC
-            // computation and comparison on the payload for both stream
-            // cipher and CBC block cipher.
-            if (bb.remaining() < tagLen) {
-                // negative data length, something is wrong
-                if (reservedBPE == null) {
-                    reservedBPE = new BadPaddingException("bad record");
-                }
-
-                // set offset of the dummy MAC
-                macOffset = cipheredLength - tagLen;
-                bb.limit(cipheredLength);
-            }
-
-            // Run MAC computation and comparison on the payload.
-            if (checkMacTags(contentType(), bb, signer, false)) {
-                if (reservedBPE == null) {
-                    reservedBPE = new BadPaddingException("bad record MAC");
-                }
-            }
-
-            // Run MAC computation and comparison on the remainder.
-            //
-            // It is only necessary for CBC block cipher.  It is used to get a
-            // constant time of MAC computation and comparison on each record.
-            if (box.isCBCMode()) {
-                int remainingLen = calculateRemainingLen(
-                                        signer, cipheredLength, macOffset);
-
-                // NOTE: here we use the InputRecord.buf because I did not find
-                // an effective way to work on ByteBuffer when its capacity is
-                // less than remainingLen.
-
-                // NOTE: remainingLen may be bigger (less than 1 block of the
-                // hash algorithm of the MAC) than the cipheredLength. However,
-                // We won't need to worry about it because we always use a
-                // maximum buffer for every record.  We need a change here if
-                // we use small buffer size in the future.
-                if (remainingLen > buf.length) {
-                    // unlikely to happen, just a placehold
-                    throw new RuntimeException(
-                        "Internal buffer capacity error");
-                }
-
-                // Won't need to worry about the result on the remainder. And
-                // then we won't need to worry about what's actual data to
-                // check MAC tag on.  We start the check from the header of the
-                // buffer so that we don't need to construct a new byte buffer.
-                checkMacTags(contentType(), buf, 0, remainingLen, signer, true);
-            }
-
-            bb.limit(macOffset);
-        }
-
-        // Is it a failover?
-        if (reservedBPE != null) {
-            throw reservedBPE;
-        }
-
-        return bb.slice();
-    }
-
-    /*
-     * Run MAC computation and comparison
-     *
-     * Please DON'T change the content of the ByteBuffer parameter!
-     */
-    private static boolean checkMacTags(byte contentType, ByteBuffer bb,
-            MAC signer, boolean isSimulated) {
-
-        int position = bb.position();
-        int tagLen = signer.MAClen();
-        int lim = bb.limit();
-        int macData = lim - tagLen;
-
-        bb.limit(macData);
-        byte[] hash = signer.compute(contentType, bb, isSimulated);
-        if (hash == null || tagLen != hash.length) {
-            // Something is wrong with MAC implementation.
-            throw new RuntimeException("Internal MAC error");
-        }
-
-        bb.position(macData);
-        bb.limit(lim);
-        try {
-            int[] results = compareMacTags(bb, hash);
-            return (results[0] != 0);
-        } finally {
-            // reset to the data
-            bb.position(position);
-            bb.limit(macData);
-        }
-    }
-
-    /*
-     * A constant-time comparison of the MAC tags.
-     *
-     * Please DON'T change the content of the ByteBuffer parameter!
-     */
-    private static int[] compareMacTags(ByteBuffer bb, byte[] tag) {
-
-        // An array of hits is used to prevent Hotspot optimization for
-        // the purpose of a constant-time check.
-        int[] results = {0, 0};     // {missed #, matched #}
-
-        // The caller ensures there are enough bytes available in the buffer.
-        // So we won't need to check the remaining of the buffer.
-        for (int i = 0; i < tag.length; i++) {
-            if (bb.get() != tag[i]) {
-                results[0]++;       // mismatched bytes
-            } else {
-                results[1]++;       // matched bytes
-            }
-        }
-
-        return results;
-    }
-
-    /*
-     * Override the actual write below.  We do things this way to be
-     * consistent with InputRecord.  InputRecord may try to write out
-     * data to the peer, and *then* throw an Exception.  This forces
-     * data to be generated/output before the exception is ever
-     * generated.
-     */
-    @Override
-    void writeBuffer(OutputStream s, byte [] buf, int off, int len)
-            throws IOException {
-        /*
-         * Copy data out of buffer, it's ready to go.
-         */
-        ByteBuffer netBB = ByteBuffer.allocate(len).put(buf, 0, len).flip();
-        engine.writer.putOutboundDataSync(netBB);
-    }
-
-    /*
-     * Delineate or read a complete packet from src.
-     *
-     * If internal data (hs, alert, ccs), the data is read and
-     * stored internally.
-     *
-     * If external data (app), return a new ByteBuffer which points
-     * to the data to process.
-     */
-    ByteBuffer read(ByteBuffer srcBB) throws IOException {
-        /*
-         * Could have a src == null/dst == null check here,
-         * but that was already checked by SSLEngine.unwrap before
-         * ever attempting to read.
-         */
-
-        /*
-         * If we have anything besides application data,
-         * or if we haven't even done the initial v2 verification,
-         * we send this down to be processed by the underlying
-         * internal cache.
-         */
-        if (!formatVerified ||
-                (srcBB.get(srcBB.position()) != ct_application_data)) {
-            internalData = true;
-            read(new ByteBufferInputStream(srcBB), (OutputStream) null);
-            return tmpBB;
-        }
-
-        internalData = false;
-
-        int srcPos = srcBB.position();
-        int srcLim = srcBB.limit();
-
-        ProtocolVersion recordVersion = ProtocolVersion.valueOf(
-                srcBB.get(srcPos + 1), srcBB.get(srcPos + 2));
-
-        // check the record version
-        checkRecordVersion(recordVersion, false);
-
-        /*
-         * It's really application data.  How much to consume?
-         * Jump over the header.
-         */
-        int len = bytesInCompletePacket(srcBB);
-        assert(len > 0);
-
-        if (debug != null && Debug.isOn("packet")) {
-            try {
-                HexDumpEncoder hd = new HexDumpEncoder();
-                ByteBuffer bb = srcBB.duplicate();  // Use copy of BB
-                bb.limit(srcPos + len);
-
-                System.out.println("[Raw read (bb)]: length = " + len);
-                hd.encodeBuffer(bb, System.out);
-            } catch (IOException e) { }
-        }
-
-        // Demarcate past header to end of packet.
-        srcBB.position(srcPos + headerSize);
-        srcBB.limit(srcPos + len);
-
-        // Protect remainder of buffer, create slice to actually
-        // operate on.
-        ByteBuffer bb = srcBB.slice();
-
-        srcBB.position(srcBB.limit());
-        srcBB.limit(srcLim);
-
-        return bb;
-    }
-}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/EngineOutputRecord.java	Thu Jun 04 18:50:30 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,329 +0,0 @@
-/*
- * 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
- * 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.security.ssl;
-
-import java.io.*;
-import java.nio.*;
-
-/**
- * A OutputRecord class extension which uses external ByteBuffers
- * or the internal ByteArrayOutputStream for data manipulations.
- * <P>
- * Instead of rewriting this entire class
- * to use ByteBuffers, we leave things intact, so handshake, CCS,
- * and alerts will continue to use the internal buffers, but application
- * data will use external buffers.
- *
- * @author Brad Wetmore
- */
-final class EngineOutputRecord extends OutputRecord {
-
-    private SSLEngineImpl engine;
-    private EngineWriter writer;
-
-    private boolean finishedMsg = false;
-
-    /*
-     * All handshake hashing is done by the superclass
-     */
-
-    /*
-     * Default constructor makes a record supporting the maximum
-     * SSL record size.  It allocates the header bytes directly.
-     *
-     * @param type the content type for the record
-     */
-    EngineOutputRecord(byte type, SSLEngineImpl engine) {
-        super(type, recordSize(type));
-        this.engine = engine;
-        writer = engine.writer;
-    }
-
-    /**
-     * Get the size of the buffer we need for records of the specified
-     * type.
-     * <P>
-     * Application data buffers will provide their own byte buffers,
-     * and will not use the internal byte caching.
-     */
-    private static int recordSize(byte type) {
-        switch (type) {
-
-        case ct_change_cipher_spec:
-        case ct_alert:
-            return maxAlertRecordSize;
-
-        case ct_handshake:
-            return maxRecordSize;
-
-        case ct_application_data:
-            return 0;
-        }
-
-        throw new RuntimeException("Unknown record type: " + type);
-    }
-
-    void setFinishedMsg() {
-        finishedMsg = true;
-    }
-
-    @Override
-    public void flush() throws IOException {
-        finishedMsg = false;
-    }
-
-    boolean isFinishedMsg() {
-        return finishedMsg;
-    }
-
-    /*
-     * Override the actual write below.  We do things this way to be
-     * consistent with InputRecord.  InputRecord may try to write out
-     * data to the peer, and *then* throw an Exception.  This forces
-     * data to be generated/output before the exception is ever
-     * generated.
-     */
-    @Override
-    void writeBuffer(OutputStream s, byte [] buf, int off, int len,
-            int debugOffset) throws IOException {
-        /*
-         * Copy data out of buffer, it's ready to go.
-         */
-        ByteBuffer netBB = ByteBuffer.allocate(len).put(buf, off, len).flip();
-        writer.putOutboundData(netBB);
-    }
-
-    /*
-     * Main method for writing non-application data.
-     * We MAC/encrypt, then send down for processing.
-     */
-    void write(Authenticator authenticator, CipherBox writeCipher)
-            throws IOException {
-
-        /*
-         * Sanity check.
-         */
-        switch (contentType()) {
-            case ct_change_cipher_spec:
-            case ct_alert:
-            case ct_handshake:
-                break;
-            default:
-                throw new RuntimeException("unexpected byte buffers");
-        }
-
-        /*
-         * Don't bother to really write empty records.  We went this
-         * far to drive the handshake machinery, for correctness; not
-         * writing empty records improves performance by cutting CPU
-         * time and network resource usage.  Also, some protocol
-         * implementations are fragile and don't like to see empty
-         * records, so this increases robustness.
-         *
-         * (Even change cipher spec messages have a byte of data!)
-         */
-        if (!isEmpty()) {
-            // compress();              // eventually
-            encrypt(authenticator, writeCipher);
-
-            // send down for processing
-            write((OutputStream)null, false, (ByteArrayOutputStream)null);
-        }
-        return;
-    }
-
-    /**
-     * Main wrap/write driver.
-     */
-    void write(EngineArgs ea, Authenticator authenticator,
-            CipherBox writeCipher) throws IOException {
-        /*
-         * sanity check to make sure someone didn't inadvertantly
-         * send us an impossible combination we don't know how
-         * to process.
-         */
-        assert(contentType() == ct_application_data);
-
-        /*
-         * Have we set the MAC's yet?  If not, we're not ready
-         * to process application data yet.
-         */
-        if (authenticator == MAC.NULL) {
-            return;
-        }
-
-        /*
-         * Don't bother to really write empty records.  We went this
-         * far to drive the handshake machinery, for correctness; not
-         * writing empty records improves performance by cutting CPU
-         * time and network resource usage.  Also, some protocol
-         * implementations are fragile and don't like to see empty
-         * records, so this increases robustness.
-         */
-        if (ea.getAppRemaining() == 0) {
-            return;
-        }
-
-        /*
-         * By default, we counter chosen plaintext issues on CBC mode
-         * ciphersuites in SSLv3/TLS1.0 by sending one byte of application
-         * data in the first record of every payload, and the rest in
-         * subsequent record(s). Note that the issues have been solved in
-         * TLS 1.1 or later.
-         *
-         * It is not necessary to split the very first application record of
-         * a freshly negotiated TLS session, as there is no previous
-         * application data to guess.  To improve compatibility, we will not
-         * split such records.
-         *
-         * Because of the compatibility, we'd better produce no more than
-         * SSLSession.getPacketBufferSize() net data for each wrap. As we
-         * need a one-byte record at first, the 2nd record size should be
-         * equal to or less than Record.maxDataSizeMinusOneByteRecord.
-         *
-         * This avoids issues in the outbound direction.  For a full fix,
-         * the peer must have similar protections.
-         */
-        int length;
-        if (engine.needToSplitPayload(writeCipher, protocolVersion)) {
-            write(ea, authenticator, writeCipher, 0x01);
-            ea.resetLim();      // reset application data buffer limit
-            length = Math.min(ea.getAppRemaining(),
-                        maxDataSizeMinusOneByteRecord);
-        } else {
-            length = Math.min(ea.getAppRemaining(), maxDataSize);
-        }
-
-        // Don't bother to really write empty records.
-        if (length > 0) {
-            write(ea, authenticator, writeCipher, length);
-        }
-
-        return;
-    }
-
-    void write(EngineArgs ea, Authenticator authenticator,
-            CipherBox writeCipher, int length) throws IOException {
-        /*
-         * Copy out existing buffer values.
-         */
-        ByteBuffer dstBB = ea.netData;
-        int dstPos = dstBB.position();
-        int dstLim = dstBB.limit();
-
-        /*
-         * Where to put the data.  Jump over the header.
-         *
-         * Don't need to worry about SSLv2 rewrites, if we're here,
-         * that's long since done.
-         */
-        int dstData = dstPos + headerSize + writeCipher.getExplicitNonceSize();
-        dstBB.position(dstData);
-
-        /*
-         * transfer application data into the network data buffer
-         */
-        ea.gather(length);
-        dstBB.limit(dstBB.position());
-        dstBB.position(dstData);
-
-        /*
-         * "flip" but skip over header again, add MAC & encrypt
-         */
-        if (authenticator instanceof MAC) {
-            MAC signer = (MAC)authenticator;
-            if (signer.MAClen() != 0) {
-                byte[] hash = signer.compute(contentType(), dstBB, false);
-
-                /*
-                 * position was advanced to limit in compute above.
-                 *
-                 * Mark next area as writable (above layers should have
-                 * established that we have plenty of room), then write
-                 * out the hash.
-                 */
-                dstBB.limit(dstBB.limit() + hash.length);
-                dstBB.put(hash);
-
-                // reset the position and limit
-                dstBB.limit(dstBB.position());
-                dstBB.position(dstData);
-            }
-        }
-
-        if (!writeCipher.isNullCipher()) {
-            /*
-             * Requires explicit IV/nonce for CBC/AEAD cipher suites for TLS 1.1
-             * or later.
-             */
-            if (protocolVersion.v >= ProtocolVersion.TLS11.v &&
-                    (writeCipher.isCBCMode() || writeCipher.isAEADMode())) {
-                byte[] nonce = writeCipher.createExplicitNonce(
-                        authenticator, contentType(), dstBB.remaining());
-                dstBB.position(dstPos + headerSize);
-                dstBB.put(nonce);
-                if (!writeCipher.isAEADMode()) {
-                    // The explicit IV in TLS 1.1 and later can be encrypted.
-                    dstBB.position(dstPos + headerSize);
-                }   // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode
-            }
-
-            /*
-             * Encrypt may pad, so again the limit may have changed.
-             */
-            writeCipher.encrypt(dstBB, dstLim);
-
-            if ((debug != null) && (Debug.isOn("record") ||
-                    (Debug.isOn("handshake") &&
-                        (contentType() == ct_change_cipher_spec)))) {
-                System.out.println(Thread.currentThread().getName()
-                    // v3.0/v3.1 ...
-                    + ", WRITE: " + protocolVersion
-                    + " " + InputRecord.contentName(contentType())
-                    + ", length = " + length);
-            }
-        } else {
-            dstBB.position(dstBB.limit());
-        }
-
-        int packetLength = dstBB.limit() - dstPos - headerSize;
-
-        /*
-         * Finish out the record header.
-         */
-        dstBB.put(dstPos, contentType());
-        dstBB.put(dstPos + 1, protocolVersion.major);
-        dstBB.put(dstPos + 2, protocolVersion.minor);
-        dstBB.put(dstPos + 3, (byte)(packetLength >> 8));
-        dstBB.put(dstPos + 4, (byte)packetLength);
-
-        /*
-         * Position was already set by encrypt() above.
-         */
-        dstBB.limit(dstLim);
-    }
-}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/EngineWriter.java	Thu Jun 04 18:50:30 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,244 +0,0 @@
-/*
- * 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
- * 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.security.ssl;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.LinkedList;
-import javax.net.ssl.SSLEngineResult.HandshakeStatus;
-import sun.misc.HexDumpEncoder;
-
-/**
- * A class to help abstract away SSLEngine writing synchronization.
- */
-final class EngineWriter {
-
-    /*
-     * Outgoing handshake Data waiting for a ride is stored here.
-     * Normal application data is written directly into the outbound
-     * buffer, but handshake data can be written out at any time,
-     * so we have buffer it somewhere.
-     *
-     * When wrap is called, we first check to see if there is
-     * any data waiting, then if we're in a data transfer state,
-     * we try to write app data.
-     *
-     * This will contain either ByteBuffers, or the marker
-     * HandshakeStatus.FINISHED to signify that a handshake just completed.
-     */
-    private LinkedList<Object> outboundList;
-
-    private boolean outboundClosed = false;
-
-    /* Class and subclass dynamic debugging support */
-    private static final Debug debug = Debug.getInstance("ssl");
-
-    EngineWriter() {
-        outboundList = new LinkedList<Object>();
-    }
-
-    /*
-     * Upper levels assured us we had room for at least one packet of data.
-     * As per the SSLEngine spec, we only return one SSL packets worth of
-     * data.
-     */
-    private HandshakeStatus getOutboundData(ByteBuffer dstBB) {
-
-        Object msg = outboundList.removeFirst();
-        assert(msg instanceof ByteBuffer);
-
-        ByteBuffer bbIn = (ByteBuffer) msg;
-        assert(dstBB.remaining() >= bbIn.remaining());
-
-        dstBB.put(bbIn);
-
-        /*
-         * If we have more data in the queue, it's either
-         * a finished message, or an indication that we need
-         * to call wrap again.
-         */
-        if (hasOutboundDataInternal()) {
-            msg = outboundList.getFirst();
-            if (msg == HandshakeStatus.FINISHED) {
-                outboundList.removeFirst();     // consume the message
-                return HandshakeStatus.FINISHED;
-            } else {
-                return HandshakeStatus.NEED_WRAP;
-            }
-        } else {
-            return null;
-        }
-    }
-
-    /*
-     * Properly orders the output of the data written to the wrap call.
-     * This is only handshake data, application data goes through the
-     * other writeRecord.
-     */
-    synchronized void writeRecord(EngineOutputRecord outputRecord,
-            Authenticator authenticator,
-            CipherBox writeCipher) throws IOException {
-
-        /*
-         * Only output if we're still open.
-         */
-        if (outboundClosed) {
-            throw new IOException("writer side was already closed.");
-        }
-
-        outputRecord.write(authenticator, writeCipher);
-
-        /*
-         * Did our handshakers notify that we just sent the
-         * Finished message?
-         *
-         * Add an "I'm finished" message to the queue.
-         */
-        if (outputRecord.isFinishedMsg()) {
-            outboundList.addLast(HandshakeStatus.FINISHED);
-        }
-    }
-
-    /*
-     * Output the packet info.
-     */
-    private void dumpPacket(EngineArgs ea, boolean hsData) {
-        try {
-            HexDumpEncoder hd = new HexDumpEncoder();
-
-            ByteBuffer bb = ea.netData.duplicate();
-
-            int pos = bb.position();
-            bb.position(pos - ea.deltaNet());
-            bb.limit(pos);
-
-            System.out.println("[Raw write" +
-                (hsData ? "" : " (bb)") + "]: length = " +
-                bb.remaining());
-            hd.encodeBuffer(bb, System.out);
-        } catch (IOException e) { }
-    }
-
-    /*
-     * Properly orders the output of the data written to the wrap call.
-     * Only app data goes through here, handshake data goes through
-     * the other writeRecord.
-     *
-     * Shouldn't expect to have an IOException here.
-     *
-     * Return any determined status.
-     */
-    synchronized HandshakeStatus writeRecord(
-            EngineOutputRecord outputRecord, EngineArgs ea,
-            Authenticator authenticator,
-            CipherBox writeCipher) throws IOException {
-
-        /*
-         * If we have data ready to go, output this first before
-         * trying to consume app data.
-         */
-        if (hasOutboundDataInternal()) {
-            HandshakeStatus hss = getOutboundData(ea.netData);
-
-            if (debug != null && Debug.isOn("packet")) {
-                /*
-                 * We could have put the dump in
-                 * OutputRecord.write(OutputStream), but let's actually
-                 * output when it's actually output by the SSLEngine.
-                 */
-                dumpPacket(ea, true);
-            }
-
-            return hss;
-        }
-
-        /*
-         * If we are closed, no more app data can be output.
-         * Only existing handshake data (above) can be obtained.
-         */
-        if (outboundClosed) {
-            throw new IOException("The write side was already closed");
-        }
-
-        outputRecord.write(ea, authenticator, writeCipher);
-
-        if (debug != null && Debug.isOn("packet")) {
-            dumpPacket(ea, false);
-        }
-
-        /*
-         * No way new outbound handshake data got here if we're
-         * locked properly.
-         *
-         * We don't have any status we can return.
-         */
-        return null;
-    }
-
-    /*
-     * We already hold "this" lock, this is the callback from the
-     * outputRecord.write() above.  We already know this
-     * writer can accept more data (outboundClosed == false),
-     * and the closure is sync'd.
-     */
-    void putOutboundData(ByteBuffer bytes) {
-        outboundList.addLast(bytes);
-    }
-
-    /*
-     * This is for the really rare case that someone is writing from
-     * the *InputRecord* before we know what to do with it.
-     */
-    synchronized void putOutboundDataSync(ByteBuffer bytes)
-            throws IOException {
-
-        if (outboundClosed) {
-            throw new IOException("Write side already closed");
-        }
-
-        outboundList.addLast(bytes);
-    }
-
-    /*
-     * Non-synch'd version of this method, called by internals
-     */
-    private boolean hasOutboundDataInternal() {
-        return (outboundList.size() != 0);
-    }
-
-    synchronized boolean hasOutboundData() {
-        return hasOutboundDataInternal();
-    }
-
-    synchronized boolean isOutboundDone() {
-        return outboundClosed && !hasOutboundDataInternal();
-    }
-
-    synchronized void closeOutbound() {
-        outboundClosed = true;
-    }
-
-}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ExtensionType.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ExtensionType.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -43,7 +43,8 @@
         return name;
     }
 
-    static List<ExtensionType> knownExtensions = new ArrayList<ExtensionType>(9);
+    static List<ExtensionType> knownExtensions =
+            new ArrayList<ExtensionType>(13);
 
     static ExtensionType get(int id) {
         for (ExtensionType ext : knownExtensions) {
--- a/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeHash.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeHash.java	Wed Jul 05 20:37:09 2017 +0200
@@ -29,6 +29,7 @@
 import java.io.ByteArrayOutputStream;
 import java.security.*;
 import java.util.Locale;
+import java.nio.ByteBuffer;
 
 /**
  * Abstraction for the SSL/TLS hash of all handshake messages that is
@@ -99,6 +100,9 @@
     // For TLS 1.2
     private MessageDigest finMD;
 
+    // Cache for input record handshake hash computation
+    private ByteArrayOutputStream reserve = new ByteArrayOutputStream();
+
     /**
      * Create a new HandshakeHash. needCertificateVerify indicates whether
      * a hash for the certificate verify message is required.
@@ -107,7 +111,106 @@
         clonesNeeded = needCertificateVerify ? 3 : 2;
     }
 
+    void reserve(ByteBuffer input) {
+        if (input.hasArray()) {
+            reserve.write(input.array(),
+                    input.position() + input.arrayOffset(), input.remaining());
+        } else {
+            int inPos = input.position();
+            byte[] holder = new byte[input.remaining()];
+            input.get(holder);
+            input.position(inPos);
+            reserve.write(holder, 0, holder.length);
+        }
+    }
+
+    void reserve(byte[] b, int offset, int len) {
+        reserve.write(b, offset, len);
+    }
+
+    void reload() {
+        if (reserve.size() != 0) {
+            byte[] bytes = reserve.toByteArray();
+            reserve.reset();
+            update(bytes, 0, bytes.length);
+        }
+    }
+
+    void update(ByteBuffer input) {
+
+        // reload if there are reserved messages.
+        reload();
+
+        int inPos = input.position();
+        switch (version) {
+            case 1:
+                md5.update(input);
+                input.position(inPos);
+
+                sha.update(input);
+                input.position(inPos);
+
+                break;
+            default:
+                if (finMD != null) {
+                    finMD.update(input);
+                    input.position(inPos);
+                }
+                if (input.hasArray()) {
+                    data.write(input.array(),
+                            inPos + input.arrayOffset(), input.remaining());
+                } else {
+                    byte[] holder = new byte[input.remaining()];
+                    input.get(holder);
+                    input.position(inPos);
+                    data.write(holder, 0, holder.length);
+                }
+                break;
+        }
+    }
+
+    void update(byte handshakeType, byte[] handshakeBody) {
+
+        // reload if there are reserved messages.
+        reload();
+
+        switch (version) {
+            case 1:
+                md5.update(handshakeType);
+                sha.update(handshakeType);
+
+                md5.update((byte)((handshakeBody.length >> 16) & 0xFF));
+                sha.update((byte)((handshakeBody.length >> 16) & 0xFF));
+                md5.update((byte)((handshakeBody.length >> 8) & 0xFF));
+                sha.update((byte)((handshakeBody.length >> 8) & 0xFF));
+                md5.update((byte)(handshakeBody.length & 0xFF));
+                sha.update((byte)(handshakeBody.length & 0xFF));
+
+                md5.update(handshakeBody);
+                sha.update(handshakeBody);
+                break;
+            default:
+                if (finMD != null) {
+                    finMD.update(handshakeType);
+                    finMD.update((byte)((handshakeBody.length >> 16) & 0xFF));
+                    finMD.update((byte)((handshakeBody.length >> 8) & 0xFF));
+                    finMD.update((byte)(handshakeBody.length & 0xFF));
+                    finMD.update(handshakeBody);
+                }
+                data.write(handshakeType);
+                data.write((byte)((handshakeBody.length >> 16) & 0xFF));
+                data.write((byte)((handshakeBody.length >> 8) & 0xFF));
+                data.write((byte)(handshakeBody.length & 0xFF));
+                data.write(handshakeBody, 0, handshakeBody.length);
+                break;
+        }
+    }
+
     void update(byte[] b, int offset, int len) {
+
+        // reload if there are reserved messages.
+        reload();
+
         switch (version) {
             case 1:
                 md5.update(b, offset, len);
@@ -139,9 +242,15 @@
     void protocolDetermined(ProtocolVersion pv) {
 
         // Do not set again, will ignore
-        if (version != -1) return;
+        if (version != -1) {
+            return;
+        }
 
-        version = pv.compareTo(ProtocolVersion.TLS12) >= 0 ? 2 : 1;
+        if (pv.maybeDTLSProtocol()) {
+            version = pv.compareTo(ProtocolVersion.DTLS12) >= 0 ? 2 : 1;
+        } else {
+            version = pv.compareTo(ProtocolVersion.TLS12) >= 0 ? 2 : 1;
+        }
         switch (version) {
             case 1:
                 // initiate md5, sha and call update on saved array
--- a/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeInStream.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeInStream.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,11 +23,11 @@
  * questions.
  */
 
-
 package sun.security.ssl;
 
-import java.io.InputStream;
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
+import java.nio.ByteBuffer;
 
 import javax.net.ssl.SSLException;
 
@@ -38,154 +38,104 @@
  * Once a new handshake record arrives, it is buffered in this class until
  * processed by the Handshaker. The buffer may also contain incomplete
  * handshake messages in case the message is split across multiple records.
- * Handshaker.process_record deals with all that. It may also contain
+ * Handshaker.processRecord deals with all that. It may also contain
  * handshake messages larger than the default buffer size (e.g. large
- * certificate messages). The buffer is grown dynamically to handle that
- * (see InputRecord.queueHandshake()).
+ * certificate messages). The buffer is grown dynamically to handle that.
  *
- * Note that the InputRecord used as a buffer here is separate from the
- * AppInStream.r, which is where data from the socket is initially read
- * into. This is because once the initial handshake has been completed,
- * handshake and application data messages may be interleaved arbitrarily
- * and must be processed independently.
+ * Note that this class only handles Handshake messages in TLS format.
+ * DTLS Handshake messages should be converted into TLS format before
+ * calling into this method.
  *
  * @author David Brownell
  */
-public class HandshakeInStream extends InputStream {
 
-    InputRecord r;
+// This class is used to handle plain text handshake messages.
+//
+public final class HandshakeInStream extends ByteArrayInputStream {
 
     /*
      * Construct the stream; we'll be accumulating hashes of the
      * input records using two sets of digests.
      */
-    HandshakeInStream(HandshakeHash handshakeHash) {
-        r = new InputRecord();
-        r.setHandshakeHash(handshakeHash);
-    }
-
-
-    // overridden InputStream methods
-
-    /*
-     * Return the number of bytes available for read().
-     *
-     * Note that this returns the bytes remaining in the buffer, not
-     * the bytes remaining in the current handshake message.
-     */
-    @Override
-    public int available() {
-        return r.available();
-    }
-
-    /*
-     * Get a byte of handshake data.
-     */
-    @Override
-    public int read() throws IOException {
-        int n = r.read();
-        if (n == -1) {
-            throw new SSLException("Unexpected end of handshake data");
-        }
-        return n;
+    HandshakeInStream() {
+        super(new byte[0]);     // lazy to alloacte the internal buffer
     }
 
-    /*
-     * Get a bunch of bytes of handshake data.
-     */
+    //
+    // overridden ByteArrayInputStream methods
+    //
+
     @Override
-    public int read(byte b [], int off, int len) throws IOException {
-        // we read from a ByteArrayInputStream, it always returns the
-        // data in a single read if enough is available
-        int n = r.read(b, off, len);
-        if (n != len) {
+    public int read(byte[] b) throws IOException {
+        if (super.read(b) != b.length) {
             throw new SSLException("Unexpected end of handshake data");
         }
-        return n;
-    }
 
-    /*
-     * Skip some handshake data.
-     */
-    @Override
-    public long skip(long n) throws IOException {
-        return r.skip(n);
+        return b.length;
     }
 
-    /*
-     * Mark/ reset code, implemented using InputRecord mark/ reset.
-     *
-     * Note that it currently provides only a limited mark functionality
-     * and should be used with care (once a new handshake record has been
-     * read, data that has already been consumed is lost even if marked).
-     */
-
-    @Override
-    public void mark(int readlimit) {
-        r.mark(readlimit);
-    }
-
-    @Override
-    public void reset() throws IOException {
-        r.reset();
-    }
-
-    @Override
-    public boolean markSupported() {
-        return true;
-    }
-
-
-    // handshake management functions
+    //
+    // handshake input stream management functions
+    //
 
     /*
      * Here's an incoming record with handshake data.  Queue the contents;
      * it might be one or more entire messages, complete a message that's
      * partly queued, or both.
      */
-    void incomingRecord(InputRecord in) throws IOException {
-        r.queueHandshake(in);
+    void incomingRecord(ByteBuffer in) throws IOException {
+        int len;
+
+        // Move any unread data to the front of the buffer.
+        if (pos != 0) {
+            len = count - pos;
+            if (len != 0) {
+                System.arraycopy(buf, pos, buf, 0, len);
+            }
+            pos = 0;
+            count = len;
+        }
+
+        // Grow buffer if needed.
+        len = in.remaining() + count;
+        if (buf.length < len) {
+            byte[] newbuf = new byte[len];
+            if (count != 0) {
+                System.arraycopy(buf, 0, newbuf, 0, count);
+            }
+            buf = newbuf;
+        }
+
+        // Append the incoming record to the buffer
+        in.get(buf, count, in.remaining());
+        count = len;
     }
 
-    /*
-     * Hash any data we've consumed but not yet hashed.  Useful mostly
-     * for processing client certificate messages (so we can check the
-     * immediately following cert verify message) and finished messages
-     * (so we can compute our own finished message).
-     */
-    void digestNow() {
-        r.doHashes();
-    }
-
-    /*
-     * Do more than skip that handshake data ... totally ignore it.
-     * The difference is that the data does not get hashed.
-     */
-    void ignore(int n) {
-        r.ignore(n);
-    }
-
-
+    //
     // Message parsing methods
+    //
 
     /*
      * Read 8, 16, 24, and 32 bit SSL integer data types, encoded
      * in standard big-endian form.
      */
-
     int getInt8() throws IOException {
+        verifyLength(1);
         return read();
     }
 
     int getInt16() throws IOException {
+        verifyLength(2);
         return (getInt8() << 8) | getInt8();
     }
 
     int getInt24() throws IOException {
+        verifyLength(3);
         return (getInt8() << 16) | (getInt8() << 8) | getInt8();
     }
 
     int getInt32() throws IOException {
+        verifyLength(4);
         return (getInt8() << 24) | (getInt8() << 16)
              | (getInt8() << 8) | getInt8();
     }
@@ -193,13 +143,12 @@
     /*
      * Read byte vectors with 8, 16, and 24 bit length encodings.
      */
-
     byte[] getBytes8() throws IOException {
         int len = getInt8();
         verifyLength(len);
         byte b[] = new byte[len];
 
-        read(b, 0, len);
+        read(b);
         return b;
     }
 
@@ -208,7 +157,7 @@
         verifyLength(len);
         byte b[] = new byte[len];
 
-        read(b, 0, len);
+        read(b);
         return b;
     }
 
@@ -217,16 +166,14 @@
         verifyLength(len);
         byte b[] = new byte[len];
 
-        read(b, 0, len);
+        read(b);
         return b;
     }
 
     // Is a length greater than available bytes in the record?
     private void verifyLength(int len) throws SSLException {
         if (len > available()) {
-            throw new SSLException(
-                        "Not enough data to fill declared vector size");
+            throw new SSLException("Unexpected end of handshake data");
         }
     }
-
 }
--- a/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeMessage.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeMessage.java	Wed Jul 05 20:37:09 2017 +0200
@@ -73,24 +73,43 @@
  */
 public abstract class HandshakeMessage {
 
-    HandshakeMessage() { }
+    /* Class and subclass dynamic debugging support */
+    public static final Debug debug = Debug.getInstance("ssl");
 
     // enum HandshakeType:
-    static final byte   ht_hello_request = 0;
-    static final byte   ht_client_hello = 1;
-    static final byte   ht_server_hello = 2;
+    static final byte   ht_hello_request          = 0;      // RFC 5246
+    static final byte   ht_client_hello           = 1;      // RFC 5246
+    static final byte   ht_server_hello           = 2;      // RFC 5246
+    static final byte   ht_hello_verify_request   = 3;      // RFC 6347
+    static final byte   ht_new_session_ticket     = 4;      // RFC 4507
+
+    static final byte   ht_certificate            = 11;     // RFC 5246
+    static final byte   ht_server_key_exchange    = 12;     // RFC 5246
+    static final byte   ht_certificate_request    = 13;     // RFC 5246
+    static final byte   ht_server_hello_done      = 14;     // RFC 5246
+    static final byte   ht_certificate_verify     = 15;     // RFC 5246
+    static final byte   ht_client_key_exchange    = 16;     // RFC 5246
 
-    static final byte   ht_certificate = 11;
-    static final byte   ht_server_key_exchange = 12;
-    static final byte   ht_certificate_request = 13;
-    static final byte   ht_server_hello_done = 14;
-    static final byte   ht_certificate_verify = 15;
-    static final byte   ht_client_key_exchange = 16;
+    static final byte   ht_finished               = 20;     // RFC 5246
+    static final byte   ht_certificate_url        = 21;     // RFC 6066
+    static final byte   ht_certificate_status     = 22;     // RFC 6066
+    static final byte   ht_supplemental_data      = 23;     // RFC 4680
+
+    static final byte   ht_not_applicable         = -1;     // N/A
 
-    static final byte   ht_finished = 20;
+    /*
+     * SSL 3.0 MAC padding constants.
+     * Also used by CertificateVerify and Finished during the handshake.
+     */
+    static final byte[] MD5_pad1 = genPad(0x36, 48);
+    static final byte[] MD5_pad2 = genPad(0x5c, 48);
 
-    /* Class and subclass dynamic debugging support */
-    public static final Debug debug = Debug.getInstance("ssl");
+    static final byte[] SHA_pad1 = genPad(0x36, 40);
+    static final byte[] SHA_pad2 = genPad(0x5c, 40);
+
+    // default constructor
+    HandshakeMessage() {
+    }
 
     /**
      * Utility method to convert a BigInteger to a byte array in unsigned
@@ -109,16 +128,6 @@
         return b;
     }
 
-    /*
-     * SSL 3.0 MAC padding constants.
-     * Also used by CertificateVerify and Finished during the handshake.
-     */
-    static final byte[] MD5_pad1 = genPad(0x36, 48);
-    static final byte[] MD5_pad2 = genPad(0x5c, 48);
-
-    static final byte[] SHA_pad1 = genPad(0x36, 40);
-    static final byte[] SHA_pad2 = genPad(0x5c, 40);
-
     private static byte[] genPad(int b, int count) {
         byte[] padding = new byte[count];
         Arrays.fill(padding, (byte)b);
@@ -141,6 +150,7 @@
         s.write(messageType());
         s.putInt24(len);
         send(s);
+        s.complete();
     }
 
     /*
@@ -199,6 +209,69 @@
 
 }
 
+/*
+ * HelloVerifyRequest ... SERVER --> CLIENT  [DTLS only]
+ *
+ * The definition of HelloVerifyRequest is as follows:
+ *
+ *     struct {
+ *       ProtocolVersion server_version;
+ *       opaque cookie<0..2^8-1>;
+ *     } HelloVerifyRequest;
+ *
+ * For DTLS protocols, once the client has transmitted the ClientHello message,
+ * it expects to see a HelloVerifyRequest from the server.  However, if the
+ * server's message is lost, the client knows that either the ClientHello or
+ * the HelloVerifyRequest has been lost and retransmits. [RFC 6347]
+ */
+static final class HelloVerifyRequest extends HandshakeMessage {
+    ProtocolVersion     protocolVersion;
+    byte[]              cookie;         // 1 to 2^8 - 1 bytes
+
+    HelloVerifyRequest(HelloCookieManager helloCookieManager,
+            ClientHello clientHelloMsg) {
+
+        this.protocolVersion = clientHelloMsg.protocolVersion;
+        this.cookie = helloCookieManager.getCookie(clientHelloMsg);
+    }
+
+    HelloVerifyRequest(
+            HandshakeInStream input, int messageLength) throws IOException {
+
+        this.protocolVersion =
+                ProtocolVersion.valueOf(input.getInt8(), input.getInt8());
+        this.cookie = input.getBytes8();
+
+        // Is it a valid cookie?
+        HelloCookieManager.checkCookie(protocolVersion, cookie);
+    }
+
+    @Override
+    int messageType() {
+        return ht_hello_verify_request;
+    }
+
+    @Override
+    int messageLength() {
+        return 2 + cookie.length;       // 2: the length of protocolVersion
+    }
+
+    @Override
+    void send(HandshakeOutStream hos) throws IOException {
+        hos.putInt8(protocolVersion.major);
+        hos.putInt8(protocolVersion.minor);
+        hos.putBytes8(cookie);
+    }
+
+    @Override
+    void print(PrintStream out) throws IOException {
+        out.println("*** HelloVerifyRequest");
+        if (debug != null && Debug.isOn("verbose")) {
+            out.println("server_version: " + protocolVersion);
+            Debug.println(out, "cookie", cookie);
+        }
+    }
+}
 
 /*
  * ClientHello ... CLIENT --> SERVER
@@ -213,22 +286,31 @@
  */
 static final class ClientHello extends HandshakeMessage {
 
-    ProtocolVersion     protocolVersion;
-    RandomCookie        clnt_random;
-    SessionId           sessionId;
-    private CipherSuiteList    cipherSuites;
-    byte[]              compression_methods;
+    ProtocolVersion             protocolVersion;
+    RandomCookie                clnt_random;
+    SessionId                   sessionId;
+    byte[]                      cookie;                     // DTLS only
+    private CipherSuiteList     cipherSuites;
+    private final boolean       isDTLS;
+    byte[]                      compression_methods;
 
     HelloExtensions extensions = new HelloExtensions();
 
     private final static byte[]  NULL_COMPRESSION = new byte[] {0};
 
     ClientHello(SecureRandom generator, ProtocolVersion protocolVersion,
-            SessionId sessionId, CipherSuiteList cipherSuites) {
+            SessionId sessionId, CipherSuiteList cipherSuites,
+            boolean isDTLS) {
 
+        this.isDTLS = isDTLS;
         this.protocolVersion = protocolVersion;
         this.sessionId = sessionId;
         this.cipherSuites = cipherSuites;
+        if (isDTLS) {
+            this.cookie = new byte[0];
+        } else {
+            this.cookie = null;
+        }
 
         if (cipherSuites.containsEC()) {
             extensions.add(SupportedEllipticCurvesExtension.DEFAULT);
@@ -239,11 +321,21 @@
         compression_methods = NULL_COMPRESSION;
     }
 
-    ClientHello(HandshakeInStream s, int messageLength) throws IOException {
+    ClientHello(HandshakeInStream s,
+            int messageLength, boolean isDTLS) throws IOException {
+
+        this.isDTLS = isDTLS;
+
         protocolVersion = ProtocolVersion.valueOf(s.getInt8(), s.getInt8());
         clnt_random = new RandomCookie(s);
         sessionId = new SessionId(s.getBytes8());
         sessionId.checkLength(protocolVersion);
+        if (isDTLS) {
+            cookie = s.getBytes8();
+        } else {
+            cookie = null;
+        }
+
         cipherSuites = new CipherSuiteList(s);
         compression_methods = s.getBytes8();
         if (messageLength() != messageLength) {
@@ -279,6 +371,28 @@
         extensions.add(signatureAlgorithm);
     }
 
+    void addMFLExtension(int maximumPacketSize) {
+        HelloExtension maxFragmentLength =
+                new MaxFragmentLengthExtension(maximumPacketSize);
+        extensions.add(maxFragmentLength);
+    }
+
+    void updateHelloCookie(MessageDigest cookieDigest) {
+        //
+        // Just use HandshakeOutStream to compute the hello verify cookie.
+        // Not actually used to output handshake message records.
+        //
+        HandshakeOutStream hos = new HandshakeOutStream(null);
+
+        try {
+            send(hos, false);    // Do not count hello verify cookie.
+        } catch (IOException ioe) {
+            // unlikely to happen
+        }
+
+        cookieDigest.update(hos.toByteArray());
+    }
+
     @Override
     int messageType() { return ht_client_hello; }
 
@@ -290,6 +404,7 @@
          */
         return (2 + 32 + 1 + 2 + 1
             + sessionId.length()                /* ... + variable parts */
+            + (isDTLS ? (1 + cookie.length) : 0)
             + (cipherSuites.size() * 2)
             + compression_methods.length)
             + extensions.length();
@@ -297,13 +412,7 @@
 
     @Override
     void send(HandshakeOutStream s) throws IOException {
-        s.putInt8(protocolVersion.major);
-        s.putInt8(protocolVersion.minor);
-        clnt_random.send(s);
-        s.putBytes8(sessionId.getId());
-        cipherSuites.send(s);
-        s.putBytes8(compression_methods);
-        extensions.send(s);
+        send(s, true);  // Count hello verify cookie.
     }
 
     @Override
@@ -317,6 +426,10 @@
             s.print("Session ID:  ");
             s.println(sessionId);
 
+            if (isDTLS) {
+                Debug.println(s, "cookie", cookie);
+            }
+
             s.println("Cipher Suites: " + cipherSuites);
 
             Debug.println(s, "Compression Methods", compression_methods);
@@ -324,6 +437,21 @@
             s.println("***");
         }
     }
+
+    private void send(HandshakeOutStream s,
+            boolean computeCookie) throws IOException {
+        s.putInt8(protocolVersion.major);
+        s.putInt8(protocolVersion.minor);
+        clnt_random.send(s);
+        s.putBytes8(sessionId.getId());
+        if (isDTLS && computeCookie) {
+            s.putBytes8(cookie);
+        }
+        cipherSuites.send(s);
+        s.putBytes8(compression_methods);
+        extensions.send(s);
+    }
+
 }
 
 /*
@@ -740,7 +868,7 @@
         setValues(obj);
 
         Signature sig;
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             this.preferableSignatureAlgorithm = signAlgorithm;
             sig = JsseJce.getSignature(signAlgorithm.getAlgorithmName());
         } else {
@@ -801,7 +929,7 @@
                                              new BigInteger(1, dh_g)));
 
         // read the signature and hash algorithm
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             int hash = input.getInt8();         // hash algorithm
             int signature = input.getInt8();    // signature algorithm
 
@@ -834,7 +962,7 @@
 
         Signature sig;
         String algorithm = publicKey.getAlgorithm();
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             sig = JsseJce.getSignature(
                         preferableSignatureAlgorithm.getAlgorithmName());
         } else {
@@ -914,7 +1042,7 @@
         temp += dh_Ys.length;
 
         if (signature != null) {
-            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (protocolVersion.useTLS12PlusSpec()) {
                 temp += SignatureAndHashAlgorithm.sizeInRecord();
             }
 
@@ -934,7 +1062,7 @@
         s.putBytes16(dh_Ys);
 
         if (signature != null) {
-            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (protocolVersion.useTLS12PlusSpec()) {
                 s.putInt8(preferableSignatureAlgorithm.getHashValue());
                 s.putInt8(preferableSignatureAlgorithm.getSignatureValue());
             }
@@ -959,7 +1087,7 @@
             if (signature == null) {
                 s.println("Anonymous");
             } else {
-                if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                if (protocolVersion.useTLS12PlusSpec()) {
                     s.println("Signature Algorithm " +
                         preferableSignatureAlgorithm.getAlgorithmName());
                 }
@@ -1021,7 +1149,7 @@
         }
 
         Signature sig;
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             this.preferableSignatureAlgorithm = signAlgorithm;
             sig = JsseJce.getSignature(signAlgorithm.getAlgorithmName());
         } else {
@@ -1084,7 +1212,7 @@
         }
 
         // read the signature and hash algorithm
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             int hash = input.getInt8();         // hash algorithm
             int signature = input.getInt8();    // signature algorithm
 
@@ -1105,7 +1233,7 @@
 
         // verify the signature
         Signature sig;
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             sig = JsseJce.getSignature(
                         preferableSignatureAlgorithm.getAlgorithmName());
         } else {
@@ -1157,7 +1285,7 @@
         int sigLen = 0;
         if (signatureBytes != null) {
             sigLen = 2 + signatureBytes.length;
-            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (protocolVersion.useTLS12PlusSpec()) {
                 sigLen += SignatureAndHashAlgorithm.sizeInRecord();
             }
         }
@@ -1172,7 +1300,7 @@
         s.putBytes8(pointBytes);
 
         if (signatureBytes != null) {
-            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (protocolVersion.useTLS12PlusSpec()) {
                 s.putInt8(preferableSignatureAlgorithm.getHashValue());
                 s.putInt8(preferableSignatureAlgorithm.getSignatureValue());
             }
@@ -1189,7 +1317,7 @@
             if (signatureBytes == null) {
                 s.println("Anonymous");
             } else {
-                if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                if (protocolVersion.useTLS12PlusSpec()) {
                     s.println("Signature Algorithm " +
                             preferableSignatureAlgorithm.getAlgorithmName());
                 }
@@ -1315,7 +1443,7 @@
         this.types = JsseJce.isEcAvailable() ? TYPES_ECC : TYPES_NO_ECC;
 
         // Use supported_signature_algorithms for TLS 1.2 or later.
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             if (signAlgs == null || signAlgs.isEmpty()) {
                 throw new SSLProtocolException(
                         "No supported signature algorithms");
@@ -1339,7 +1467,7 @@
         types = input.getBytes8();
 
         // Read the supported_signature_algorithms for TLS 1.2 or later.
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             algorithmsLen = input.getInt16();
             if (algorithmsLen < 2) {
                 throw new SSLProtocolException(
@@ -1406,7 +1534,7 @@
     int messageLength() {
         int len = 1 + types.length + 2;
 
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             len += algorithmsLen + 2;
         }
 
@@ -1423,7 +1551,7 @@
         output.putBytes8(types);
 
         // put supported_signature_algorithms
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             output.putInt16(algorithmsLen);
             for (SignatureAndHashAlgorithm algorithm : algorithms) {
                 output.putInt8(algorithm.getHashValue());      // hash
@@ -1478,7 +1606,7 @@
             }
             s.println();
 
-            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (protocolVersion.useTLS12PlusSpec()) {
                 StringBuilder sb = new StringBuilder();
                 boolean opened = false;
                 for (SignatureAndHashAlgorithm signAlg : algorithms) {
@@ -1576,7 +1704,7 @@
 
         String algorithm = privateKey.getAlgorithm();
         Signature sig = null;
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             this.preferableSignatureAlgorithm = signAlgorithm;
             sig = JsseJce.getSignature(signAlgorithm.getAlgorithmName());
         } else {
@@ -1598,7 +1726,7 @@
         this.protocolVersion = protocolVersion;
 
         // read the signature and hash algorithm
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             int hashAlg = input.getInt8();         // hash algorithm
             int signAlg = input.getInt8();         // signature algorithm
 
@@ -1634,7 +1762,7 @@
             SecretKey masterSecret) throws GeneralSecurityException {
         String algorithm = publicKey.getAlgorithm();
         Signature sig = null;
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             sig = JsseJce.getSignature(
                         preferableSignatureAlgorithm.getAlgorithmName());
         } else {
@@ -1676,11 +1804,11 @@
             throws SignatureException {
 
         if (algorithm.equals("RSA")) {
-            if (protocolVersion.v < ProtocolVersion.TLS12.v) { // TLS1.1-
+            if (!protocolVersion.useTLS12PlusSpec()) {  // TLS1.1-
                 MessageDigest md5Clone = handshakeHash.getMD5Clone();
                 MessageDigest shaClone = handshakeHash.getSHAClone();
 
-                if (protocolVersion.v < ProtocolVersion.TLS10.v) { // SSLv3
+                if (!protocolVersion.useTLS10PlusSpec()) {  // SSLv3
                     updateDigest(md5Clone, MD5_pad1, MD5_pad2, masterKey);
                     updateDigest(shaClone, SHA_pad1, SHA_pad2, masterKey);
                 }
@@ -1692,10 +1820,10 @@
                 sig.update(handshakeHash.getAllHandshakeMessages());
             }
         } else { // DSA, ECDSA
-            if (protocolVersion.v < ProtocolVersion.TLS12.v) { // TLS1.1-
+            if (!protocolVersion.useTLS12PlusSpec()) {  // TLS1.1-
                 MessageDigest shaClone = handshakeHash.getSHAClone();
 
-                if (protocolVersion.v < ProtocolVersion.TLS10.v) { // SSLv3
+                if (!protocolVersion.useTLS10PlusSpec()) {  // SSLv3
                     updateDigest(shaClone, SHA_pad1, SHA_pad2, masterKey);
                 }
 
@@ -1811,7 +1939,7 @@
     int messageLength() {
         int temp = 2;
 
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             temp += SignatureAndHashAlgorithm.sizeInRecord();
         }
 
@@ -1820,7 +1948,7 @@
 
     @Override
     void send(HandshakeOutStream s) throws IOException {
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             s.putInt8(preferableSignatureAlgorithm.getHashValue());
             s.putInt8(preferableSignatureAlgorithm.getSignatureValue());
         }
@@ -1833,7 +1961,7 @@
         s.println("*** CertificateVerify");
 
         if (debug != null && Debug.isOn("verbose")) {
-            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (protocolVersion.useTLS12PlusSpec()) {
                 s.println("Signature Algorithm " +
                         preferableSignatureAlgorithm.getAlgorithmName());
             }
@@ -1899,7 +2027,7 @@
             CipherSuite cipherSuite) throws IOException {
         this.protocolVersion = protocolVersion;
         this.cipherSuite = cipherSuite;
-        int msgLen = (protocolVersion.v >= ProtocolVersion.TLS10.v) ? 12 : 36;
+        int msgLen = protocolVersion.useTLS10PlusSpec() ?  12 : 36;
         verifyData = new byte[msgLen];
         input.read(verifyData);
     }
@@ -1932,7 +2060,7 @@
             throw new RuntimeException("Invalid sender: " + sender);
         }
 
-        if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
+        if (protocolVersion.useTLS10PlusSpec()) {
             // TLS 1.0+
             try {
                 byte [] seed;
@@ -1940,14 +2068,14 @@
                 PRF prf;
 
                 // Get the KeyGenerator alg and calculate the seed.
-                if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
-                    // TLS 1.2
+                if (protocolVersion.useTLS12PlusSpec()) {
+                    // TLS 1.2+ or DTLS 1.2+
                     seed = handshakeHash.getFinishedHash();
 
                     prfAlg = "SunTls12Prf";
                     prf = cipherSuite.prfAlg;
                 } else {
-                    // TLS 1.0/1.1
+                    // TLS 1.0/1.1, DTLS 1.0
                     MessageDigest md5Clone = handshakeHash.getMD5Clone();
                     MessageDigest shaClone = handshakeHash.getSHAClone();
                     seed = new byte[36];
--- a/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeOutStream.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeOutStream.java	Wed Jul 05 20:37:09 2017 +0200
@@ -23,10 +23,9 @@
  * questions.
  */
 
-
 package sun.security.ssl;
 
-import java.io.OutputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 
 /**
@@ -40,197 +39,113 @@
  *
  * @author  David Brownell
  */
-public class HandshakeOutStream extends OutputStream {
-
-    private SSLSocketImpl socket;
-    private SSLEngineImpl engine;
-
-    OutputRecord r;
+public class HandshakeOutStream extends ByteArrayOutputStream {
 
-    HandshakeOutStream(ProtocolVersion protocolVersion,
-            ProtocolVersion helloVersion, HandshakeHash handshakeHash,
-            SSLSocketImpl socket) {
-        this.socket = socket;
-        r = new OutputRecord(Record.ct_handshake);
-        init(protocolVersion, helloVersion, handshakeHash);
-    }
+    OutputRecord outputRecord;      // May be null if not actually used to
+                                    // output handshake message records.
 
-    HandshakeOutStream(ProtocolVersion protocolVersion,
-            ProtocolVersion helloVersion, HandshakeHash handshakeHash,
-            SSLEngineImpl engine) {
-        this.engine = engine;
-        r = new EngineOutputRecord(Record.ct_handshake, engine);
-        init(protocolVersion, helloVersion, handshakeHash);
-    }
-
-    private void init(ProtocolVersion protocolVersion,
-            ProtocolVersion helloVersion, HandshakeHash handshakeHash) {
-        r.setVersion(protocolVersion);
-        r.setHelloVersion(helloVersion);
-        r.setHandshakeHash(handshakeHash);
+    HandshakeOutStream(OutputRecord outputRecord) {
+        super();
+        this.outputRecord = outputRecord;
     }
 
+    // Complete a handshakin message writing. Called by HandshakeMessage.
+    void complete() throws IOException {
+        if (size() < 4) {       // 4: handshake message header size
+            // internal_error alert will be triggered
+            throw new RuntimeException("handshake message is not available");
+        }
 
-    /*
-     * Update the handshake data hashes ... mostly for use after a
-     * client cert has been sent, so the cert verify message can be
-     * constructed correctly yet without forcing extra I/O.  In all
-     * other cases, automatic hash calculation suffices.
-     */
-    void doHashes() {
-        r.doHashes();
+        // outputRecord cannot be null
+        outputRecord.encodeHandshake(buf, 0, count);
+
+        // reset the byte array output stream
+        reset();
     }
 
-    /*
-     * Write some data out onto the stream ... buffers as much as possible.
-     * Hashes are updated automatically if something gets flushed to the
-     * network (e.g. a big cert message etc).
-     */
-    @Override
-    public void write(byte buf[], int off, int len) throws IOException {
-        while (len > 0) {
-            int howmuch = Math.min(len, r.availableDataBytes());
+    //
+    // overridden ByteArrayOutputStream methods
+    //
 
-            if (howmuch == 0) {
-                flush();
-            } else {
-                r.write(buf, off, howmuch);
-                off += howmuch;
-                len -= howmuch;
-            }
-        }
-    }
-
-    /*
-     * write-a-byte
-     */
     @Override
-    public void write(int i) throws IOException {
-        if (r.availableDataBytes() < 1) {
-            flush();
-        }
-        r.write(i);
+    public void write(byte[] b, int off, int len) {
+        // The maximum fragment size is 24 bytes.
+        checkOverflow(len, Record.OVERFLOW_OF_INT24);
+        super.write(b, off, len);
     }
 
     @Override
     public void flush() throws IOException {
-        if (socket != null) {
-            try {
-                socket.writeRecord(r);
-            } catch (IOException e) {
-                // Had problems writing; check if there was an
-                // alert from peer. If alert received, waitForClose
-                // will throw an exception for the alert
-                socket.waitForClose(true);
-
-                // No alert was received, just rethrow exception
-                throw e;
-            }
-        } else {  // engine != null
-            /*
-             * Even if record might be empty, flush anyway in case
-             * there is a finished handshake message that we need
-             * to queue.
-             */
-            engine.writeRecord((EngineOutputRecord)r);
-        }
+        outputRecord.flush();
     }
 
-    /*
-     * Tell the OutputRecord that a finished message was
-     * contained either in this record or the one immeiately
-     * preceding it.  We need to reliably pass back notifications
-     * that a finish message occurred.
-     */
-    void setFinishedMsg() {
-        assert(socket == null);
-
-        ((EngineOutputRecord)r).setFinishedMsg();
-    }
+    //
+    // handshake output stream management functions
+    //
 
     /*
      * Put integers encoded in standard 8, 16, 24, and 32 bit
      * big endian formats. Note that OutputStream.write(int) only
      * writes the least significant 8 bits and ignores the rest.
      */
-
     void putInt8(int i) throws IOException {
         checkOverflow(i, Record.OVERFLOW_OF_INT08);
-        r.write(i);
+        super.write(i);
     }
 
     void putInt16(int i) throws IOException {
         checkOverflow(i, Record.OVERFLOW_OF_INT16);
-        if (r.availableDataBytes() < 2) {
-            flush();
-        }
-        r.write(i >> 8);
-        r.write(i);
+        super.write(i >> 8);
+        super.write(i);
     }
 
     void putInt24(int i) throws IOException {
         checkOverflow(i, Record.OVERFLOW_OF_INT24);
-        if (r.availableDataBytes() < 3) {
-            flush();
-        }
-        r.write(i >> 16);
-        r.write(i >> 8);
-        r.write(i);
-    }
-
-    void putInt32(int i) throws IOException {
-        if (r.availableDataBytes() < 4) {
-            flush();
-        }
-        r.write(i >> 24);
-        r.write(i >> 16);
-        r.write(i >> 8);
-        r.write(i);
+        super.write(i >> 16);
+        super.write(i >> 8);
+        super.write(i);
     }
 
     /*
      * Put byte arrays with length encoded as 8, 16, 24 bit
      * integers in big-endian format.
      */
-    void putBytes8(byte b[]) throws IOException {
+    void putBytes8(byte[] b) throws IOException {
         if (b == null) {
             putInt8(0);
-            return;
         } else {
-            checkOverflow(b.length, Record.OVERFLOW_OF_INT08);
+            putInt8(b.length);
+            super.write(b, 0, b.length);
         }
-        putInt8(b.length);
-        write(b, 0, b.length);
     }
 
     public void putBytes16(byte b[]) throws IOException {
         if (b == null) {
             putInt16(0);
-            return;
         } else {
-            checkOverflow(b.length, Record.OVERFLOW_OF_INT16);
+            putInt16(b.length);
+            super.write(b, 0, b.length);
         }
-        putInt16(b.length);
-        write(b, 0, b.length);
     }
 
     void putBytes24(byte b[]) throws IOException {
         if (b == null) {
             putInt24(0);
-            return;
         } else {
-            checkOverflow(b.length, Record.OVERFLOW_OF_INT24);
+            putInt24(b.length);
+            super.write(b, 0, b.length);
         }
-        putInt24(b.length);
-        write(b, 0, b.length);
     }
 
-    private void checkOverflow(int length, int overflow) {
-        if (length >= overflow) {
+    /*
+     * Does the specified length overflow the limitation?
+     */
+    private static void checkOverflow(int length, int limit) {
+        if (length >= limit) {
             // internal_error alert will be triggered
             throw new RuntimeException(
                     "Field length overflow, the field length (" +
-                    length + ") should be less than " + overflow);
+                    length + ") should be less than " + limit);
         }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeStateManager.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,925 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.security.ssl;
+
+import java.util.LinkedList;
+import java.util.HashMap;
+import javax.net.ssl.SSLProtocolException;
+
+import sun.security.ssl.HandshakeMessage.*;
+
+import static sun.security.ssl.CipherSuite.KeyExchange;
+import static sun.security.ssl.CipherSuite.KeyExchange.*;
+import static sun.security.ssl.HandshakeStateManager.HandshakeState.*;
+import static sun.security.ssl.HandshakeMessage.*;
+
+/*
+ * Handshake state manager.
+ *
+ * Messages flow for a full handshake:
+ *
+ *      -                                                         -
+ *      |          HelloRequest       (No.0, RFC 5246) [*]        |
+ *      |     <--------------------------------------------       |
+ *      |                                                         |
+ *      |          ClientHello        (No.1, RFC 5246)            |
+ *      |     -------------------------------------------->       |
+ *      |                                                         |
+ *      |   -      HelloVerifyRequest (No.3, RFC 6347)      -     |
+ *      | D | <-------------------------------------------- | D   |
+ *      | T |                                               | T   |
+ *      | L |      ClientHello        (No.1, RFC 5246)      | L   |
+ *      | S | --------------------------------------------> | S   |
+ *      |   -                                               -     |
+ *      |                                                         |
+ *   C  |          ServerHello        (No.2, RFC 5246)            |  S
+ *   L  |          SupplementalData   (No.23, RFC4680) [*]        |  E
+ *   I  |          Certificate        (No.11, RFC 5246) [*]       |  R
+ *   E  |          CertificateStatus  (No.22, RFC 6066) [*]       |  V
+ *   N  |          ServerKeyExchange  (No.12, RFC 5246) [*]       |  E
+ *   T  |          CertificateRequest (No.13, RFC 5246) [*]       |  R
+ *      |          ServerHelloDone    (No.14, RFC 5246)           |
+ *      |     <--------------------------------------------       |
+ *      |                                                         |
+ *      |          SupplementalData   (No.23, RFC4680) [*]        |
+ *      |          Certificate        (No.11, RFC 5246) [*] Or    |
+ *      |              CertificateURL (No.21, RFC6066) [*]        |
+ *      |          ClientKeyExchange  (No.16, RFC 5246)           |
+ *      |          CertificateVerify  (No.15, RFC 5246) [*]       |
+ *      |          [ChangeCipherSpec] (RFC 5246)                  |
+ *      |          Finished           (No.20, RFC 5246)           |
+ *      |     -------------------------------------------->       |
+ *      |                                                         |
+ *      |          NewSessionTicket   (No.4, RFC4507) [*]         |
+ *      |          [ChangeCipherSpec] (RFC 5246)                  |
+ *      |          Finished           (No.20, RFC 5246)           |
+ *      |     <--------------------------------------------       |
+ *      -                                                         -
+ * [*] Indicates optional or situation-dependent messages that are not
+ * always sent.
+ *
+ * Message flow for an abbreviated handshake:
+ *      -                                                         -
+ *      |          ClientHello        (No.1, RFC 5246)            |
+ *      |     -------------------------------------------->       |
+ *      |                                                         |
+ *   C  |          ServerHello        (No.2, RFC 5246)            |  S
+ *   L  |          NewSessionTicket   (No.4, RFC4507) [*]         |  E
+ *   I  |          [ChangeCipherSpec] (RFC 5246)                  |  R
+ *   E  |          Finished           (No.20, RFC 5246)           |  V
+ *   N  |     <--------------------------------------------       |  E
+ *   T  |                                                         |  R
+ *      |          [ChangeCipherSpec] (RFC 5246)                  |
+ *      |          Finished           (No.20, RFC 5246)           |
+ *      |     -------------------------------------------->       |
+ *      -                                                         -
+ *
+ *
+ * State machine of handshake states:
+ *
+ *                   +--------------+
+ *      START -----> | HelloRequest |
+ *        |          +--------------+
+ *        |               |
+ *        v               v
+ *     +---------------------+   -->  +---------------------+
+ *     |    ClientHello      |        | HelloVerifyRequest  |
+ *     +---------------------+   <--  +---------------------+
+ *               |
+ *               |
+ * =========================================================================
+ *               |
+ *               v
+ *     +---------------------+
+ *     |    ServerHello      |  ----------------------------------+------+
+ *     +---------------------+  -->  +-------------------------+  |      |
+ *                    |              | Server SupplementalData |  |      |
+ *                    |              +-------------------------+  |      |
+ *                    |                |                          |      |
+ *                    v                v                          |      |
+ *                +---------------------+                         |      |
+ *         +----  | Server Certificate  |                         |      |
+ *         |      +---------------------+                         |      |
+ *         |          |                                           |      |
+ *         |          |   +--------------------+                  |      |
+ *         |          +-> | CertificateStatus  |                  |      |
+ *         |          |   +--------------------+                  v      |
+ *         |          |      |          |     +--------------------+     |
+ *         |          v      v          +-->  | ServerKeyExchange  |     |
+ *         |  +---------------------+   |     +--------------------+     |
+ *         |  | CertificateRequest  |   |         |                      |
+ *         |  +---------------------+ <-+---------+                      |
+ *         |            |               |         |                      |
+ *         v            v               |         |                      |
+ *     +---------------------+  <-------+         |                      |
+ *     |  ServerHelloDone    |  <-----------------+                      |
+ *     +---------------------+                                           |
+ *       |         |                                                     |
+ *       |         |                                                     |
+ *       |         |                                                     |
+ * =========================================================================
+ *       |         |                                                     |
+ *       |         v                                                     |
+ *       |   +-------------------------+                                 |
+ *       |   | Client SupplementalData | --------------+                 |
+ *       |   +-------------------------+               |                 |
+ *       |             |                               |                 |
+ *       |             v                               |                 |
+ *       |   +--------------------+                    |                 |
+ *       +-> | Client Certificate | ALT.               |                 |
+ *       |   +--------------------+----------------+   |                 |
+ *       |                        | CertificateURL |   |                 |
+ *       |                        +----------------+   |                 |
+ *       v                                             |                 |
+ *     +-------------------+  <------------------------+                 |
+ *     | ClientKeyExchange |                                             |
+ *     +-------------------+                                             |
+ *          |           |                                                |
+ *          |           v                                                |
+ *          |      +-------------------+                                 |
+ *          |      | CertificateVerify |                                 |
+ *          |      +-------------------+                                 |
+ *          |          |                                                 |
+ *          v          v                                                 |
+ *     +-------------------------+                                       |
+ *     | Client ChangeCipherSpec |  <---------------+                    |
+ *     +-------------------------+                  |                    |
+ *               |                                  |                    |
+ *               v                                  |                    |
+ *     +-----------------+  (abbreviated)           |                    |
+ *     | Client Finished |  -------------> END      |                    |
+ *     +-----------------+  (Abbreviated handshake) |                    |
+ *                      |                           |                    |
+ *                      | (full)                    |                    |
+ *                      |                           |                    |
+ * ================================                 |                    |
+ *                      |                           |                    |
+ *                      |                   ================================
+ *                      |                           |                    |
+ *                      v                           |                    |
+ *                 +------------------+             |    (abbreviated)   |
+ *                 | NewSessionTicket | <--------------------------------+
+ *                 +------------------+             |                    |
+ *                      |                           |                    |
+ *                      v                           |                    |
+ *     +-------------------------+                  |    (abbreviated)   |
+ *     | Server ChangeCipherSpec | <-------------------------------------+
+ *     +-------------------------+                  |
+ *               |                                  |
+ *               v                                  |
+ *     +-----------------+    (abbreviated)         |
+ *     | Server Finished | -------------------------+
+ *     +-----------------+
+ *            | (full)
+ *            v
+ *        END (Full handshake)
+ *
+ *
+ * The scenarios of the use of this class:
+ * 1. Create an instance of HandshakeStateManager during the initializtion
+ *    handshake.
+ * 2. If receiving a handshake message, call HandshakeStateManager.check()
+ *    to make sure that the message is of the expected handshake type.  And
+ *    then call HandshakeStateManager.update() in case handshake states may
+ *    be impacted by this new incoming handshake message.
+ * 3. On delivering a handshake message, call HandshakeStateManager.update()
+ *    in case handshake states may by thie new outgoing handshake message.
+ * 4. On receiving and delivering ChangeCipherSpec message, call
+ *    HandshakeStateManager.changeCipherSpec() to check the present sequence
+ *    of this message, and update the states if necessary.
+ */
+final class HandshakeStateManager {
+    // upcoming handshake states.
+    private LinkedList<HandshakeState> upcomingStates;
+    private LinkedList<HandshakeState> alternatives;
+
+    private boolean isDTLS;
+
+    private final static boolean debugIsOn;
+
+    private final static HashMap<Byte, String> handshakeTypes;
+
+    static {
+        debugIsOn = (Handshaker.debug != null) &&
+                Debug.isOn("handshake") && Debug.isOn("verbose");
+        handshakeTypes = new HashMap<>(15);
+
+        handshakeTypes.put(ht_hello_request,            "hello_request");
+        handshakeTypes.put(ht_client_hello,             "client_hello");
+        handshakeTypes.put(ht_server_hello,             "server_hello");
+        handshakeTypes.put(ht_hello_verify_request,     "hello_verify_request");
+        handshakeTypes.put(ht_new_session_ticket,       "session_ticket");
+        handshakeTypes.put(ht_certificate,              "certificate");
+        handshakeTypes.put(ht_server_key_exchange,      "server_key_exchange");
+        handshakeTypes.put(ht_certificate_request,      "certificate_request");
+        handshakeTypes.put(ht_server_hello_done,        "server_hello_done");
+        handshakeTypes.put(ht_certificate_verify,       "certificate_verify");
+        handshakeTypes.put(ht_client_key_exchange,      "client_key_exchange");
+        handshakeTypes.put(ht_finished,                 "finished");
+        handshakeTypes.put(ht_certificate_url,          "certificate_url");
+        handshakeTypes.put(ht_certificate_status,       "certificate_status");
+        handshakeTypes.put(ht_supplemental_data,        "supplemental_data");
+    }
+
+    HandshakeStateManager(boolean isDTLS) {
+        this.upcomingStates = new LinkedList<>();
+        this.alternatives = new LinkedList<>();
+        this.isDTLS = isDTLS;
+    }
+
+    //
+    // enumation of handshake type
+    //
+    static enum HandshakeState {
+        HS_HELLO_REQUEST(
+                "hello_request",
+                HandshakeMessage.ht_hello_request),
+        HS_CLIENT_HELLO(
+                "client_hello",
+                HandshakeMessage.ht_client_hello),
+        HS_HELLO_VERIFY_REQUEST(
+                "hello_verify_request",
+                HandshakeMessage.ht_hello_verify_request),
+        HS_SERVER_HELLO(
+                "server_hello",
+                HandshakeMessage.ht_server_hello),
+        HS_SERVER_SUPPLEMENTAL_DATA(
+                "server supplemental_data",
+                HandshakeMessage.ht_supplemental_data, true),
+        HS_SERVER_CERTIFICATE(
+                "server certificate",
+                HandshakeMessage.ht_certificate),
+        HS_CERTIFICATE_STATUS(
+                "certificate_status",
+                HandshakeMessage.ht_certificate_status, true),
+        HS_SERVER_KEY_EXCHANGE(
+                "server_key_exchange",
+                HandshakeMessage.ht_server_key_exchange, true),
+        HS_CERTIFICATE_REQUEST(
+                "certificate_request",
+                HandshakeMessage.ht_certificate_request, true),
+        HS_SERVER_HELLO_DONE(
+                "server_hello_done",
+                HandshakeMessage.ht_server_hello_done),
+        HS_CLIENT_SUPPLEMENTAL_DATA(
+                "client supplemental_data",
+                HandshakeMessage.ht_supplemental_data, true),
+        HS_CLIENT_CERTIFICATE(
+                "client certificate",
+                HandshakeMessage.ht_certificate, true),
+        HS_CERTIFICATE_URL(
+                "certificate_url",
+                HandshakeMessage.ht_certificate_url, true),
+        HS_CLIENT_KEY_EXCHANGE(
+                "client_key_exchange",
+                HandshakeMessage.ht_client_key_exchange),
+        HS_CERTIFICATE_VERIFY(
+                "certificate_verify",
+                HandshakeMessage.ht_certificate_verify, true),
+        HS_CLIENT_CHANGE_CIPHER_SPEC(
+                "client change_cipher_spec",
+                HandshakeMessage.ht_not_applicable),
+        HS_CLEINT_FINISHED(
+                "client finished",
+                HandshakeMessage.ht_finished),
+        HS_NEW_SESSION_TICKET(
+                "session_ticket",
+                HandshakeMessage.ht_new_session_ticket),
+        HS_SERVER_CHANGE_CIPHER_SPEC(
+                "server change_cipher_spec",
+                HandshakeMessage.ht_not_applicable),
+        HS_SERVER_FINISHDE(
+                "server finished",
+                HandshakeMessage.ht_finished);
+
+        final String description;
+        final byte handshakeType;
+        final boolean isOptional;
+
+        HandshakeState(String description, byte handshakeType) {
+            this.description = description;
+            this.handshakeType = handshakeType;
+            this.isOptional = false;
+        }
+
+        HandshakeState(String description,
+                byte handshakeType, boolean isOptional) {
+
+            this.description = description;
+            this.handshakeType = handshakeType;
+            this.isOptional = isOptional;
+        }
+
+        public String toString() {
+            return description + "[" + handshakeType + "]" +
+                    (isOptional ? "(optional)" : "");
+        }
+    }
+
+    boolean isEmpty() {
+        return upcomingStates.isEmpty();
+    }
+
+    void check(byte handshakeType) throws SSLProtocolException {
+        String exceptionMsg =
+                 "Handshake message sequence violation, " + handshakeType;
+
+        if (debugIsOn) {
+            System.out.println(
+                    "check handshake state: " + toString(handshakeType));
+        }
+
+        if (upcomingStates.isEmpty()) {
+            // Is it a kickstart message?
+            if ((handshakeType != HandshakeMessage.ht_hello_request) &&
+                (handshakeType != HandshakeMessage.ht_client_hello)) {
+
+                throw new SSLProtocolException(
+                    "Handshake message sequence violation, " + handshakeType);
+            }
+
+            // It is a kickstart message.
+            return;
+        }
+
+        // Ignore the checking for HelloRequest messages as they are
+        // may be sent by the server at any time.
+        if (handshakeType == HandshakeMessage.ht_hello_request) {
+            return;
+        }
+
+        for (HandshakeState handshakeState : upcomingStates) {
+            if (handshakeState.handshakeType == handshakeType) {
+                // It's the expected next handshake type.
+                return;
+            }
+
+            if (handshakeState.isOptional) {
+                continue;
+            } else {
+                for (HandshakeState alternative : alternatives) {
+                    if (alternative.handshakeType == handshakeType) {
+                        return;
+                    }
+
+                    if (alternative.isOptional) {
+                        continue;
+                    } else {
+                        throw new SSLProtocolException(exceptionMsg);
+                    }
+                }
+            }
+
+            throw new SSLProtocolException(exceptionMsg);
+        }
+
+        // Not an expected Handshake message.
+        throw new SSLProtocolException(
+                "Handshake message sequence violation, " + handshakeType);
+    }
+
+    void update(HandshakeMessage handshakeMessage,
+            boolean isAbbreviated) throws SSLProtocolException {
+
+        byte handshakeType = (byte)handshakeMessage.messageType();
+        String exceptionMsg =
+                 "Handshake message sequence violation, " + handshakeType;
+
+        if (debugIsOn) {
+            System.out.println(
+                    "update handshake state: " + toString(handshakeType));
+        }
+
+        boolean hasPresentState = false;
+        switch (handshakeType) {
+        case HandshakeMessage.ht_hello_request:
+            //
+            // State machine:
+            //     PRESENT: START
+            //        TO  : ClientHello
+            //
+
+            // No old state to update.
+
+            // Add the upcoming states.
+            if (!upcomingStates.isEmpty()) {
+                // A ClientHello message should be followed.
+                upcomingStates.add(HS_CLIENT_HELLO);
+
+            }   // Otherwise, ignore this HelloRequest message.
+
+            break;
+
+        case HandshakeMessage.ht_client_hello:
+            //
+            // State machine:
+            //     PRESENT: START
+            //              HS_CLIENT_HELLO
+            //        TO  : HS_HELLO_VERIFY_REQUEST (DTLS)
+            //              HS_SERVER_HELLO
+            //
+
+            // Check and update the present state.
+            if (!upcomingStates.isEmpty()) {
+                // The current state should be HS_CLIENT_HELLO.
+                HandshakeState handshakeState = upcomingStates.pop();
+                if (handshakeState != HS_CLIENT_HELLO) {
+                    throw new SSLProtocolException(exceptionMsg);
+                }
+            }
+
+            // Add the upcoming states.
+            ClientHello clientHello = (ClientHello)handshakeMessage;
+            if (isDTLS) {
+                // Is it an initial ClientHello message?
+                if (clientHello.cookie == null ||
+                        clientHello.cookie.length == 0) {
+                    // Is it an abbreviated handshake?
+                    if (clientHello.sessionId.length() != 0) {
+                        // A HelloVerifyRequest message or a ServerHello
+                        // message may follow the abbreviated session
+                        // resuming handshake request.
+                        upcomingStates.add(HS_HELLO_VERIFY_REQUEST);
+                        alternatives.add(HS_SERVER_HELLO);
+                    } else {
+                        // A HelloVerifyRequest message should follow
+                        // the initial ClientHello message.
+                        upcomingStates.add(HS_HELLO_VERIFY_REQUEST);
+                    }
+                } else {
+                    // A HelloVerifyRequest may be followed if the cookie
+                    // cannot be verified.
+                    upcomingStates.add(HS_SERVER_HELLO);
+                    alternatives.add(HS_HELLO_VERIFY_REQUEST);
+                }
+            } else {
+                upcomingStates.add(HS_SERVER_HELLO);
+            }
+
+            break;
+
+        case HandshakeMessage.ht_hello_verify_request:
+            //
+            // State machine:
+            //     PRESENT: HS_HELLO_VERIFY_REQUEST
+            //        TO  : HS_CLIENT_HELLO
+            //
+            // Note that this state may have an alternative option.
+
+            // Check and update the present state.
+            if (!upcomingStates.isEmpty()) {
+                // The current state should be HS_HELLO_VERIFY_REQUEST.
+                HandshakeState handshakeState = upcomingStates.pop();
+                HandshakeState alternative = null;
+                if (!alternatives.isEmpty()) {
+                    alternative = alternatives.pop();
+                }
+
+                if ((handshakeState != HS_HELLO_VERIFY_REQUEST) &&
+                        (alternative != HS_HELLO_VERIFY_REQUEST)) {
+
+                    throw new SSLProtocolException(exceptionMsg);
+                }
+            } else {
+                // No present state.
+                throw new SSLProtocolException(exceptionMsg);
+            }
+
+            // Add the upcoming states.
+            upcomingStates.add(HS_CLIENT_HELLO);
+
+            break;
+
+        case HandshakeMessage.ht_server_hello:
+            //
+            // State machine:
+            //     PRESENT: HS_SERVER_HELLO
+            //        TO  :
+            //          Full handshake state stacks
+            //              (ServerHello Flight)
+            //              HS_SERVER_SUPPLEMENTAL_DATA [optional]
+            //          --> HS_SERVER_CERTIFICATE [optional]
+            //          --> HS_CERTIFICATE_STATUS [optional]
+            //          --> HS_SERVER_KEY_EXCHANGE [optional]
+            //          --> HS_CERTIFICATE_REQUEST [optional]
+            //          --> HS_SERVER_HELLO_DONE
+            //              (Client ClientKeyExchange Flight)
+            //          --> HS_CLIENT_SUPPLEMENTAL_DATA [optional]
+            //          --> HS_CLIENT_CERTIFICATE or
+            //              HS_CERTIFICATE_URL
+            //          --> HS_CLIENT_KEY_EXCHANGE
+            //          --> HS_CERTIFICATE_VERIFY [optional]
+            //          --> HS_CLIENT_CHANGE_CIPHER_SPEC
+            //          --> HS_CLEINT_FINISHED
+            //              (Server Finished Flight)
+            //          --> HS_CLIENT_SUPPLEMENTAL_DATA [optional]
+            //
+            //          Abbreviated handshake state stacks
+            //              (Server Finished Flight)
+            //              HS_NEW_SESSION_TICKET
+            //          --> HS_SERVER_CHANGE_CIPHER_SPEC
+            //          --> HS_SERVER_FINISHDE
+            //              (Client Finished Flight)
+            //          --> HS_CLIENT_CHANGE_CIPHER_SPEC
+            //          --> HS_CLEINT_FINISHED
+            //
+            // Note that this state may have an alternative option.
+
+            // Check and update the present state.
+            if (!upcomingStates.isEmpty()) {
+                // The current state should be HS_SERVER_HELLO
+                HandshakeState handshakeState = upcomingStates.pop();
+                HandshakeState alternative = null;
+                if (!alternatives.isEmpty()) {
+                    alternative = alternatives.pop();
+                }
+
+                if ((handshakeState != HS_SERVER_HELLO) &&
+                        (alternative != HS_SERVER_HELLO)) {
+
+                    throw new SSLProtocolException(exceptionMsg);
+                }
+            } else {
+                // No present state.
+                throw new SSLProtocolException(exceptionMsg);
+            }
+
+            // Add the upcoming states.
+            ServerHello serverHello = (ServerHello)handshakeMessage;
+            HelloExtensions hes = serverHello.extensions;
+
+
+            // Not support SessionTicket extension yet.
+            //
+            // boolean hasSessionTicketExt =
+            //     (hes.get(HandshakeMessage.ht_new_session_ticket) != null);
+
+            if (isAbbreviated) {
+                // Not support SessionTicket extension yet.
+                //
+                // // Mandatory NewSessionTicket message
+                // if (hasSessionTicketExt) {
+                //     upcomingStates.add(HS_NEW_SESSION_TICKET);
+                // }
+
+                // Mandatory server ChangeCipherSpec and Finished messages
+                upcomingStates.add(HS_SERVER_CHANGE_CIPHER_SPEC);
+                upcomingStates.add(HS_SERVER_FINISHDE);
+
+                // Mandatory client ChangeCipherSpec and Finished messages
+                upcomingStates.add(HS_CLIENT_CHANGE_CIPHER_SPEC);
+                upcomingStates.add(HS_CLEINT_FINISHED);
+            } else {
+                // Not support SupplementalData extension yet.
+                //
+                // boolean hasSupplementalDataExt =
+                //     (hes.get(HandshakeMessage.ht_supplemental_data) != null);
+
+                // Not support CertificateStatus extension yet.
+                //
+                // boolean hasCertificateStatusExt =
+                //    (hes.get(HandshakeMessage.ht_certificate_status) != null);
+
+                // Not support CertificateURL extension yet.
+                //
+                // boolean hasCertificateUrlExt =
+                //     (hes.get(HandshakeMessage.ht_certificate_url) != null);
+
+                // Not support SupplementalData extension yet.
+                //
+                // // Optional SupplementalData message
+                // if (hasSupplementalDataExt) {
+                //     upcomingStates.add(HS_SERVER_SUPPLEMENTAL_DATA);
+                // }
+
+                // Need server Certificate message or not?
+                KeyExchange keyExchange = serverHello.cipherSuite.keyExchange;
+                if ((keyExchange != K_KRB5) &&
+                        (keyExchange != K_KRB5_EXPORT) &&
+                        (keyExchange != K_DH_ANON) &&
+                        (keyExchange != K_ECDH_ANON)) {
+                    // Mandatory Certificate message
+                    upcomingStates.add(HS_SERVER_CERTIFICATE);
+                }
+
+                // Not support CertificateStatus extension yet.
+                //
+                // // Optional CertificateStatus message
+                // if (hasCertificateStatusExt) {
+                //     upcomingStates.add(HS_CERTIFICATE_STATUS);
+                // }
+
+                // Need ServerKeyExchange message or not?
+                if ((keyExchange == K_RSA_EXPORT) ||
+                        (keyExchange == K_DHE_RSA) ||
+                        (keyExchange == K_DHE_DSS) ||
+                        (keyExchange == K_DH_ANON) ||
+                        (keyExchange == K_ECDHE_RSA) ||
+                        (keyExchange == K_ECDHE_ECDSA) ||
+                        (keyExchange == K_ECDH_ANON)) {
+                    // Optional ServerKeyExchange message
+                    upcomingStates.add(HS_SERVER_KEY_EXCHANGE);
+                }
+
+                // Optional CertificateRequest message
+                upcomingStates.add(HS_CERTIFICATE_REQUEST);
+
+                // Mandatory ServerHelloDone message
+                upcomingStates.add(HS_SERVER_HELLO_DONE);
+
+                // Not support SupplementalData extension yet.
+                //
+                // // Optional SupplementalData message
+                // if (hasSupplementalDataExt) {
+                //     upcomingStates.add(HS_CLIENT_SUPPLEMENTAL_DATA);
+                // }
+
+                // Optional client Certificate message
+                upcomingStates.add(HS_CLIENT_CERTIFICATE);
+
+                // Not support CertificateURL extension yet.
+                //
+                // // Alternative CertificateURL message, optional too.
+                // //
+                // // Please put CertificateURL rather than Certificate
+                // // message in the alternatives list.  So that we can
+                // // simplify the process of this alternative pair later.
+                // if (hasCertificateUrlExt) {
+                //     alternatives.add(HS_CERTIFICATE_URL);
+                // }
+
+                // Mandatory ClientKeyExchange message
+                upcomingStates.add(HS_CLIENT_KEY_EXCHANGE);
+
+                // Optional CertificateVerify message
+                upcomingStates.add(HS_CERTIFICATE_VERIFY);
+
+                // Mandatory client ChangeCipherSpec and Finished messages
+                upcomingStates.add(HS_CLIENT_CHANGE_CIPHER_SPEC);
+                upcomingStates.add(HS_CLEINT_FINISHED);
+
+                // Not support SessionTicket extension yet.
+                //
+                // // Mandatory NewSessionTicket message
+                // if (hasSessionTicketExt) {
+                //     upcomingStates.add(HS_NEW_SESSION_TICKET);
+                // }
+
+                // Mandatory server ChangeCipherSpec and Finished messages
+                upcomingStates.add(HS_SERVER_CHANGE_CIPHER_SPEC);
+                upcomingStates.add(HS_SERVER_FINISHDE);
+            }
+
+            break;
+
+        case HandshakeMessage.ht_certificate:
+            //
+            // State machine:
+            //     PRESENT: HS_CERTIFICATE_URL or
+            //              HS_CLIENT_CERTIFICATE
+            //        TO  : HS_CLIENT_KEY_EXCHANGE
+            //
+            //     Or
+            //
+            //     PRESENT: HS_SERVER_CERTIFICATE
+            //        TO  : HS_CERTIFICATE_STATUS [optional]
+            //              HS_SERVER_KEY_EXCHANGE [optional]
+            //              HS_CERTIFICATE_REQUEST [optional]
+            //              HS_SERVER_HELLO_DONE
+            //
+            // Note that this state may have an alternative option.
+
+            // Check and update the present state.
+            while (!upcomingStates.isEmpty()) {
+                HandshakeState handshakeState = upcomingStates.pop();
+                if (handshakeState.handshakeType == handshakeType) {
+                    hasPresentState = true;
+
+                    // The current state should be HS_CLIENT_CERTIFICATE or
+                    // HS_SERVER_CERTIFICATE.
+                    //
+                    // Note that we won't put HS_CLIENT_CERTIFICATE into
+                    // the alternative list.
+                    if ((handshakeState != HS_CLIENT_CERTIFICATE) &&
+                            (handshakeState != HS_SERVER_CERTIFICATE)) {
+                        throw new SSLProtocolException(exceptionMsg);
+                    }
+
+                    // Is it an expected client Certificate message?
+                    boolean isClientMessage = false;
+                    if (!upcomingStates.isEmpty()) {
+                        // If the next expected message is ClientKeyExchange,
+                        // this one should be an expected client Certificate
+                        // message.
+                        HandshakeState nextState = upcomingStates.getFirst();
+                        if (nextState == HS_CLIENT_KEY_EXCHANGE) {
+                            isClientMessage = true;
+                        }
+                    }
+
+                    if (isClientMessage) {
+                        if (handshakeState != HS_CLIENT_CERTIFICATE) {
+                            throw new SSLProtocolException(exceptionMsg);
+                        }
+
+                        // Not support CertificateURL extension yet.
+                        /*******************************************
+                        // clear up the alternatives list
+                        if (!alternatives.isEmpty()) {
+                            HandshakeState alternative = alternatives.pop();
+
+                            if (alternative != HS_CERTIFICATE_URL) {
+                                throw new SSLProtocolException(exceptionMsg);
+                            }
+                        }
+                        ********************************************/
+                    } else {
+                        if ((handshakeState != HS_SERVER_CERTIFICATE)) {
+                            throw new SSLProtocolException(exceptionMsg);
+                        }
+                    }
+
+                    break;
+                } else if (!handshakeState.isOptional) {
+                    throw new SSLProtocolException(exceptionMsg);
+                }   // Otherwise, looking for next state track.
+            }
+
+            // No present state.
+            if (!hasPresentState) {
+                throw new SSLProtocolException(exceptionMsg);
+            }
+
+            // no new upcoming states.
+
+            break;
+
+        // Not support CertificateURL extension yet.
+        /*************************************************/
+        case HandshakeMessage.ht_certificate_url:
+            //
+            // State machine:
+            //     PRESENT: HS_CERTIFICATE_URL or
+            //              HS_CLIENT_CERTIFICATE
+            //        TO  : HS_CLIENT_KEY_EXCHANGE
+            //
+            // Note that this state may have an alternative option.
+
+            // Check and update the present state.
+            while (!upcomingStates.isEmpty()) {
+                // The current state should be HS_CLIENT_CERTIFICATE.
+                //
+                // Note that we won't put HS_CLIENT_CERTIFICATE into
+                // the alternative list.
+                HandshakeState handshakeState = upcomingStates.pop();
+                if (handshakeState.handshakeType ==
+                        HS_CLIENT_CERTIFICATE.handshakeType) {
+                    hasPresentState = true;
+
+                    // Look for HS_CERTIFICATE_URL state track.
+                    if (!alternatives.isEmpty()) {
+                        HandshakeState alternative = alternatives.pop();
+
+                        if (alternative != HS_CERTIFICATE_URL) {
+                            throw new SSLProtocolException(exceptionMsg);
+                        }
+                    } else {
+                        // No alternative CertificateUR state track.
+                        throw new SSLProtocolException(exceptionMsg);
+                    }
+
+                    if ((handshakeState != HS_CLIENT_CERTIFICATE)) {
+                        throw new SSLProtocolException(exceptionMsg);
+                    }
+
+                    break;
+                } else if (!handshakeState.isOptional) {
+                    throw new SSLProtocolException(exceptionMsg);
+                }   // Otherwise, looking for next state track.
+
+            }
+
+            // No present state.
+            if (!hasPresentState) {
+                // No present state.
+                throw new SSLProtocolException(exceptionMsg);
+            }
+
+            // no new upcoming states.
+
+            break;
+        /*************************************************/
+
+        default:
+            // Check and update the present state.
+            while (!upcomingStates.isEmpty()) {
+                HandshakeState handshakeState = upcomingStates.pop();
+                if (handshakeState.handshakeType == handshakeType) {
+                    hasPresentState = true;
+                    break;
+                } else if (!handshakeState.isOptional) {
+                    throw new SSLProtocolException(exceptionMsg);
+                }   // Otherwise, looking for next state track.
+            }
+
+            // No present state.
+            if (!hasPresentState) {
+                throw new SSLProtocolException(exceptionMsg);
+            }
+
+            // no new upcoming states.
+        }
+
+        if (debugIsOn) {
+            for (HandshakeState handshakeState : upcomingStates) {
+                System.out.println(
+                    "upcoming handshake states: " + handshakeState);
+            }
+            for (HandshakeState handshakeState : alternatives) {
+                System.out.println(
+                    "upcoming handshake alternative state: " + handshakeState);
+            }
+        }
+    }
+
+    void changeCipherSpec(boolean isInput,
+            boolean isClient) throws SSLProtocolException {
+
+        if (debugIsOn) {
+            System.out.println(
+                    "update handshake state: change_cipher_spec");
+        }
+
+        String exceptionMsg = "ChangeCipherSpec message sequence violation";
+
+        HandshakeState expectedState;
+        if ((isClient && isInput) || (!isClient && !isInput)) {
+            expectedState = HS_SERVER_CHANGE_CIPHER_SPEC;
+        } else {
+            expectedState = HS_CLIENT_CHANGE_CIPHER_SPEC;
+        }
+
+        boolean hasPresentState = false;
+
+        // Check and update the present state.
+        while (!upcomingStates.isEmpty()) {
+            HandshakeState handshakeState = upcomingStates.pop();
+            if (handshakeState == expectedState) {
+                hasPresentState = true;
+                break;
+            } else if (!handshakeState.isOptional) {
+                throw new SSLProtocolException(exceptionMsg);
+            }   // Otherwise, looking for next state track.
+        }
+
+        // No present state.
+        if (!hasPresentState) {
+            throw new SSLProtocolException(exceptionMsg);
+        }
+
+        // no new upcoming states.
+
+        if (debugIsOn) {
+            for (HandshakeState handshakeState : upcomingStates) {
+                System.out.println(
+                    "upcoming handshake states: " + handshakeState);
+            }
+            for (HandshakeState handshakeState : alternatives) {
+                System.out.println(
+                    "upcoming handshake alternative state: " + handshakeState);
+            }
+        }
+    }
+
+    private static String toString(byte handshakeType) {
+        String s = handshakeTypes.get(handshakeType);
+        if (s == null) {
+            s = "unknown";
+        }
+        return (s + "[" + handshakeType + "]");
+    }
+}
+
--- a/jdk/src/java.base/share/classes/sun/security/ssl/Handshaker.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/Handshaker.java	Wed Jul 05 20:37:09 2017 +0200
@@ -29,6 +29,7 @@
 import java.io.*;
 import java.util.*;
 import java.security.*;
+import java.nio.ByteBuffer;
 import java.security.NoSuchAlgorithmException;
 import java.security.AccessController;
 import java.security.AlgorithmConstraints;
@@ -83,7 +84,7 @@
     private CipherSuiteList     enabledCipherSuites;
 
     // The endpoint identification protocol
-    String              identificationProtocol;
+    String                      identificationProtocol;
 
     // The cryptographic algorithm constraints
     private AlgorithmConstraints    algorithmConstraints = null;
@@ -109,12 +110,15 @@
      * Active cipher suites is a subset of enabled cipher suites, and will
      * contain only those cipher suites available for the active protocols.
      */
-    private CipherSuiteList    activeCipherSuites;
+    private CipherSuiteList     activeCipherSuites;
 
     // The server name indication and matchers
     List<SNIServerName> serverNames = Collections.<SNIServerName>emptyList();
     Collection<SNIMatcher> sniMatchers = Collections.<SNIMatcher>emptyList();
 
+    // The maximum expected network packet size for SSL/TLS/DTLS records.
+    int                         maximumPacketSize = 0;
+
     private boolean             isClient;
     private boolean             needCertVerify;
 
@@ -124,11 +128,16 @@
     HandshakeHash               handshakeHash;
     HandshakeInStream           input;
     HandshakeOutStream          output;
-    int                         state;
     SSLContextImpl              sslContext;
     RandomCookie                clnt_random, svr_random;
     SSLSessionImpl              session;
 
+    HandshakeStateManager       handshakeState;
+    boolean                     clientHelloDelivered;
+    boolean                     serverHelloRequested;
+    boolean                     handshakeActivated;
+    boolean                     handshakeFinished;
+
     // current CipherSuite. Never null, initially SSL_NULL_WITH_NULL_NULL
     CipherSuite         cipherSuite;
 
@@ -141,10 +150,6 @@
     // True if it's OK to start a new SSL session
     boolean             enableNewSession;
 
-    // True if session keys have been calculated and the caller may receive
-    // and process a ChangeCipherSpec message
-    private boolean sessKeysCalculated;
-
     // Whether local cipher suites preference should be honored during
     // handshaking?
     //
@@ -207,12 +212,18 @@
     // need to dispose the object when it is invalidated
     boolean invalidated;
 
+    /*
+     * Is this an instance for Datagram Transport Layer Security (DTLS)?
+     */
+    final boolean isDTLS;
+
     Handshaker(SSLSocketImpl c, SSLContextImpl context,
             ProtocolList enabledProtocols, boolean needCertVerify,
             boolean isClient, ProtocolVersion activeProtocolVersion,
             boolean isInitialHandshake, boolean secureRenegotiation,
             byte[] clientVerifyData, byte[] serverVerifyData) {
         this.conn = c;
+        this.isDTLS = false;
         init(context, enabledProtocols, needCertVerify, isClient,
             activeProtocolVersion, isInitialHandshake, secureRenegotiation,
             clientVerifyData, serverVerifyData);
@@ -222,8 +233,10 @@
             ProtocolList enabledProtocols, boolean needCertVerify,
             boolean isClient, ProtocolVersion activeProtocolVersion,
             boolean isInitialHandshake, boolean secureRenegotiation,
-            byte[] clientVerifyData, byte[] serverVerifyData) {
+            byte[] clientVerifyData, byte[] serverVerifyData,
+            boolean isDTLS) {
         this.engine = engine;
+        this.isDTLS = isDTLS;
         init(context, enabledProtocols, needCertVerify, isClient,
             activeProtocolVersion, isInitialHandshake, secureRenegotiation,
             clientVerifyData, serverVerifyData);
@@ -251,9 +264,13 @@
         this.secureRenegotiation = secureRenegotiation;
         this.clientVerifyData = clientVerifyData;
         this.serverVerifyData = serverVerifyData;
-        enableNewSession = true;
-        invalidated = false;
-        sessKeysCalculated = false;
+        this.enableNewSession = true;
+        this.invalidated = false;
+        this.handshakeState = new HandshakeStateManager(isDTLS);
+        this.clientHelloDelivered = false;
+        this.serverHelloRequested = false;
+        this.handshakeActivated = false;
+        this.handshakeFinished = false;
 
         setCipherSuite(CipherSuite.C_NULL);
         setEnabledProtocols(enabledProtocols);
@@ -263,22 +280,6 @@
         } else {        // engine != null
             algorithmConstraints = new SSLAlgorithmConstraints(engine, true);
         }
-
-
-        //
-        // In addition to the connection state machine, controlling
-        // how the connection deals with the different sorts of records
-        // that get sent (notably handshake transitions!), there's
-        // also a handshaking state machine that controls message
-        // sequencing.
-        //
-        // It's a convenient artifact of the protocol that this can,
-        // with only a couple of minor exceptions, be driven by the
-        // type constant for the last message seen:  except for the
-        // client's cert verify, those constants are in a convenient
-        // order to drastically simplify state machine checking.
-        //
-        state = -2;  // initialized but not activated
     }
 
     /*
@@ -360,14 +361,6 @@
         }
     }
 
-    final boolean receivedChangeCipherSpec() {
-        if (conn != null) {
-            return conn.receivedChangeCipherSpec();
-        } else {
-            return engine.receivedChangeCipherSpec();
-        }
-    }
-
     String getEndpointIdentificationAlgorithmSE() {
         SSLParameters paras;
         if (conn != null) {
@@ -395,8 +388,6 @@
     void setVersion(ProtocolVersion protocolVersion) {
         this.protocolVersion = protocolVersion;
         setVersionSE(protocolVersion);
-
-        output.r.setVersion(protocolVersion);
     }
 
     /**
@@ -483,6 +474,13 @@
     }
 
     /**
+     * Sets the maximum packet size of the handshaking.
+     */
+    void setMaximumPacketSize(int maximumPacketSize) {
+        this.maximumPacketSize = maximumPacketSize;
+    }
+
+    /**
      * Sets the cipher suites preference.
      */
     void setUseCipherSuitesOrder(boolean on) {
@@ -532,23 +530,29 @@
         handshakeHash = new HandshakeHash(needCertVerify);
 
         // Generate handshake input/output stream.
-        input = new HandshakeInStream(handshakeHash);
         if (conn != null) {
-            output = new HandshakeOutStream(protocolVersion, helloVersion,
-                                        handshakeHash, conn);
-            conn.getAppInputStream().r.setHandshakeHash(handshakeHash);
-            conn.getAppInputStream().r.setHelloVersion(helloVersion);
-            conn.getAppOutputStream().r.setHelloVersion(helloVersion);
-        } else {
-            output = new HandshakeOutStream(protocolVersion, helloVersion,
-                                        handshakeHash, engine);
+            input = new HandshakeInStream();
+            output = new HandshakeOutStream(conn.outputRecord);
+
+            conn.inputRecord.setHandshakeHash(handshakeHash);
+            conn.inputRecord.setHelloVersion(helloVersion);
+
+            conn.outputRecord.setHandshakeHash(handshakeHash);
+            conn.outputRecord.setHelloVersion(helloVersion);
+            conn.outputRecord.setVersion(protocolVersion);
+        } else if (engine != null) {
+            input = new HandshakeInStream();
+            output = new HandshakeOutStream(engine.outputRecord);
+
             engine.inputRecord.setHandshakeHash(handshakeHash);
             engine.inputRecord.setHelloVersion(helloVersion);
+
+            engine.outputRecord.setHandshakeHash(handshakeHash);
             engine.outputRecord.setHelloVersion(helloVersion);
+            engine.outputRecord.setVersion(protocolVersion);
         }
 
-        // move state to activated
-        state = -1;
+        handshakeActivated = true;
     }
 
     /**
@@ -637,15 +641,15 @@
             if (!(activeProtocols.collection().isEmpty()) &&
                     activeProtocols.min.v != ProtocolVersion.NONE.v) {
                 for (CipherSuite suite : enabledCipherSuites.collection()) {
-                    if (suite.obsoleted > activeProtocols.min.v &&
-                            suite.supported <= activeProtocols.max.v) {
+                    if (!activeProtocols.min.obsoletes(suite) &&
+                            activeProtocols.max.supports(suite)) {
                         if (algorithmConstraints.permits(
                                 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
                                 suite.name, null)) {
                             suites.add(suite);
                         }
                     } else if (debug != null && Debug.isOn("verbose")) {
-                        if (suite.obsoleted <= activeProtocols.min.v) {
+                        if (activeProtocols.min.obsoletes(suite)) {
                             System.out.println(
                                 "Ignoring obsoleted cipher suite: " + suite);
                         } else {
@@ -700,8 +704,8 @@
 
                 boolean found = false;
                 for (CipherSuite suite : enabledCipherSuites.collection()) {
-                    if (suite.isAvailable() && suite.obsoleted > protocol.v &&
-                                               suite.supported <= protocol.v) {
+                    if (suite.isAvailable() && (!protocol.obsoletes(suite)) &&
+                                               protocol.supports(suite)) {
                         if (algorithmConstraints.permits(
                                 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
                                 suite.name, null)) {
@@ -837,7 +841,7 @@
      * this freshly created session can become the current one.
      */
     boolean isDone() {
-        return state == HandshakeMessage.ht_finished;
+        return started() && handshakeState.isEmpty() && handshakeFinished;
     }
 
 
@@ -861,6 +865,14 @@
         }
     }
 
+    void expectingFinishFlightSE() {
+        if (conn != null) {
+            conn.expectingFinishFlight();
+        } else {
+            engine.expectingFinishFlight();
+        }
+    }
+
     /*
      * Returns true if renegotiation is in use for this connection.
      */
@@ -886,8 +898,8 @@
      * This routine is fed SSL handshake records when they become available,
      * and processes messages found therein.
      */
-    void process_record(InputRecord r, boolean expectingFinished)
-            throws IOException {
+    void processRecord(ByteBuffer record,
+            boolean expectingFinished) throws IOException {
 
         checkThrown();
 
@@ -895,7 +907,7 @@
          * Store the incoming handshake data, then see if we can
          * now process any completed handshake messages
          */
-        input.incomingRecord(r);
+        input.incomingRecord(record);
 
         /*
          * We don't need to create a separate delegatable task
@@ -946,6 +958,13 @@
                 return;
             }
 
+            // Set the flags in the message receiving side.
+            if (messageType == HandshakeMessage.ht_client_hello) {
+                clientHelloDelivered = true;
+            } else if (messageType == HandshakeMessage.ht_hello_request) {
+                serverHelloRequested = true;
+            }
+
             /*
              * Process the message.  We require
              * that processMessage() consumes the entire message.  In
@@ -961,14 +980,16 @@
              * Also, note that hello request messages are never hashed;
              * that includes the hello request header, too.
              */
-            if (messageType == HandshakeMessage.ht_hello_request) {
-                input.reset();
-                processMessage(messageType, messageLen);
-                input.ignore(4 + messageLen);
-            } else {
-                input.mark(messageLen);
-                processMessage(messageType, messageLen);
-                input.digestNow();
+            processMessage(messageType, messageLen);
+
+            // Reload if this message has been reserved.
+            //
+            // Note: in the implementation, only certificate_verify and
+            // finished messages are reserved.
+            if ((messageType == HandshakeMessage.ht_finished) ||
+                (messageType == HandshakeMessage.ht_certificate_verify)) {
+
+                handshakeHash.reload();
             }
         }
     }
@@ -980,29 +1001,29 @@
      * In activated state, the handshaker may not send any messages out.
      */
     boolean activated() {
-        return state >= -1;
+        return handshakeActivated;
     }
 
     /**
      * Returns true iff the handshaker has sent any messages.
      */
     boolean started() {
-        return state >= 0;  // 0: HandshakeMessage.ht_hello_request
-                            // 1: HandshakeMessage.ht_client_hello
+        return (serverHelloRequested || clientHelloDelivered);
     }
 
-
     /*
      * Used to kickstart the negotiation ... either writing a
      * ClientHello or a HelloRequest as appropriate, whichever
      * the subclass returns.  NOP if handshaking's already started.
      */
     void kickstart() throws IOException {
-        if (state >= 0) {
+        if ((isClient && clientHelloDelivered) ||
+                (!isClient && serverHelloRequested)) {
             return;
         }
 
         HandshakeMessage m = getKickstartMessage();
+        handshakeState.update(m, resumingSession);
 
         if (debug != null && Debug.isOn("handshake")) {
             m.print(System.out);
@@ -1010,7 +1031,13 @@
         m.write(output);
         output.flush();
 
-        state = m.messageType();
+        // Set the flags in the message delivering side.
+        int handshakeType = m.messageType();
+        if (handshakeType == HandshakeMessage.ht_hello_request) {
+            serverHelloRequested = true;
+        } else {        // HandshakeMessage.ht_client_hello
+            clientHelloDelivered = true;
+        }
     }
 
     /**
@@ -1052,24 +1079,16 @@
          * We already hold SSLEngine/SSLSocket "this" by virtue
          * of this being called from the readRecord code.
          */
-        OutputRecord r;
-        if (conn != null) {
-            r = new OutputRecord(Record.ct_change_cipher_spec);
-        } else {
-            r = new EngineOutputRecord(Record.ct_change_cipher_spec, engine);
-        }
-
-        r.setVersion(protocolVersion);
-        r.write(1);     // single byte of data
-
         if (conn != null) {
             conn.writeLock.lock();
             try {
-                conn.writeRecord(r);
+                handshakeState.changeCipherSpec(false, isClient);
                 conn.changeWriteCiphers();
                 if (debug != null && Debug.isOn("handshake")) {
                     mesg.print(System.out);
                 }
+
+                handshakeState.update(mesg, resumingSession);
                 mesg.write(output);
                 output.flush();
             } finally {
@@ -1077,19 +1096,25 @@
             }
         } else {
             synchronized (engine.writeLock) {
-                engine.writeRecord((EngineOutputRecord)r);
+                handshakeState.changeCipherSpec(false, isClient);
                 engine.changeWriteCiphers();
                 if (debug != null && Debug.isOn("handshake")) {
                     mesg.print(System.out);
                 }
+
+                handshakeState.update(mesg, resumingSession);
                 mesg.write(output);
-
-                if (lastMessage) {
-                    output.setFinishedMsg();
-                }
                 output.flush();
             }
         }
+
+        if (lastMessage) {
+            handshakeFinished = true;
+        }
+    }
+
+    void receiveChangeCipherSpec() throws IOException {
+        handshakeState.changeCipherSpec(true, isClient);
     }
 
     /*
@@ -1131,12 +1156,31 @@
         String masterAlg;
         PRF prf;
 
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
-            masterAlg = "SunTls12MasterSecret";
-            prf = cipherSuite.prfAlg;
+        byte majorVersion = protocolVersion.major;
+        byte minorVersion = protocolVersion.minor;
+        if (protocolVersion.isDTLSProtocol()) {
+            // Use TLS version number for DTLS key calculation
+            if (protocolVersion.v == ProtocolVersion.DTLS10.v) {
+                majorVersion = ProtocolVersion.TLS11.major;
+                minorVersion = ProtocolVersion.TLS11.minor;
+
+                masterAlg = "SunTlsMasterSecret";
+                prf = P_NONE;
+            } else {    // DTLS 1.2
+                majorVersion = ProtocolVersion.TLS12.major;
+                minorVersion = ProtocolVersion.TLS12.minor;
+
+                masterAlg = "SunTls12MasterSecret";
+                prf = cipherSuite.prfAlg;
+            }
         } else {
-            masterAlg = "SunTlsMasterSecret";
-            prf = P_NONE;
+            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                masterAlg = "SunTls12MasterSecret";
+                prf = cipherSuite.prfAlg;
+            } else {
+                masterAlg = "SunTlsMasterSecret";
+                prf = P_NONE;
+            }
         }
 
         String prfHashAlg = prf.getPRFHashAlg();
@@ -1145,7 +1189,7 @@
 
         @SuppressWarnings("deprecation")
         TlsMasterSecretParameterSpec spec = new TlsMasterSecretParameterSpec(
-                preMasterSecret, protocolVersion.major, protocolVersion.minor,
+                preMasterSecret, (majorVersion & 0xFF), (minorVersion & 0xFF),
                 clnt_random.random_bytes, svr_random.random_bytes,
                 prfHashAlg, prfHashLength, prfBlockSize);
 
@@ -1196,36 +1240,55 @@
         String keyMaterialAlg;
         PRF prf;
 
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
-            keyMaterialAlg = "SunTls12KeyMaterial";
-            prf = cipherSuite.prfAlg;
+        byte majorVersion = protocolVersion.major;
+        byte minorVersion = protocolVersion.minor;
+        if (protocolVersion.isDTLSProtocol()) {
+            // Use TLS version number for DTLS key calculation
+            if (protocolVersion.v == ProtocolVersion.DTLS10.v) {
+                majorVersion = ProtocolVersion.TLS11.major;
+                minorVersion = ProtocolVersion.TLS11.minor;
+
+                keyMaterialAlg = "SunTlsKeyMaterial";
+                prf = P_NONE;
+            } else {    // DTLS 1.2+
+                majorVersion = ProtocolVersion.TLS12.major;
+                minorVersion = ProtocolVersion.TLS12.minor;
+
+                keyMaterialAlg = "SunTls12KeyMaterial";
+                prf = cipherSuite.prfAlg;
+            }
         } else {
-            keyMaterialAlg = "SunTlsKeyMaterial";
-            prf = P_NONE;
+            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                keyMaterialAlg = "SunTls12KeyMaterial";
+                prf = cipherSuite.prfAlg;
+            } else {
+                keyMaterialAlg = "SunTlsKeyMaterial";
+                prf = P_NONE;
+            }
         }
 
         String prfHashAlg = prf.getPRFHashAlg();
         int prfHashLength = prf.getPRFHashLength();
         int prfBlockSize = prf.getPRFBlockSize();
 
-        // TLS v1.1 or later uses an explicit IV in CBC cipher suites to
+        // TLS v1.1+ and DTLS use an explicit IV in CBC cipher suites to
         // protect against the CBC attacks.  AEAD/GCM cipher suites in TLS
         // v1.2 or later use a fixed IV as the implicit part of the partially
         // implicit nonce technique described in RFC 5116.
         int ivSize = cipher.ivSize;
         if (cipher.cipherType == AEAD_CIPHER) {
             ivSize = cipher.fixedIvSize;
-        } else if (protocolVersion.v >= ProtocolVersion.TLS11.v &&
-                cipher.cipherType == BLOCK_CIPHER) {
+        } else if ((cipher.cipherType == BLOCK_CIPHER) &&
+                protocolVersion.useTLS11PlusSpec()) {
             ivSize = 0;
         }
 
         TlsKeyMaterialParameterSpec spec = new TlsKeyMaterialParameterSpec(
-            masterKey, protocolVersion.major, protocolVersion.minor,
-            clnt_random.random_bytes, svr_random.random_bytes,
-            cipher.algorithm, cipher.keySize, expandedKeySize,
-            ivSize, hashSize,
-            prfHashAlg, prfHashLength, prfBlockSize);
+                masterKey, (majorVersion & 0xFF), (minorVersion & 0xFF),
+                clnt_random.random_bytes, svr_random.random_bytes,
+                cipher.algorithm, cipher.keySize, expandedKeySize,
+                ivSize, hashSize,
+                prfHashAlg, prfHashLength, prfBlockSize);
 
         try {
             KeyGenerator kg = JsseJce.getKeyGenerator(keyMaterialAlg);
@@ -1247,10 +1310,6 @@
             throw new ProviderException(e);
         }
 
-        // Mark a flag that allows outside entities (like SSLSocket/SSLEngine)
-        // determine if a ChangeCipherSpec message could be processed.
-        sessKeysCalculated = true;
-
         //
         // Dump the connection keys as they're generated.
         //
@@ -1293,7 +1352,7 @@
                     System.out.println("Server write IV:");
                     printHex(dump, svrWriteIV.getIV());
                 } else {
-                    if (protocolVersion.v >= ProtocolVersion.TLS11.v) {
+                    if (protocolVersion.useTLS11PlusSpec()) {
                         System.out.println(
                                 "... no IV derived for this protocol");
                     } else {
@@ -1305,15 +1364,6 @@
         }
     }
 
-    /**
-     * Return whether or not the Handshaker has derived session keys for
-     * this handshake.  This is used for determining readiness to process
-     * an incoming ChangeCipherSpec message.
-     */
-    boolean sessionKeysCalculated() {
-        return sessKeysCalculated;
-    }
-
     private static void printHex(HexDumpEncoder dump, byte[] bytes) {
         if (bytes == null) {
             System.out.println("(key bytes not available)");
@@ -1326,19 +1376,6 @@
         }
     }
 
-    /**
-     * Throw an SSLException with the specified message and cause.
-     * Shorthand until a new SSLException constructor is added.
-     * This method never returns.
-     */
-    static void throwSSLException(String msg, Throwable cause)
-            throws SSLException {
-        SSLException e = new SSLException(msg);
-        e.initCause(cause);
-        throw e;
-    }
-
-
     /*
      * Implement a simple task delegator.
      *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/HelloCookieManager.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.security.ssl;
+
+import java.io.IOException;
+import javax.net.ssl.SSLProtocolException;
+import java.security.MessageDigest;
+import java.security.SecureRandom;
+
+import sun.security.ssl.HandshakeMessage.ClientHello;
+
+/*
+ * HelloVerifyRequest cookie manager
+ */
+final class HelloCookieManager {
+    // the cookie secret life time
+    private static long COOKIE_TIMING_WINDOW = 3600000;     // in milliseconds
+    private static int  COOKIE_MAX_LENGTH_DTLS10 = 32;      // 32 bytes
+    private static int  COOKIE_MAX_LENGTH_DTLS12 = 0xFF;    // 2^8 -1 bytes
+
+    private final SecureRandom          secureRandom;
+    private final MessageDigest         cookieDigest;
+
+    private int                         cookieVersion;      // allow to wrap
+    private long                        secretLifetime;
+    private byte[]                      cookieSecret;
+
+    private int                         prevCookieVersion;
+    private byte[]                      prevCookieSecret;
+
+    HelloCookieManager(SecureRandom secureRandom) {
+        this.secureRandom = secureRandom;
+        this.cookieDigest = JsseJce.getMessageDigest("SHA-256");
+
+        this.cookieVersion = secureRandom.nextInt();
+        this.secretLifetime = 0;
+        this.cookieSecret = null;
+
+        this.prevCookieVersion = 0;
+        this.prevCookieSecret = null;
+    }
+
+    // Used by server side to generate cookies in HelloVerifyRequest message.
+    synchronized byte[] getCookie(ClientHello clientHelloMsg) {
+        if (secretLifetime < System.currentTimeMillis()) {
+            if (cookieSecret != null) {
+                prevCookieVersion = cookieVersion;
+                prevCookieSecret = cookieSecret.clone();
+            } else {
+                cookieSecret = new byte[32];
+            }
+
+            cookieVersion++;
+            secureRandom.nextBytes(cookieSecret);
+            secretLifetime = System.currentTimeMillis() + COOKIE_TIMING_WINDOW;
+        }
+
+        clientHelloMsg.updateHelloCookie(cookieDigest);
+        byte[] cookie = cookieDigest.digest(cookieSecret);      // 32 bytes
+        cookie[0] = (byte)((cookieVersion >> 24) & 0xFF);
+        cookie[1] = (byte)((cookieVersion >> 16) & 0xFF);
+        cookie[2] = (byte)((cookieVersion >> 8) & 0xFF);
+        cookie[3] = (byte)(cookieVersion & 0xFF);
+
+        return cookie;
+    }
+
+    // Used by server side to check the cookie in ClientHello message.
+    synchronized boolean isValid(ClientHello clientHelloMsg) {
+        byte[] cookie = clientHelloMsg.cookie;
+
+        // no cookie exchange or not a valid cookie length
+        if ((cookie == null) || (cookie.length != 32)) {
+            return false;
+        }
+
+        int version = ((cookie[0] & 0xFF) << 24) |
+                      ((cookie[1] & 0xFF) << 16) |
+                      ((cookie[2] & 0xFF) << 8) |
+                       (cookie[3] & 0xFF);
+
+        byte[] secret;
+        if (version == cookieVersion) {
+            secret = cookieSecret;
+        } else if (version == prevCookieVersion) {
+            secret = prevCookieSecret;
+        } else {
+            return false;       // may be out of the timing window
+        }
+
+        clientHelloMsg.updateHelloCookie(cookieDigest);
+        byte[] target = cookieDigest.digest(secret);            // 32 bytes
+
+        for (int i = 4; i < 32; i++) {
+            if (cookie[i] != target[i]) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    // Used by client side to check the cookie in HelloVerifyRequest message.
+    static void checkCookie(ProtocolVersion protocolVersion,
+            byte[] cookie) throws IOException {
+        if (cookie != null && cookie.length != 0) {
+            int limit = COOKIE_MAX_LENGTH_DTLS12;
+            if (protocolVersion.v == ProtocolVersion.DTLS10.v) {
+                limit = COOKIE_MAX_LENGTH_DTLS10;
+            }
+
+            if (cookie.length > COOKIE_MAX_LENGTH_DTLS10) {
+                throw new SSLProtocolException(
+                        "Invalid HelloVerifyRequest.cookie (length = " +
+                         cookie.length + " bytes)");
+            }
+        }
+
+        // Otherwise, no cookie exchange.
+    }
+}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/HelloExtensions.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/HelloExtensions.java	Wed Jul 05 20:37:09 2017 +0200
@@ -85,6 +85,8 @@
                         new SupportedEllipticPointFormatsExtension(s, extlen);
             } else if (extType == ExtensionType.EXT_RENEGOTIATION_INFO) {
                 extension = new RenegotiationInfoExtension(s, extlen);
+            } else if (extType == ExtensionType.EXT_MAX_FRAGMENT_LENGTH) {
+                extension = new MaxFragmentLengthExtension(s, extlen);
             } else {
                 extension = new UnknownExtension(s, extlen, extType);
             }
--- a/jdk/src/java.base/share/classes/sun/security/ssl/InputRecord.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/InputRecord.java	Wed Jul 05 20:37:09 2017 +0200
@@ -23,11 +23,11 @@
  * questions.
  */
 
-
 package sun.security.ssl;
 
 import java.io.*;
 import java.nio.*;
+import java.util.*;
 
 import javax.crypto.BadPaddingException;
 
@@ -37,66 +37,35 @@
 
 
 /**
- * SSL 3.0 records, as pulled off a TCP stream.  Input records are
- * basically buffers tied to a particular input stream ... a layer
- * above this must map these records into the model of a continuous
- * stream of data.
- *
- * Since this returns SSL 3.0 records, it's the layer that needs to
- * map SSL 2.0 style handshake records into SSL 3.0 ones for those
- * "old" clients that interop with both V2 and V3 servers.  Not as
- * pretty as might be desired.
- *
- * NOTE:  During handshaking, each message must be hashed to support
- * verification that the handshake process wasn't compromised.
+ * {@code InputRecord} takes care of the management of SSL/TLS/DTLS input
+ * records, including buffering, decryption, handshake messages marshal, etc.
  *
  * @author David Brownell
  */
-class InputRecord extends ByteArrayInputStream implements Record {
+class InputRecord implements Record, Closeable {
+
+    /* Class and subclass dynamic debugging support */
+    static final Debug debug = Debug.getInstance("ssl");
 
-    private HandshakeHash       handshakeHash;
-    private int                 lastHashed;
-    boolean                     formatVerified = true;  // SSLv2 ruled out?
-    private boolean             isClosed;
-    private boolean             appDataValid;
+    Authenticator       readAuthenticator;
+    CipherBox           readCipher;
+
+    HandshakeHash       handshakeHash;
+    boolean             isClosed;
 
     // The ClientHello version to accept. If set to ProtocolVersion.SSL20Hello
     // and the first message we read is a ClientHello in V2 format, we convert
     // it to V3. Otherwise we throw an exception when encountering a V2 hello.
-    private ProtocolVersion     helloVersion;
-
-    /* Class and subclass dynamic debugging support */
-    static final Debug debug = Debug.getInstance("ssl");
+    ProtocolVersion     helloVersion;
 
-    /* The existing record length */
-    private int exlen;
-
-    /* V2 handshake message */
-    private byte v2Buf[];
+    // fragment size
+    int                 fragmentSize;
 
-    /*
-     * Construct the record to hold the maximum sized input record.
-     * Data will be filled in separately.
-     *
-     * The structure of the byte buffer looks like:
-     *
-     *     |--------+---------+---------------------------------|
-     *     | header |   IV    | content, MAC/TAG, padding, etc. |
-     *     | headerPlusIVSize |
-     *
-     * header: the header of an SSL records
-     * IV:     the optional IV/nonce field, it is only required for block
-     *         (TLS 1.1 or later) and AEAD cipher suites.
-     *
-     */
     InputRecord() {
-        super(new byte[maxRecordSize]);
-        setHelloVersion(ProtocolVersion.DEFAULT_HELLO);
-        pos = headerSize;
-        count = headerSize;
-        lastHashed = count;
-        exlen = 0;
-        v2Buf = null;
+        this.readCipher = CipherBox.NULL;
+        this.readAuthenticator = null;      // Please override this assignment.
+        this.helloVersion = ProtocolVersion.DEFAULT_HELLO;
+        this.fragmentSize = Record.maxDataSize;
     }
 
     void setHelloVersion(ProtocolVersion helloVersion) {
@@ -108,70 +77,332 @@
     }
 
     /*
-     * Enable format checks if initial handshaking hasn't completed
-     */
-    void enableFormatChecks() {
-        formatVerified = false;
-    }
-
-    // return whether the data in this record is valid, decrypted data
-    boolean isAppDataValid() {
-        return appDataValid;
-    }
-
-    void setAppDataValid(boolean value) {
-        appDataValid = value;
-    }
-
-    /*
-     * Return the content type of the record.
-     */
-    byte contentType() {
-        return buf[0];
-    }
-
-    /*
+     * Set instance for the computation of handshake hashes.
+     *
      * For handshaking, we need to be able to hash every byte above the
      * record marking layer.  This is where we're guaranteed to see those
      * bytes, so this is where we can hash them ... especially in the
      * case of hashing the initial V2 message!
      */
     void setHandshakeHash(HandshakeHash handshakeHash) {
+        if (handshakeHash != null) {
+            byte[] reserved = null;
+            if (this.handshakeHash != null) {
+                reserved = this.handshakeHash.getAllHandshakeMessages();
+            }
+            if ((reserved != null) && (reserved.length != 0)) {
+                handshakeHash.update(reserved, 0, reserved.length);
+
+               if (debug != null && Debug.isOn("data")) {
+                    Debug.printHex(
+                        "[reserved] handshake hash: len = " + reserved.length,
+                        reserved);
+               }
+            }
+        }
+
         this.handshakeHash = handshakeHash;
     }
 
-    HandshakeHash getHandshakeHash() {
-        return handshakeHash;
+    boolean seqNumIsHuge() {
+        return (readAuthenticator != null) &&
+                        readAuthenticator.seqNumIsHuge();
+    }
+
+    boolean isEmpty() {
+        return false;
+    }
+
+    // apply to DTLS SSLEngine
+    void expectingFinishFlight() {
+        // blank
+    }
+
+    /**
+     * Prevent any more data from being read into this record,
+     * and flag the record as holding no data.
+     */
+    @Override
+    synchronized public void close() throws IOException {
+        if (!isClosed) {
+            isClosed = true;
+            readCipher.dispose();
+        }
+    }
+
+    // apply to SSLSocket and SSLEngine
+    void changeReadCiphers(
+            Authenticator readAuthenticator, CipherBox readCipher) {
+
+        /*
+         * Dispose of any intermediate state in the underlying cipher.
+         * For PKCS11 ciphers, this will release any attached sessions,
+         * and thus make finalization faster.
+         *
+         * Since MAC's doFinal() is called for every SSL/TLS packet, it's
+         * not necessary to do the same with MAC's.
+         */
+        readCipher.dispose();
+
+        this.readAuthenticator = readAuthenticator;
+        this.readCipher = readCipher;
+    }
+
+    // change fragment size
+    void changeFragmentSize(int fragmentSize) {
+        this.fragmentSize = fragmentSize;
+    }
+
+    /*
+     * Check if there is enough inbound data in the ByteBuffer to make
+     * a inbound packet.
+     *
+     * @return -1 if there are not enough bytes to tell (small header),
+     */
+    // apply to SSLEngine only
+    int bytesInCompletePacket(ByteBuffer buf) throws SSLException {
+        throw new UnsupportedOperationException();
+    }
+
+    // apply to SSLSocket only
+    int bytesInCompletePacket(InputStream is) throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Return true if the specified record protocol version is out of the
+     * range of the possible supported versions.
+     */
+    void checkRecordVersion(ProtocolVersion version,
+            boolean allowSSL20Hello) throws SSLException {
+        // blank
+    }
+
+    // apply to DTLS SSLEngine only
+    Plaintext acquirePlaintext()
+            throws IOException, BadPaddingException {
+        throw new UnsupportedOperationException();
+    }
+
+    // read, decrypt and decompress the network record.
+    //
+    // apply to SSLEngine only
+    Plaintext decode(ByteBuffer netData)
+            throws IOException, BadPaddingException {
+        throw new UnsupportedOperationException();
+    }
+
+    // apply to SSLSocket only
+    Plaintext decode(InputStream is, ByteBuffer destination)
+            throws IOException, BadPaddingException {
+        throw new UnsupportedOperationException();
+    }
+
+    // apply to SSLSocket only
+    void setDeliverStream(OutputStream outputStream) {
+        throw new UnsupportedOperationException();
+    }
+
+    // calculate plaintext fragment size
+    //
+    // apply to SSLEngine only
+    int estimateFragmentSize(int packetSize) {
+        throw new UnsupportedOperationException();
     }
 
-    void decrypt(Authenticator authenticator,
-            CipherBox box) throws BadPaddingException {
+    //
+    // shared helpers
+    //
+
+    // Not apply to DTLS
+    static ByteBuffer convertToClientHello(ByteBuffer packet) {
+
+        int srcPos = packet.position();
+        int srcLim = packet.limit();
+
+        byte firstByte = packet.get();
+        byte secondByte = packet.get();
+        int recordLen = (((firstByte & 0x7F) << 8) | (secondByte & 0xFF)) + 2;
+
+        packet.position(srcPos + 3);        // the V2ClientHello record header
+
+        byte majorVersion = packet.get();
+        byte minorVersion = packet.get();
+
+        int cipherSpecLen = ((packet.get() & 0xFF) << 8) +
+                             (packet.get() & 0xFF);
+        int sessionIdLen  = ((packet.get() & 0xFF) << 8) +
+                             (packet.get() & 0xFF);
+        int nonceLen      = ((packet.get() & 0xFF) << 8) +
+                             (packet.get() & 0xFF);
+
+        // Required space for the target SSLv3 ClientHello message.
+        //  5: record header size
+        //  4: handshake header size
+        //  2: ClientHello.client_version
+        // 32: ClientHello.random
+        //  1: length byte of ClientHello.session_id
+        //  2: empty ClientHello.compression_methods
+        int requiredSize = 46 + sessionIdLen + ((cipherSpecLen * 2 ) / 3 );
+        byte[] converted = new byte[requiredSize];
+
+        /*
+         * Build the first part of the V3 record header from the V2 one
+         * that's now buffered up.  (Lengths are fixed up later).
+         */
+        // Note: need not to set the header actually.
+        converted[0] = ct_handshake;
+        converted[1] = majorVersion;
+        converted[2] = minorVersion;
+        // header [3..4] for handshake message length
+        // required size is 5;
+
+        /*
+         * Store the generic V3 handshake header:  4 bytes
+         */
+        converted[5] = 1;    // HandshakeMessage.ht_client_hello
+        // buf [6..8] for length of ClientHello (int24)
+        // required size += 4;
+
+        /*
+         * ClientHello header starts with SSL version
+         */
+        converted[9] = majorVersion;
+        converted[10] = minorVersion;
+        // required size += 2;
+        int pointer = 11;
+
+        /*
+         * Copy Random value/nonce ... if less than the 32 bytes of
+         * a V3 "Random", right justify and zero pad to the left.  Else
+         * just take the last 32 bytes.
+         */
+        int offset = srcPos + 11 + cipherSpecLen + sessionIdLen;
+
+        if (nonceLen < 32) {
+            for (int i = 0; i < (32 - nonceLen); i++) {
+                converted[pointer++] = 0;
+            }
+            packet.position(offset);
+            packet.get(converted, pointer, nonceLen);
+
+            pointer += nonceLen;
+        } else {
+            packet.position(offset + nonceLen - 32);
+            packet.get(converted, pointer, 32);
+
+            pointer += 32;
+        }
+
+        /*
+         * Copy session ID (only one byte length!)
+         */
+        offset -= sessionIdLen;
+        converted[pointer++] = (byte)(sessionIdLen & 0xFF);
+        packet.position(offset);
+        packet.get(converted, pointer, sessionIdLen);
+
+        /*
+         * Copy and translate cipher suites ... V2 specs with first byte zero
+         * are really V3 specs (in the last 2 bytes), just copy those and drop
+         * the other ones.  Preference order remains unchanged.
+         *
+         * Example:  Netscape Navigator 3.0 (exportable) says:
+         *
+         * 0/3,     SSL_RSA_EXPORT_WITH_RC4_40_MD5
+         * 0/6,     SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5
+         *
+         * Microsoft Internet Explorer 3.0 (exportable) supports only
+         *
+         * 0/3,     SSL_RSA_EXPORT_WITH_RC4_40_MD5
+         */
+        int j;
+
+        offset -= cipherSpecLen;
+        packet.position(offset);
+
+        j = pointer + 2;
+        for (int i = 0; i < cipherSpecLen; i += 3) {
+            if (packet.get() != 0) {
+                // Ignore version 2.0 specifix cipher suite.  Clients
+                // should also include the version 3.0 equivalent in
+                // the V2ClientHello message.
+                packet.get();           // ignore the 2nd byte
+                packet.get();           // ignore the 3rd byte
+                continue;
+            }
+
+            converted[j++] = packet.get();
+            converted[j++] = packet.get();
+        }
+
+        j -= pointer + 2;
+        converted[pointer++] = (byte)((j >>> 8) & 0xFF);
+        converted[pointer++] = (byte)(j & 0xFF);
+        pointer += j;
+
+        /*
+         * Append compression methods (default/null only)
+         */
+        converted[pointer++] = 1;
+        converted[pointer++] = 0;      // Session.compression_null
+
+        /*
+         * Fill in lengths of the messages we synthesized (nested:
+         * V3 handshake message within V3 record).
+         */
+        // Note: need not to set the header actually.
+        int fragLen = pointer - 5;                      // TLSPlaintext.length
+        converted[3] = (byte)((fragLen >>> 8) & 0xFF);
+        converted[4] = (byte)(fragLen & 0xFF);
+
+        /*
+         * Handshake.length, length of ClientHello message
+         */
+        fragLen = pointer - 9;                          // Handshake.length
+        converted[6] = (byte)((fragLen >>> 16) & 0xFF);
+        converted[7] = (byte)((fragLen >>> 8) & 0xFF);
+        converted[8] = (byte)(fragLen & 0xFF);
+
+        // consume the full record
+        packet.position(srcPos + recordLen);
+
+        // Need no header bytes.
+        return ByteBuffer.wrap(converted, 5, pointer - 5);  // 5: header size
+    }
+
+    static ByteBuffer decrypt(Authenticator authenticator, CipherBox box,
+            byte contentType, ByteBuffer bb) throws BadPaddingException {
+
+        return decrypt(authenticator, box, contentType, bb, null);
+    }
+
+    static ByteBuffer decrypt(Authenticator authenticator,
+            CipherBox box, byte contentType, ByteBuffer bb,
+            byte[] sequence) throws BadPaddingException {
+
         BadPaddingException reservedBPE = null;
         int tagLen =
             (authenticator instanceof MAC) ? ((MAC)authenticator).MAClen() : 0;
-        int cipheredLength = count - headerSize;
-
+        int cipheredLength = bb.remaining();
+        int srcPos = bb.position();
         if (!box.isNullCipher()) {
             try {
                 // apply explicit nonce for AEAD/CBC cipher suites if needed
-                int nonceSize = box.applyExplicitNonce(authenticator,
-                        contentType(), buf, headerSize, cipheredLength);
-                pos = headerSize + nonceSize;
-                lastHashed = pos;   // don't digest the explicit nonce
+                int nonceSize = box.applyExplicitNonce(
+                        authenticator, contentType, bb, sequence);
 
                 // decrypt the content
-                int offset = headerSize;
                 if (box.isAEADMode()) {
-                    // DON'T encrypt the nonce_explicit for AEAD mode
-                    offset += nonceSize;
+                    // DON'T decrypt the nonce_explicit for AEAD mode
+                    bb.position(srcPos + nonceSize);
                 }   // The explicit IV for CBC mode can be decrypted.
 
                 // Note that the CipherBox.decrypt() does not change
                 // the capacity of the buffer.
-                count = offset +
-                    box.decrypt(buf, offset, count - offset, tagLen);
-
-                // Note that we don't remove the nonce from the buffer.
+                box.decrypt(bb, tagLen);
+                // We don't actually remove the nonce.
+                bb.position(srcPos + nonceSize);
             } catch (BadPaddingException bpe) {
                 // RFC 2246 states that decryption_failed should be used
                 // for this purpose. However, that allows certain attacks,
@@ -187,10 +418,9 @@
 
         // Requires message authentication code for null, stream and block
         // cipher suites.
-        if (authenticator instanceof MAC && tagLen != 0) {
+        if ((authenticator instanceof MAC) && (tagLen != 0)) {
             MAC signer = (MAC)authenticator;
-            int macOffset = count - tagLen;
-            int contentLen = macOffset - pos;
+            int contentLen = bb.remaining() - tagLen;
 
             // Note that although it is not necessary, we run the same MAC
             // computation and comparison on the payload for both stream
@@ -202,19 +432,14 @@
                 }
 
                 // set offset of the dummy MAC
-                macOffset = headerSize + cipheredLength - tagLen;
-                contentLen = macOffset - headerSize;
+                contentLen = cipheredLength - tagLen;
+                bb.limit(srcPos + cipheredLength);
             }
 
-            count -= tagLen;  // Set the count before any MAC checking
-                              // exception occurs, so that the following
-                              // process can read the actual decrypted
-                              // content (minus the MAC) in the fragment
-                              // if necessary.
-
             // Run MAC computation and comparison on the payload.
-            if (checkMacTags(contentType(),
-                    buf, pos, contentLen, signer, false)) {
+            //
+            // MAC data would be stripped off during the check.
+            if (checkMacTags(contentType, bb, signer, sequence, false)) {
                 if (reservedBPE == null) {
                     reservedBPE = new BadPaddingException("bad record MAC");
                 }
@@ -229,21 +454,18 @@
                                         signer, cipheredLength, contentLen);
 
                 // NOTE: remainingLen may be bigger (less than 1 block of the
-                // hash algorithm of the MAC) than the cipheredLength. However,
-                // We won't need to worry about it because we always use a
-                // maximum buffer for every record.  We need a change here if
-                // we use small buffer size in the future.
-                if (remainingLen > buf.length) {
-                    // unlikely to happen, just a placehold
-                    throw new RuntimeException(
-                        "Internal buffer capacity error");
-                }
+                // hash algorithm of the MAC) than the cipheredLength.
+                //
+                // Is it possible to use a static buffer, rather than allocate
+                // it dynamically?
+                remainingLen += signer.MAClen();
+                ByteBuffer temporary = ByteBuffer.allocate(remainingLen);
 
                 // Won't need to worry about the result on the remainder. And
                 // then we won't need to worry about what's actual data to
                 // check MAC tag on.  We start the check from the header of the
                 // buffer so that we don't need to construct a new byte buffer.
-                checkMacTags(contentType(), buf, 0, remainingLen, signer, true);
+                checkMacTags(contentType, temporary, signer, sequence, true);
             }
         }
 
@@ -251,6 +473,63 @@
         if (reservedBPE != null) {
             throw reservedBPE;
         }
+
+        return bb.slice();
+    }
+
+    /*
+     * Run MAC computation and comparison
+     *
+     */
+    private static boolean checkMacTags(byte contentType, ByteBuffer bb,
+            MAC signer, byte[] sequence, boolean isSimulated) {
+
+        int tagLen = signer.MAClen();
+        int position = bb.position();
+        int lim = bb.limit();
+        int macOffset = lim - tagLen;
+
+        bb.limit(macOffset);
+        byte[] hash = signer.compute(contentType, bb, sequence, isSimulated);
+        if (hash == null || tagLen != hash.length) {
+            // Something is wrong with MAC implementation.
+            throw new RuntimeException("Internal MAC error");
+        }
+
+        bb.position(macOffset);
+        bb.limit(lim);
+        try {
+            int[] results = compareMacTags(bb, hash);
+            return (results[0] != 0);
+        } finally {
+            // reset to the data
+            bb.position(position);
+            bb.limit(macOffset);
+        }
+    }
+
+    /*
+     * A constant-time comparison of the MAC tags.
+     *
+     * Please DON'T change the content of the ByteBuffer parameter!
+     */
+    private static int[] compareMacTags(ByteBuffer bb, byte[] tag) {
+
+        // An array of hits is used to prevent Hotspot optimization for
+        // the purpose of a constant-time check.
+        int[] results = {0, 0};     // {missed #, matched #}
+
+        // The caller ensures there are enough bytes available in the buffer.
+        // So we won't need to check the remaining of the buffer.
+        for (int i = 0; i < tag.length; i++) {
+            if (bb.get() != tag[i]) {
+                results[0]++;       // mismatched bytes
+            } else {
+                results[1]++;       // matched bytes
+            }
+        }
+
+        return results;
     }
 
     /*
@@ -258,7 +537,7 @@
      *
      * Please DON'T change the content of the byte buffer parameter!
      */
-    static boolean checkMacTags(byte contentType, byte[] buffer,
+    private static boolean checkMacTags(byte contentType, byte[] buffer,
             int offset, int contentLen, MAC signer, boolean isSimulated) {
 
         int tagLen = signer.MAClen();
@@ -304,7 +583,7 @@
      *
      * The caller MUST ensure that the fullLen is not less than usedLen.
      */
-    static int calculateRemainingLen(
+    private static int calculateRemainingLen(
             MAC signer, int fullLen, int usedLen) {
 
         int blockLen = signer.hashBlockLen();
@@ -322,551 +601,7 @@
         // that the return value is positive.  The extra one byte does
         // not impact the overall MAC compression function evaluations.
         return 0x01 + (int)(Math.ceil(fullLen/(1.0d * blockLen)) -
-                Math.ceil(usedLen/(1.0d * blockLen))) * signer.hashBlockLen();
-    }
-
-    /*
-     * Well ... hello_request messages are _never_ hashed since we can't
-     * know when they'd appear in the sequence.
-     */
-    void ignore(int bytes) {
-        if (bytes > 0) {
-            pos += bytes;
-            lastHashed = pos;
-        }
-    }
-
-    /*
-     * We hash the (plaintext) we've processed, but only on demand.
-     *
-     * There is one place where we want to access the hash in the middle
-     * of a record:  client cert message gets hashed, and part of the
-     * same record is the client cert verify message which uses that hash.
-     * So we track how much we've read and hashed.
-     */
-    void doHashes() {
-        int len = pos - lastHashed;
-
-        if (len > 0) {
-            hashInternal(buf, lastHashed, len);
-            lastHashed = pos;
-        }
-    }
-
-    /*
-     * Need a helper function so we can hash the V2 hello correctly
-     */
-    private void hashInternal(byte databuf [], int offset, int len) {
-        if (debug != null && Debug.isOn("data")) {
-            try {
-                HexDumpEncoder hd = new HexDumpEncoder();
-
-                System.out.println("[read] MD5 and SHA1 hashes:  len = "
-                    + len);
-                hd.encodeBuffer(new ByteArrayInputStream(databuf, offset, len),
-                    System.out);
-            } catch (IOException e) { }
-        }
-        handshakeHash.update(databuf, offset, len);
-    }
-
-
-    /*
-     * Handshake messages may cross record boundaries.  We "queue"
-     * these in big buffers if we need to cope with this problem.
-     * This is not anticipated to be a common case; if this turns
-     * out to be wrong, this can readily be sped up.
-     */
-    void queueHandshake(InputRecord r) throws IOException {
-        int len;
-
-        /*
-         * Hash any data that's read but unhashed.
-         */
-        doHashes();
-
-        /*
-         * Move any unread data to the front of the buffer,
-         * flagging it all as unhashed.
-         */
-        if (pos > headerSize) {
-            len = count - pos;
-            if (len != 0) {
-                System.arraycopy(buf, pos, buf, headerSize, len);
-            }
-            pos = headerSize;
-            lastHashed = pos;
-            count = headerSize + len;
-        }
-
-        /*
-         * Grow "buf" if needed
-         */
-        len = r.available() + count;
-        if (buf.length < len) {
-            byte        newbuf [];
-
-            newbuf = new byte [len];
-            System.arraycopy(buf, 0, newbuf, 0, count);
-            buf = newbuf;
-        }
-
-        /*
-         * Append the new buffer to this one.
-         */
-        System.arraycopy(r.buf, r.pos, buf, count, len - count);
-        count = len;
-
-        /*
-         * Adjust lastHashed; important for now with clients which
-         * send SSL V2 client hellos.  This will go away eventually,
-         * by buffer code cleanup.
-         */
-        len = r.lastHashed - r.pos;
-        if (pos == headerSize) {
-            lastHashed += len;
-        } else {
-            throw new SSLProtocolException("?? confused buffer hashing ??");
-        }
-        // we've read the record, advance the pointers
-        r.pos = r.count;
-    }
-
-
-    /**
-     * Prevent any more data from being read into this record,
-     * and flag the record as holding no data.
-     */
-    @Override
-    public void close() {
-        appDataValid = false;
-        isClosed = true;
-        mark = 0;
-        pos = 0;
-        count = 0;
+                Math.ceil(usedLen/(1.0d * blockLen))) * blockLen;
     }
-
-
-    /*
-     * We may need to send this SSL v2 "No Cipher" message back, if we
-     * are faced with an SSLv2 "hello" that's not saying "I talk v3".
-     * It's the only one documented in the V2 spec as a fatal error.
-     */
-    private static final byte[] v2NoCipher = {
-        (byte)0x80, (byte)0x03, // unpadded 3 byte record
-        (byte)0x00,             // ... error message
-        (byte)0x00, (byte)0x01  // ... NO_CIPHER error
-    };
-
-    private int readFully(InputStream s, byte b[], int off, int len)
-            throws IOException {
-        int n = 0;
-        while (n < len) {
-            int readLen = s.read(b, off + n, len - n);
-            if (readLen < 0) {
-                return readLen;
-            }
-
-            if (debug != null && Debug.isOn("packet")) {
-                try {
-                    HexDumpEncoder hd = new HexDumpEncoder();
-                    ByteBuffer bb = ByteBuffer.wrap(b, off + n, readLen);
-
-                    System.out.println("[Raw read]: length = " +
-                        bb.remaining());
-                    hd.encodeBuffer(bb, System.out);
-                } catch (IOException e) { }
-            }
-
-            n += readLen;
-            exlen += readLen;
-        }
-
-        return n;
-    }
-
-    /*
-     * Read the SSL V3 record ... first time around, check to see if it
-     * really IS a V3 record.  Handle SSL V2 clients which can talk V3.0,
-     * as well as real V3 record format; otherwise report an error.
-     */
-    void read(InputStream s, OutputStream o) throws IOException {
-        if (isClosed) {
-            return;
-        }
-
-        /*
-         * For SSL it really _is_ an error if the other end went away
-         * so ungracefully as to not shut down cleanly.
-         */
-        if(exlen < headerSize) {
-            int really = readFully(s, buf, exlen, headerSize - exlen);
-            if (really < 0) {
-                throw new EOFException("SSL peer shut down incorrectly");
-            }
-
-            pos = headerSize;
-            count = headerSize;
-            lastHashed = pos;
-        }
-
-        /*
-         * The first record might use some other record marking convention,
-         * typically SSL v2 header.  (PCT could also be detected here.)
-         * This case is currently common -- Navigator 3.0 usually works
-         * this way, as do IE 3.0 and other products.
-         */
-        if (!formatVerified) {
-            formatVerified = true;
-            /*
-             * The first record must either be a handshake record or an
-             * alert message. If it's not, it is either invalid or an
-             * SSLv2 message.
-             */
-            if (buf[0] != ct_handshake && buf[0] != ct_alert) {
-                handleUnknownRecord(s, o);
-            } else {
-                readV3Record(s, o);
-            }
-        } else { // formatVerified == true
-            readV3Record(s, o);
-        }
-    }
-
-    /**
-     * Return true if the specified record protocol version is out of the
-     * range of the possible supported versions.
-     */
-    static void checkRecordVersion(ProtocolVersion version,
-            boolean allowSSL20Hello) throws SSLException {
-        // Check if the record version is too old (currently not possible)
-        // or if the major version does not match.
-        //
-        // The actual version negotiation is in the handshaker classes
-        if ((version.v < ProtocolVersion.MIN.v) ||
-            ((version.major & 0xFF) > (ProtocolVersion.MAX.major & 0xFF))) {
-
-            // if it's not SSLv2, we're out of here.
-            if (!allowSSL20Hello ||
-                    (version.v != ProtocolVersion.SSL20Hello.v)) {
-                throw new SSLException("Unsupported record version " + version);
-            }
-        }
-    }
-
-    /**
-     * Read a SSL/TLS record. Throw an IOException if the format is invalid.
-     */
-    private void readV3Record(InputStream s, OutputStream o)
-            throws IOException {
-        ProtocolVersion recordVersion = ProtocolVersion.valueOf(buf[1], buf[2]);
-
-        // check the record version
-        checkRecordVersion(recordVersion, false);
-
-        /*
-         * Get and check length, then the data.
-         */
-        int contentLen = ((buf[3] & 0x0ff) << 8) + (buf[4] & 0xff);
-
-        /*
-         * Check for upper bound.
-         */
-        if (contentLen < 0 || contentLen > maxLargeRecordSize - headerSize) {
-            throw new SSLProtocolException("Bad InputRecord size"
-                + ", count = " + contentLen
-                + ", buf.length = " + buf.length);
-        }
-
-        /*
-         * Grow "buf" if needed. Since buf is maxRecordSize by default,
-         * this only occurs when we receive records which violate the
-         * SSL specification. This is a workaround for a Microsoft SSL bug.
-         */
-        if (contentLen > buf.length - headerSize) {
-            byte[] newbuf = new byte[contentLen + headerSize];
-            System.arraycopy(buf, 0, newbuf, 0, headerSize);
-            buf = newbuf;
-        }
+}
 
-        if (exlen < contentLen + headerSize) {
-            int really = readFully(
-                s, buf, exlen, contentLen + headerSize - exlen);
-            if (really < 0) {
-                throw new SSLException("SSL peer shut down incorrectly");
-            }
-        }
-
-        // now we've got a complete record.
-        count = contentLen + headerSize;
-        exlen = 0;
-
-        if (debug != null && Debug.isOn("record")) {
-            if (count < 0 || count > (maxRecordSize - headerSize)) {
-                System.out.println(Thread.currentThread().getName()
-                    + ", Bad InputRecord size" + ", count = " + count);
-            }
-            System.out.println(Thread.currentThread().getName()
-                + ", READ: " + recordVersion + " "
-                + contentName(contentType()) + ", length = " + available());
-        }
-        /*
-         * then caller decrypts, verifies, and uncompresses
-         */
-    }
-
-    /**
-     * Deal with unknown records. Called if the first data we read on this
-     * connection does not look like an SSL/TLS record. It could a SSLv2
-     * message, or just garbage.
-     */
-    private void handleUnknownRecord(InputStream s, OutputStream o)
-            throws IOException {
-        /*
-         * No?  Oh well; does it look like a V2 "ClientHello"?
-         * That'd be an unpadded handshake message; we don't
-         * bother checking length just now.
-         */
-        if (((buf[0] & 0x080) != 0) && buf[2] == 1) {
-            /*
-             * if the user has disabled SSLv2Hello (using
-             * setEnabledProtocol) then throw an
-             * exception
-             */
-            if (helloVersion != ProtocolVersion.SSL20Hello) {
-                throw new SSLHandshakeException("SSLv2Hello is disabled");
-            }
-
-            ProtocolVersion recordVersion =
-                                ProtocolVersion.valueOf(buf[3], buf[4]);
-
-            if (recordVersion == ProtocolVersion.SSL20Hello) {
-                /*
-                 * Looks like a V2 client hello, but not one saying
-                 * "let's talk SSLv3".  So we send an SSLv2 error
-                 * message, one that's treated as fatal by clients.
-                 * (Otherwise we'll hang.)
-                 */
-                try {
-                    writeBuffer(o, v2NoCipher, 0, v2NoCipher.length);
-                } catch (Exception e) {
-                    /* NOTHING */
-                }
-                throw new SSLException("Unsupported SSL v2.0 ClientHello");
-            }
-
-            /*
-             * If we can map this into a V3 ClientHello, read and
-             * hash the rest of the V2 handshake, turn it into a
-             * V3 ClientHello message, and pass it up.
-             */
-            int len = ((buf[0] & 0x7f) << 8) +
-                (buf[1] & 0xff) - 3;
-            if (v2Buf == null) {
-                v2Buf = new byte[len];
-            }
-            if (exlen < len + headerSize) {
-                int really = readFully(
-                        s, v2Buf, exlen - headerSize, len + headerSize - exlen);
-                if (really < 0) {
-                    throw new EOFException("SSL peer shut down incorrectly");
-                }
-            }
-
-            // now we've got a complete record.
-            exlen = 0;
-
-            hashInternal(buf, 2, 3);
-            hashInternal(v2Buf, 0, len);
-            V2toV3ClientHello(v2Buf);
-            v2Buf = null;
-            lastHashed = count;
-
-            if (debug != null && Debug.isOn("record"))  {
-                System.out.println(
-                    Thread.currentThread().getName()
-                    + ", READ:  SSL v2, contentType = "
-                    + contentName(contentType())
-                    + ", translated length = " + available());
-            }
-            return;
-
-        } else {
-            /*
-             * Does it look like a V2 "ServerHello"?
-             */
-            if (((buf [0] & 0x080) != 0) && buf [2] == 4) {
-                throw new SSLException(
-                    "SSL V2.0 servers are not supported.");
-            }
-
-            /*
-             * If this is a V2 NoCipher message then this means
-             * the other server doesn't support V3. Otherwise, we just
-             * don't understand what it's saying.
-             */
-            for (int i = 0; i < v2NoCipher.length; i++) {
-                if (buf[i] != v2NoCipher[i]) {
-                    throw new SSLException(
-                        "Unrecognized SSL message, plaintext connection?");
-                }
-            }
-
-            throw new SSLException("SSL V2.0 servers are not supported.");
-        }
-    }
-
-    /*
-     * Actually do the write here.  For SSLEngine's HS data,
-     * we'll override this method and let it take the appropriate
-     * action.
-     */
-    void writeBuffer(OutputStream s, byte [] buf, int off, int len)
-            throws IOException {
-        s.write(buf, 0, len);
-        s.flush();
-    }
-
-    /*
-     * Support "old" clients which are capable of SSL V3.0 protocol ... for
-     * example, Navigator 3.0 clients.  The V2 message is in the header and
-     * the bytes passed as parameter.  This routine translates the V2 message
-     * into an equivalent V3 one.
-     */
-    private void V2toV3ClientHello(byte v2Msg []) throws SSLException
-    {
-        int i;
-
-        /*
-         * Build the first part of the V3 record header from the V2 one
-         * that's now buffered up.  (Lengths are fixed up later).
-         */
-        buf [0] = ct_handshake;
-        buf [1] = buf [3];      // V3.x
-        buf[2] = buf[4];
-        // header [3..4] for handshake message length
-        // count = 5;
-
-        /*
-         * Store the generic V3 handshake header:  4 bytes
-         */
-        buf [5] = 1;    // HandshakeMessage.ht_client_hello
-        // buf [6..8] for length of ClientHello (int24)
-        // count += 4;
-
-        /*
-         * ClientHello header starts with SSL version
-         */
-        buf [9] = buf [1];
-        buf [10] = buf [2];
-        // count += 2;
-        count = 11;
-
-        /*
-         * Start parsing the V2 message ...
-         */
-        int      cipherSpecLen, sessionIdLen, nonceLen;
-
-        cipherSpecLen = ((v2Msg [0] & 0xff) << 8) + (v2Msg [1] & 0xff);
-        sessionIdLen  = ((v2Msg [2] & 0xff) << 8) + (v2Msg [3] & 0xff);
-        nonceLen   = ((v2Msg [4] & 0xff) << 8) + (v2Msg [5] & 0xff);
-
-        /*
-         * Copy Random value/nonce ... if less than the 32 bytes of
-         * a V3 "Random", right justify and zero pad to the left.  Else
-         * just take the last 32 bytes.
-         */
-        int      offset = 6 + cipherSpecLen + sessionIdLen;
-
-        if (nonceLen < 32) {
-            for (i = 0; i < (32 - nonceLen); i++)
-                buf [count++] = 0;
-            System.arraycopy(v2Msg, offset, buf, count, nonceLen);
-            count += nonceLen;
-        } else {
-            System.arraycopy(v2Msg, offset + (nonceLen - 32),
-                    buf, count, 32);
-            count += 32;
-        }
-
-        /*
-         * Copy Session ID (only one byte length!)
-         */
-        offset -= sessionIdLen;
-        buf [count++] = (byte) sessionIdLen;
-
-        System.arraycopy(v2Msg, offset, buf, count, sessionIdLen);
-        count += sessionIdLen;
-
-        /*
-         * Copy and translate cipher suites ... V2 specs with first byte zero
-         * are really V3 specs (in the last 2 bytes), just copy those and drop
-         * the other ones.  Preference order remains unchanged.
-         *
-         * Example:  Netscape Navigator 3.0 (exportable) says:
-         *
-         * 0/3,     SSL_RSA_EXPORT_WITH_RC4_40_MD5
-         * 0/6,     SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5
-         *
-         * Microsoft Internet Explorer 3.0 (exportable) supports only
-         *
-         * 0/3,     SSL_RSA_EXPORT_WITH_RC4_40_MD5
-         */
-        int j;
-
-        offset -= cipherSpecLen;
-        j = count + 2;
-
-        for (i = 0; i < cipherSpecLen; i += 3) {
-            if (v2Msg [offset + i] != 0)
-                continue;
-            buf [j++] = v2Msg [offset + i + 1];
-            buf [j++] = v2Msg [offset + i + 2];
-        }
-
-        j -= count + 2;
-        buf [count++] = (byte) (j >>> 8);
-        buf [count++] = (byte) j;
-        count += j;
-
-        /*
-         * Append compression methods (default/null only)
-         */
-        buf [count++] = 1;
-        buf [count++] = 0;      // Session.compression_null
-
-        /*
-         * Fill in lengths of the messages we synthesized (nested:
-         * V3 handshake message within V3 record) and then return
-         */
-        buf [3] = (byte) (count - headerSize);
-        buf [4] = (byte) ((count - headerSize) >>> 8);
-
-        buf [headerSize + 1] = 0;
-        buf [headerSize + 2] = (byte) (((count - headerSize) - 4) >>> 8);
-        buf [headerSize + 3] = (byte) ((count - headerSize) - 4);
-
-        pos = headerSize;
-    }
-
-    /**
-     * Return a description for the given content type. This method should be
-     * in Record, but since that is an interface this is not possible.
-     * Called from InputRecord and OutputRecord.
-     */
-    static String contentName(int contentType) {
-        switch (contentType) {
-        case ct_change_cipher_spec:
-            return "Change Cipher Spec";
-        case ct_alert:
-            return "Alert";
-        case ct_handshake:
-            return "Handshake";
-        case ct_application_data:
-            return "Application Data";
-        default:
-            return "contentType = " + contentType;
-        }
-    }
-
-}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/JsseJce.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/JsseJce.java	Wed Jul 05 20:37:09 2017 +0200
@@ -64,24 +64,9 @@
     // If true, then all the Kerberos-based crypto we need is available.
     private final static boolean kerberosAvailable;
     static {
-        boolean temp;
-        try {
-            AccessController.doPrivileged(
-                new PrivilegedExceptionAction<Void>() {
-                    @Override
-                    public Void run() throws Exception {
-                        // Test for Kerberos using the bootstrap class loader
-                        Class.forName("sun.security.krb5.PrincipalName", true,
-                                null);
-                        return null;
-                    }
-                });
-            temp = true;
-
-        } catch (Exception e) {
-            temp = false;
-        }
-        kerberosAvailable = temp;
+        ClientKeyExchangeService p =
+                ClientKeyExchangeService.find("KRB5");
+        kerberosAvailable = (p != null);
     }
 
     static {
--- a/jdk/src/java.base/share/classes/sun/security/ssl/KerberosClientKeyExchange.java	Thu Jun 04 18:50:30 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,154 +0,0 @@
-/*
- * 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
- * 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.security.ssl;
-
-import java.io.IOException;
-import java.io.PrintStream;
-import java.security.AccessController;
-import java.security.AccessControlContext;
-import java.security.Principal;
-import java.security.PrivilegedAction;
-import java.security.SecureRandom;
-import javax.crypto.SecretKey;
-
-/**
- * A helper class that calls the KerberosClientKeyExchange implementation.
- */
-public class KerberosClientKeyExchange extends HandshakeMessage {
-
-    private static final String IMPL_CLASS =
-        "sun.security.ssl.krb5.KerberosClientKeyExchangeImpl";
-
-    private static final Class<?> implClass = AccessController.doPrivileged(
-            new PrivilegedAction<Class<?>>() {
-                @Override
-                public Class<?> run() {
-                    try {
-                        return Class.forName(IMPL_CLASS, true, null);
-                    } catch (ClassNotFoundException cnf) {
-                        return null;
-                    }
-                }
-            }
-        );
-    private final KerberosClientKeyExchange impl = createImpl();
-
-    private KerberosClientKeyExchange createImpl() {
-        if (implClass != null &&
-                getClass() == KerberosClientKeyExchange.class) {
-            try {
-                return (KerberosClientKeyExchange)implClass.newInstance();
-            } catch (InstantiationException e) {
-                throw new AssertionError(e);
-            } catch (IllegalAccessException e) {
-                throw new AssertionError(e);
-            }
-        }
-        return null;
-    }
-
-    // This constructor will be called when constructing an instance of its
-    // subclass -- KerberosClientKeyExchangeImpl.  Please won't check the
-    // value of impl variable in this constructor.
-    protected KerberosClientKeyExchange() {
-        // please won't check the value of impl variable
-    }
-
-    public KerberosClientKeyExchange(String serverName,
-        AccessControlContext acc, ProtocolVersion protocolVersion,
-        SecureRandom rand) throws IOException {
-
-        if (impl != null) {
-            init(serverName, acc, protocolVersion, rand);
-        } else {
-            throw new IllegalStateException("Kerberos is unavailable");
-        }
-    }
-
-    public KerberosClientKeyExchange(ProtocolVersion protocolVersion,
-            ProtocolVersion clientVersion, SecureRandom rand,
-            HandshakeInStream input, AccessControlContext acc,
-            Object serverKeys) throws IOException {
-
-        if (impl != null) {
-            init(protocolVersion, clientVersion, rand, input, acc, serverKeys);
-        } else {
-            throw new IllegalStateException("Kerberos is unavailable");
-        }
-    }
-
-    @Override
-    int messageType() {
-        return ht_client_key_exchange;
-    }
-
-    @Override
-    public int messageLength() {
-        return impl.messageLength();
-    }
-
-    @Override
-    public void send(HandshakeOutStream s) throws IOException {
-        impl.send(s);
-    }
-
-    @Override
-    public void print(PrintStream p) throws IOException {
-        impl.print(p);
-    }
-
-    public void init(String serverName,
-        AccessControlContext acc, ProtocolVersion protocolVersion,
-        SecureRandom rand) throws IOException {
-
-        if (impl != null) {
-            impl.init(serverName, acc, protocolVersion, rand);
-        }
-    }
-
-    public void init(ProtocolVersion protocolVersion,
-            ProtocolVersion clientVersion, SecureRandom rand,
-            HandshakeInStream input, AccessControlContext acc,
-            Object ServiceCreds) throws IOException {
-
-        if (impl != null) {
-            impl.init(protocolVersion, clientVersion,
-                                    rand, input, acc, ServiceCreds);
-        }
-    }
-
-    public byte[] getUnencryptedPreMasterSecret() {
-        return impl.getUnencryptedPreMasterSecret();
-    }
-
-    public Principal getPeerPrincipal(){
-        return impl.getPeerPrincipal();
-    }
-
-    public Principal getLocalPrincipal(){
-        return impl.getLocalPrincipal();
-    }
-}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/Krb5Helper.java	Thu Jun 04 18:50:30 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,135 +0,0 @@
-/*
- * Copyright (c) 2009, 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.security.ssl;
-
-import java.security.AccessControlContext;
-import java.security.AccessController;
-import java.security.Permission;
-import java.security.Principal;
-import java.security.PrivilegedAction;
-import javax.crypto.SecretKey;
-import javax.security.auth.Subject;
-import javax.security.auth.login.LoginException;
-
-/**
- * A helper class for Kerberos APIs.
- */
-public final class Krb5Helper {
-
-    private Krb5Helper() { }
-
-    // loads Krb5Proxy implementation class if available
-    private static final String IMPL_CLASS =
-        "sun.security.ssl.krb5.Krb5ProxyImpl";
-
-    private static final Krb5Proxy proxy =
-        AccessController.doPrivileged(new PrivilegedAction<Krb5Proxy>() {
-            @Override
-            public Krb5Proxy run() {
-                try {
-                    Class<?> c = Class.forName(IMPL_CLASS, true, null);
-                    return (Krb5Proxy)c.newInstance();
-                } catch (ClassNotFoundException cnf) {
-                    return null;
-                } catch (InstantiationException e) {
-                    throw new AssertionError(e);
-                } catch (IllegalAccessException e) {
-                    throw new AssertionError(e);
-                }
-            }});
-
-    /**
-     * Returns true if Kerberos is available.
-     */
-    public static boolean isAvailable() {
-        return proxy != null;
-    }
-
-    private static void ensureAvailable() {
-        if (proxy == null)
-            throw new AssertionError("Kerberos should have been available");
-    }
-
-    /**
-     * Returns the Subject associated with client-side of the SSL socket.
-     */
-    public static Subject getClientSubject(AccessControlContext acc)
-            throws LoginException {
-        ensureAvailable();
-        return proxy.getClientSubject(acc);
-    }
-
-    /**
-     * Returns the Subject associated with server-side of the SSL socket.
-     */
-    public static Subject getServerSubject(AccessControlContext acc)
-            throws LoginException {
-        ensureAvailable();
-        return proxy.getServerSubject(acc);
-    }
-
-    /**
-     * Returns the KerberosKeys for the default server-side principal.
-     */
-    public static Object getServiceCreds(AccessControlContext acc)
-            throws LoginException {
-        ensureAvailable();
-        return proxy.getServiceCreds(acc);
-    }
-
-    /**
-     * Returns the server-side principal name associated with the KerberosKey.
-     */
-    public static String getServerPrincipalName(Object serviceCreds) {
-        ensureAvailable();
-        return proxy.getServerPrincipalName(serviceCreds);
-    }
-
-    /**
-     * Returns the hostname embedded in the principal name.
-     */
-    public static String getPrincipalHostName(Principal principal) {
-        ensureAvailable();
-        return proxy.getPrincipalHostName(principal);
-    }
-
-    /**
-     * Returns a ServicePermission for the principal name and action.
-     */
-    public static Permission getServicePermission(String principalName,
-            String action) {
-        ensureAvailable();
-        return proxy.getServicePermission(principalName, action);
-    }
-
-    /**
-     * Determines if the Subject might contain creds for princ.
-     */
-    public static boolean isRelated(Subject subject, Principal princ) {
-        ensureAvailable();
-        return proxy.isRelated(subject, princ);
-    }
-}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/Krb5Proxy.java	Thu Jun 04 18:50:30 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2009, 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.security.ssl;
-
-import java.security.AccessControlContext;
-import java.security.Permission;
-import java.security.Principal;
-import javax.crypto.SecretKey;
-import javax.security.auth.Subject;
-import javax.security.auth.login.LoginException;
-
-/**
- * An interface to a subset of the Kerberos APIs to avoid a static dependency
- * on the types defined by these APIs.
- */
-public interface Krb5Proxy {
-
-    /**
-     * Returns the Subject associated with the client-side of the SSL socket.
-     */
-    Subject getClientSubject(AccessControlContext acc) throws LoginException;
-
-    /**
-     * Returns the Subject associated with the server-side of the SSL socket.
-     */
-    Subject getServerSubject(AccessControlContext acc) throws LoginException;
-
-
-    /**
-     * Returns the Kerberos ServiceCreds for the default server-side principal.
-     */
-    Object getServiceCreds(AccessControlContext acc) throws LoginException;
-
-    /**
-     * Returns the server-side principal name associated with the KerberosKey.
-     */
-    String getServerPrincipalName(Object serviceCreds);
-
-    /**
-     * Returns the hostname embedded in the principal name.
-     */
-    String getPrincipalHostName(Principal principal);
-
-    /**
-     * Returns a ServicePermission for the principal name and action.
-     */
-    Permission getServicePermission(String principalName, String action);
-
-    /**
-     * Determines if the Subject might contain creds for princ.
-     */
-    boolean isRelated(Subject subject, Principal princ);
-}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/MAC.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/MAC.java	Wed Jul 05 20:37:09 2017 +0200
@@ -23,7 +23,6 @@
  * questions.
  */
 
-
 package sun.security.ssl;
 
 import java.security.InvalidKeyException;
@@ -50,24 +49,26 @@
  */
 final class MAC extends Authenticator {
 
-    final static MAC NULL = new MAC();
+    final static MAC TLS_NULL = new MAC(false);
 
     // Value of the null MAC is fixed
     private static final byte nullMAC[] = new byte[0];
 
     // internal identifier for the MAC algorithm
-    private final MacAlg        macAlg;
+    private final MacAlg macAlg;
 
     // JCE Mac object
     private final Mac mac;
 
-    private MAC() {
+    MAC(boolean isDTLS) {
+        super(isDTLS);
+
         macAlg = M_NULL;
         mac = null;
     }
 
     /**
-     * Set up, configured for the given SSL/TLS MAC type and version.
+     * Set up, configured for the given MAC type and version.
      */
     MAC(MacAlg macAlg, ProtocolVersion protocolVersion, SecretKey key)
             throws NoSuchAlgorithmException, InvalidKeyException {
@@ -75,12 +76,14 @@
         this.macAlg = macAlg;
 
         String algorithm;
-        boolean tls = (protocolVersion.v >= ProtocolVersion.TLS10.v);
+
+        // using SSL MAC computation?
+        boolean useSSLMac = (protocolVersion.v < ProtocolVersion.TLS10.v);
 
         if (macAlg == M_MD5) {
-            algorithm = tls ? "HmacMD5" : "SslMacMD5";
+            algorithm = useSSLMac ? "SslMacMD5" : "HmacMD5";
         } else if (macAlg == M_SHA) {
-            algorithm = tls ? "HmacSHA1" : "SslMacSHA1";
+            algorithm = useSSLMac ? "SslMacSHA1" : "HmacSHA1";
         } else if (macAlg == M_SHA256) {
             algorithm = "HmacSHA256";    // TLS 1.2+
         } else if (macAlg == M_SHA384) {
@@ -122,6 +125,8 @@
      * @param offset start of compressed record data
      * @param len the size of the compressed record
      * @param isSimulated if true, simulate the MAC computation
+     *
+     * @return the MAC result
      */
     final byte[] compute(byte type, byte buf[],
             int offset, int len, boolean isSimulated) {
@@ -130,7 +135,8 @@
         }
 
         if (!isSimulated) {
-            byte[] additional = acquireAuthenticationBytes(type, len);
+            // Uses the implicit sequence number for the computation.
+            byte[] additional = acquireAuthenticationBytes(type, len, null);
             mac.update(additional);
         }
         mac.update(buf, offset, len);
@@ -149,15 +155,22 @@
      * @param bb a ByteBuffer in which the position and limit
      *          demarcate the data to be MAC'd.
      * @param isSimulated if true, simulate the MAC computation
+     * @param sequence the explicit sequence number, or null if using
+     *        the implicit sequence number for the computation
+     *
+     * @return the MAC result
      */
-    final byte[] compute(byte type, ByteBuffer bb, boolean isSimulated) {
+    final byte[] compute(byte type, ByteBuffer bb,
+            byte[] sequence, boolean isSimulated) {
+
         if (macAlg.size == 0) {
             return nullMAC;
         }
 
         if (!isSimulated) {
+            // Uses the explicit sequence number for the computation.
             byte[] additional =
-                    acquireAuthenticationBytes(type, bb.remaining());
+                    acquireAuthenticationBytes(type, bb.remaining(), sequence);
             mac.update(additional);
         }
         mac.update(bb);
@@ -165,5 +178,22 @@
         return mac.doFinal();
     }
 
+    /**
+     * Compute and returns the MAC for the remaining data
+     * in this ByteBuffer.
+     *
+     * On return, the bb position == limit, and limit will
+     * have not changed.
+     *
+     * @param type record type
+     * @param bb a ByteBuffer in which the position and limit
+     *        demarcate the data to be MAC'd.
+     * @param isSimulated if true, simulate the the MAC computation
+     *
+     * @return the MAC result
+     */
+    final byte[] compute(byte type, ByteBuffer bb, boolean isSimulated) {
+        // Uses the implicit sequence number for the computation.
+        return compute(type, bb, null, isSimulated);
+    }
 }
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/MaxFragmentLengthExtension.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.security.ssl;
+
+import java.io.IOException;
+import javax.net.ssl.SSLProtocolException;
+
+/*
+ * [RFC6066] TLS specifies a fixed maximum plaintext fragment length of
+ * 2^14 bytes.  It may be desirable for constrained clients to negotiate
+ * a smaller maximum fragment length due to memory limitations or bandwidth
+ * limitations.
+ *
+ * In order to negotiate smaller maximum fragment lengths, clients MAY
+ * include an extension of type "max_fragment_length" in the (extended)
+ * client hello.  The "extension_data" field of this extension SHALL
+ * contain:
+ *
+ *    enum{
+ *        2^9(1), 2^10(2), 2^11(3), 2^12(4), (255)
+ *    } MaxFragmentLength;
+ *
+ * whose value is the desired maximum fragment length.
+ */
+final class MaxFragmentLengthExtension extends HelloExtension {
+
+    private static final int MAX_FRAGMENT_LENGTH_512  = 1;      // 2^9
+    private static final int MAX_FRAGMENT_LENGTH_1024 = 2;      // 2^10
+    private static final int MAX_FRAGMENT_LENGTH_2048 = 3;      // 2^11
+    private static final int MAX_FRAGMENT_LENGTH_4096 = 4;      // 2^12
+
+    final int maxFragmentLength;
+
+    MaxFragmentLengthExtension(int fragmentSize) {
+        super(ExtensionType.EXT_MAX_FRAGMENT_LENGTH);
+
+        if (fragmentSize < 1024) {
+            maxFragmentLength = MAX_FRAGMENT_LENGTH_512;
+        } else if (fragmentSize < 2048) {
+            maxFragmentLength = MAX_FRAGMENT_LENGTH_1024;
+        } else if (fragmentSize < 4096) {
+            maxFragmentLength = MAX_FRAGMENT_LENGTH_2048;
+        } else {
+            maxFragmentLength = MAX_FRAGMENT_LENGTH_4096;
+        }
+    }
+
+    MaxFragmentLengthExtension(HandshakeInStream s, int len)
+                throws IOException {
+        super(ExtensionType.EXT_MAX_FRAGMENT_LENGTH);
+
+        // check the extension length
+        if (len != 1) {
+            throw new SSLProtocolException("Invalid " + type + " extension");
+        }
+
+        maxFragmentLength = s.getInt8();
+        if ((maxFragmentLength > 4) || (maxFragmentLength < 1)) {
+            throw new SSLProtocolException("Invalid " + type + " extension");
+        }
+    }
+
+    // Length of the encoded extension, including the type and length fields
+    @Override
+    int length() {
+        return 5;               // 4: extension type and length fields
+                                // 1: MaxFragmentLength field
+    }
+
+    @Override
+    void send(HandshakeOutStream s) throws IOException {
+        s.putInt16(type.id);
+        s.putInt16(1);
+        s.putInt8(maxFragmentLength);
+    }
+
+    int getMaxFragLen() {
+        switch (maxFragmentLength) {
+            case MAX_FRAGMENT_LENGTH_512:
+                return 512;
+            case MAX_FRAGMENT_LENGTH_1024:
+                return 1024;
+            case MAX_FRAGMENT_LENGTH_2048:
+                return 2048;
+            case MAX_FRAGMENT_LENGTH_4096:
+                return 4096;
+        }
+
+        // unlikely to happen
+        return -1;
+    }
+
+    static boolean needFragLenNego(int fragmentSize) {
+        return (fragmentSize > 0) && (fragmentSize <= 4096);
+    }
+
+    static int getValidMaxFragLen(int fragmentSize) {
+        if (fragmentSize < 1024) {
+            return 512;
+        } else if (fragmentSize < 2048) {
+            return 1024;
+        } else if (fragmentSize < 4096) {
+            return 2048;
+        } else if (fragmentSize == 4096) {
+            return 4096;
+        } else {
+            return 16384;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "Extension " + type + ", max_fragment_length: " +
+                "(2^" + (maxFragmentLength + 8) + ")";
+    }
+}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/OutputRecord.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/OutputRecord.java	Wed Jul 05 20:37:09 2017 +0200
@@ -23,7 +23,6 @@
  * questions.
  */
 
-
 package sun.security.ssl;
 
 import java.io.*;
@@ -35,92 +34,61 @@
 
 
 /**
- * SSL 3.0 records, as written to a TCP stream.
- *
- * Each record has a message area that starts out with data supplied by the
- * application.  It may grow/shrink due to compression and will be modified
- * in place for mac-ing and encryption.
- *
- * Handshake records have additional needs, notably accumulation of a set
- * of hashes which are used to establish that handshaking was done right.
- * Handshake records usually have several handshake messages each, and we
- * need message-level control over what's hashed.
+ * {@code OutputRecord} takes care of the management of SSL/TLS/DTLS output
+ * records, including buffering, encryption, handshake messages marshal, etc.
  *
  * @author David Brownell
  */
-class OutputRecord extends ByteArrayOutputStream implements Record {
+abstract class OutputRecord extends ByteArrayOutputStream
+            implements Record, Closeable {
+
+    /* Class and subclass dynamic debugging support */
+    static final Debug          debug = Debug.getInstance("ssl");
 
-    private HandshakeHash       handshakeHash;
-    private int                 lastHashed;
-    private boolean             firstMessage;
-    final private byte          contentType;
-    private int                 headerOffset;
+    Authenticator               writeAuthenticator;
+    CipherBox                   writeCipher;
+
+    HandshakeHash               handshakeHash;
+    boolean                     firstMessage;
 
     // current protocol version, sent as record version
-    ProtocolVersion     protocolVersion;
+    ProtocolVersion             protocolVersion;
 
     // version for the ClientHello message. Only relevant if this is a
     // client handshake record. If set to ProtocolVersion.SSL20Hello,
     // the V3 client hello is converted to V2 format.
-    private ProtocolVersion     helloVersion;
+    ProtocolVersion             helloVersion;
+
+    // Is it the first application record to write?
+    boolean                     isFirstAppOutputRecord = true;
 
-    /* Class and subclass dynamic debugging support */
-    static final Debug debug = Debug.getInstance("ssl");
+    // packet size
+    int                         packetSize;
+
+    // fragment size
+    int                         fragmentSize;
+
+    // closed or not?
+    boolean                     isClosed;
 
     /*
-     * Default constructor makes a record supporting the maximum
-     * SSL record size.  It allocates the header bytes directly.
-     *
-     * The structure of the byte buffer looks like:
-     *
-     *     |---------+--------+-------+---------------------------------|
-     *     | unused  | header |  IV   | content, MAC/TAG, padding, etc. |
-     *     |    headerPlusMaxIVSize   |
-     *
-     * unused: unused part of the buffer of size
-     *
-     *             headerPlusMaxIVSize - header size - IV size
-     *
-     *         When this object is created, we don't know the protocol
-     *         version number, IV length, etc., so reserve space in front
-     *         to avoid extra data movement (copies).
-     * header: the header of an SSL record
-     * IV:     the optional IV/nonce field, it is only required for block
-     *         (TLS 1.1 or later) and AEAD cipher suites.
-     *
-     * @param type the content type for the record
+     * Mappings from V3 cipher suite encodings to their pure V2 equivalents.
+     * This is taken from the SSL V3 specification, Appendix E.
      */
-    OutputRecord(byte type, int size) {
-        super(size);
-        this.protocolVersion = ProtocolVersion.DEFAULT;
-        this.helloVersion = ProtocolVersion.DEFAULT_HELLO;
-        firstMessage = true;
-        count = headerPlusMaxIVSize;
-        contentType = type;
-        lastHashed = count;
-        headerOffset = headerPlusMaxIVSize - headerSize;
+    private static int[] V3toV2CipherMap1 =
+        {-1, -1, -1, 0x02, 0x01, -1, 0x04, 0x05, -1, 0x06, 0x07};
+    private static int[] V3toV2CipherMap3 =
+        {-1, -1, -1, 0x80, 0x80, -1, 0x80, 0x80, -1, 0x40, 0xC0};
+
+    OutputRecord() {
+        this.writeCipher = CipherBox.NULL;
+        this.firstMessage = true;
+        this.fragmentSize = Record.maxDataSize;
+
+        // Please set packetSize and protocolVersion in the implementation.
     }
 
-    OutputRecord(byte type) {
-        this(type, recordSize(type));
-    }
-
-    /**
-     * Get the size of the buffer we need for records of the specified
-     * type.
-     */
-    private static int recordSize(byte type) {
-        if ((type == ct_change_cipher_spec) || (type == ct_alert)) {
-            return maxAlertRecordSize;
-        } else {
-            return maxRecordSize;
-        }
-    }
-
-    /*
-     * Updates the SSL version of this record.
-     */
-    synchronized void setVersion(ProtocolVersion protocolVersion) {
+    void setVersion(ProtocolVersion protocolVersion) {
         this.protocolVersion = protocolVersion;
     }
 
@@ -132,441 +100,364 @@
     }
 
     /*
-     * Reset the record so that it can be refilled, starting
-     * immediately after the header.
-     */
-    @Override
-    public synchronized void reset() {
-        super.reset();
-        count = headerPlusMaxIVSize;
-        lastHashed = count;
-        headerOffset = headerPlusMaxIVSize - headerSize;
-    }
-
-    /*
      * For handshaking, we need to be able to hash every byte above the
      * record marking layer.  This is where we're guaranteed to see those
      * bytes, so this is where we can hash them.
      */
     void setHandshakeHash(HandshakeHash handshakeHash) {
-        assert(contentType == ct_handshake);
         this.handshakeHash = handshakeHash;
     }
 
     /*
-     * We hash (the plaintext) on demand.  There is one place where
-     * we want to access the hash in the middle of a record:  client
-     * cert message gets hashed, and part of the same record is the
-     * client cert verify message which uses that hash.  So we track
-     * how much of each record we've hashed so far.
-     */
-    void doHashes() {
-        int len = count - lastHashed;
-
-        if (len > 0) {
-            hashInternal(buf, lastHashed, len);
-            lastHashed = count;
-        }
-    }
-
-    /*
-     * Need a helper function so we can hash the V2 hello correctly
-     */
-    private void hashInternal(byte buf [], int offset, int len) {
-        if (debug != null && Debug.isOn("data")) {
-            try {
-                HexDumpEncoder hd = new HexDumpEncoder();
-
-                System.out.println("[write] MD5 and SHA1 hashes:  len = "
-                    + len);
-                hd.encodeBuffer(new ByteArrayInputStream(buf,
-                    lastHashed, len), System.out);
-            } catch (IOException e) { }
-        }
-
-        handshakeHash.update(buf, lastHashed, len);
-        lastHashed = count;
-    }
-
-    /*
      * Return true iff the record is empty -- to avoid doing the work
      * of sending empty records over the network.
      */
     boolean isEmpty() {
-        return count == headerPlusMaxIVSize;
-    }
-
-    /*
-     * Return true if the record is of an alert of the given description.
-     *
-     * Per SSL/TLS specifications, alert messages convey the severity of the
-     * message (warning or fatal) and a description of the alert. An alert
-     * is defined with a two bytes struct, {byte level, byte description},
-     * following after the header bytes.
-     */
-    boolean isAlert(byte description) {
-        if ((count > (headerPlusMaxIVSize + 1)) && (contentType == ct_alert)) {
-            return buf[headerPlusMaxIVSize + 1] == description;
-        }
-
         return false;
     }
 
-    /*
-     * Encrypt ... length may grow due to block cipher padding, or
-     * message authentication code or tag.
-     */
-    void encrypt(Authenticator authenticator, CipherBox box)
-            throws IOException {
+    boolean seqNumIsHuge() {
+        return (writeAuthenticator != null) &&
+                        writeAuthenticator.seqNumIsHuge();
+    }
 
-        // In case we are automatically flushing a handshake stream, make
-        // sure we have hashed the message first.
-        //
-        // when we support compression, hashing can't go here
-        // since it'll need to be done on the uncompressed data,
-        // and the MAC applies to the compressed data.
-        if (contentType == ct_handshake) {
-            doHashes();
-        }
+    // SSLEngine and SSLSocket
+    abstract void encodeAlert(byte level, byte description) throws IOException;
+
+    // SSLEngine and SSLSocket
+    abstract void encodeHandshake(byte[] buffer,
+            int offset, int length) throws IOException;
+
+    // SSLEngine and SSLSocket
+    abstract void encodeChangeCipherSpec() throws IOException;
 
-        // Requires message authentication code for stream and block
-        // cipher suites.
-        if (authenticator instanceof MAC) {
-            MAC signer = (MAC)authenticator;
-            if (signer.MAClen() != 0) {
-                byte[] hash = signer.compute(contentType, buf,
-                    headerPlusMaxIVSize, count - headerPlusMaxIVSize, false);
-                write(hash);
-            }
-        }
+    // apply to SSLEngine only
+    Ciphertext encode(ByteBuffer[] sources, int offset, int length,
+            ByteBuffer destination) throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    // apply to SSLEngine only
+    void encodeV2NoCipher() throws IOException {
+        throw new UnsupportedOperationException();
+    }
 
-        if (!box.isNullCipher()) {
-            // Requires explicit IV/nonce for CBC/AEAD cipher suites for
-            // TLS 1.1 or later.
-            if ((protocolVersion.v >= ProtocolVersion.TLS11.v) &&
-                                    (box.isCBCMode() || box.isAEADMode())) {
-                byte[] nonce = box.createExplicitNonce(authenticator,
-                                    contentType, count - headerPlusMaxIVSize);
-                int offset = headerPlusMaxIVSize - nonce.length;
-                System.arraycopy(nonce, 0, buf, offset, nonce.length);
-                headerOffset = offset - headerSize;
-            } else {
-                headerOffset = headerPlusMaxIVSize - headerSize;
-            }
+    // apply to SSLSocket only
+    void deliver(byte[] source, int offset, int length) throws IOException {
+        throw new UnsupportedOperationException();
+    }
 
-            // encrypt the content
-            int offset = headerPlusMaxIVSize;
-            if (!box.isAEADMode()) {
-                // The explicit IV can be encrypted.
-                offset = headerOffset + headerSize;
-            }   // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode
+    // apply to SSLSocket only
+    void setDeliverStream(OutputStream outputStream) {
+        throw new UnsupportedOperationException();
+    }
 
-            count = offset + box.encrypt(buf, offset, count - offset);
-        }
+    // apply to SSLEngine only
+    Ciphertext acquireCiphertext(ByteBuffer destination) throws IOException {
+        throw new UnsupportedOperationException();
     }
 
-    /*
-     * Tell how full the buffer is ... for filling it with application or
-     * handshake data.
-     */
-    final int availableDataBytes() {
-        int dataSize = count - headerPlusMaxIVSize;
-        return maxDataSize - dataSize;
+    void changeWriteCiphers(Authenticator writeAuthenticator,
+            CipherBox writeCipher) throws IOException {
+
+        encodeChangeCipherSpec();
+
+        /*
+         * Dispose of any intermediate state in the underlying cipher.
+         * For PKCS11 ciphers, this will release any attached sessions,
+         * and thus make finalization faster.
+         *
+         * Since MAC's doFinal() is called for every SSL/TLS packet, it's
+         * not necessary to do the same with MAC's.
+         */
+        writeCipher.dispose();
+
+        this.writeAuthenticator = writeAuthenticator;
+        this.writeCipher = writeCipher;
+        this.isFirstAppOutputRecord = true;
     }
 
-    /*
-     * Increases the capacity if necessary to ensure that it can hold
-     * at least the number of elements specified by the minimum
-     * capacity argument.
-     *
-     * Note that the increased capacity is only can be used for held
-     * record buffer. Please DO NOT update the availableDataBytes()
-     * according to the expended buffer capacity.
-     *
-     * @see availableDataBytes()
-     */
-    private void ensureCapacity(int minCapacity) {
-        // overflow-conscious code
-        if (minCapacity > buf.length) {
-            buf = Arrays.copyOf(buf, minCapacity);
+    void changePacketSize(int packetSize) {
+        this.packetSize = packetSize;
+    }
+
+    void changeFragmentSize(int fragmentSize) {
+        this.fragmentSize = fragmentSize;
+    }
+
+    int getMaxPacketSize() {
+        return packetSize;
+    }
+
+    // apply to DTLS SSLEngine
+    void initHandshaker() {
+        // blank
+    }
+
+    @Override
+    synchronized public void close() throws IOException {
+        if (!isClosed) {
+            isClosed = true;
+            writeCipher.dispose();
         }
     }
 
-    /*
-     * Return the type of SSL record that's buffered here.
-     */
-    final byte contentType() {
-        return contentType;
-    }
+    //
+    // shared helpers
+    //
+
+    // Encrypt a fragment and wrap up a record.
+    //
+    // To be consistent with the spec of SSLEngine.wrap() methods, the
+    // destination ByteBuffer's position is updated to reflect the amount
+    // of data produced.  The limit remains the same.
+    static long encrypt(Authenticator authenticator,
+            CipherBox encCipher, byte contentType, ByteBuffer destination,
+            int headerOffset, int dstLim, int headerSize,
+            ProtocolVersion protocolVersion, boolean isDTLS) {
+
+        byte[] sequenceNumber = null;
+        int dstContent = destination.position();
 
-    /*
-     * Write the record out on the stream.  Note that you must have (in
-     * order) compressed the data, appended the MAC, and encrypted it in
-     * order for the record to be understood by the other end.  (Some of
-     * those steps will be null early in handshaking.)
-     *
-     * Note that this does no locking for the connection, it's required
-     * that synchronization be done elsewhere.  Also, this does its work
-     * in a single low level write, for efficiency.
-     */
-    void write(OutputStream s, boolean holdRecord,
-            ByteArrayOutputStream heldRecordBuffer) throws IOException {
+        // Acquire the current sequence number before using.
+        if (isDTLS) {
+            sequenceNumber = authenticator.sequenceNumber();
+        }
+
+        // "flip" but skip over header again, add MAC & encrypt
+        if (authenticator instanceof MAC) {
+            MAC signer = (MAC)authenticator;
+            if (signer.MAClen() != 0) {
+                byte[] hash = signer.compute(contentType, destination, false);
 
-        /*
-         * Don't emit content-free records.  (Even change cipher spec
-         * messages have a byte of data!)
-         */
-        if (count == headerPlusMaxIVSize) {
-            return;
+                /*
+                 * position was advanced to limit in MAC compute above.
+                 *
+                 * Mark next area as writable (above layers should have
+                 * established that we have plenty of room), then write
+                 * out the hash.
+                 */
+                destination.limit(destination.limit() + hash.length);
+                destination.put(hash);
+
+                // reset the position and limit
+                destination.limit(destination.position());
+                destination.position(dstContent);
+            }
         }
 
-        int length = count - headerOffset - headerSize;
-        // "should" really never write more than about 14 Kb...
-        if (length < 0) {
-            throw new SSLException("output record size too small: "
-                + length);
+        if (!encCipher.isNullCipher()) {
+            if (protocolVersion.useTLS11PlusSpec() &&
+                    (encCipher.isCBCMode() || encCipher.isAEADMode())) {
+                byte[] nonce = encCipher.createExplicitNonce(
+                        authenticator, contentType, destination.remaining());
+                destination.position(headerOffset + headerSize);
+                destination.put(nonce);
+            }
+            if (!encCipher.isAEADMode()) {
+                // The explicit IV in TLS 1.1 and later can be encrypted.
+                destination.position(headerOffset + headerSize);
+            }   // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode
+
+            // Encrypt may pad, so again the limit may be changed.
+            encCipher.encrypt(destination, dstLim);
+        } else {
+            destination.position(destination.limit());
+        }
+
+        // Finish out the record header.
+        int fragLen = destination.limit() - headerOffset - headerSize;
+
+        destination.put(headerOffset, contentType);         // content type
+        destination.put(headerOffset + 1, protocolVersion.major);
+        destination.put(headerOffset + 2, protocolVersion.minor);
+        if (!isDTLS) {
+            // fragment length
+            destination.put(headerOffset + 3, (byte)(fragLen >> 8));
+            destination.put(headerOffset + 4, (byte)fragLen);
+        } else {
+            // epoch and sequence_number
+            destination.put(headerOffset + 3, sequenceNumber[0]);
+            destination.put(headerOffset + 4, sequenceNumber[1]);
+            destination.put(headerOffset + 5, sequenceNumber[2]);
+            destination.put(headerOffset + 6, sequenceNumber[3]);
+            destination.put(headerOffset + 7, sequenceNumber[4]);
+            destination.put(headerOffset + 8, sequenceNumber[5]);
+            destination.put(headerOffset + 9, sequenceNumber[6]);
+            destination.put(headerOffset + 10, sequenceNumber[7]);
+
+            // fragment length
+            destination.put(headerOffset + 11, (byte)(fragLen >> 8));
+            destination.put(headerOffset + 12, (byte)fragLen);
+
+            // Increase the sequence number for next use.
+            authenticator.increaseSequenceNumber();
         }
 
-        if (debug != null
-                && (Debug.isOn("record") || Debug.isOn("handshake"))) {
-            if ((debug != null && Debug.isOn("record"))
-                    || contentType() == ct_change_cipher_spec)
-                System.out.println(Thread.currentThread().getName()
-                    // v3.0/v3.1 ...
-                    + ", WRITE: " + protocolVersion
-                    + " " + InputRecord.contentName(contentType())
-                    + ", length = " + length);
+        // Update destination position to reflect the amount of data produced.
+        destination.position(destination.limit());
+
+        return Authenticator.toLong(sequenceNumber);
+    }
+
+    // Encrypt a fragment and wrap up a record.
+    //
+    // Uses the internal expandable buf variable and the current
+    // protocolVersion variable.
+    void encrypt(Authenticator authenticator,
+            CipherBox encCipher, byte contentType, int headerSize) {
+
+        int position = headerSize + writeCipher.getExplicitNonceSize();
+
+        // "flip" but skip over header again, add MAC & encrypt
+        int macLen = 0;
+        if (authenticator instanceof MAC) {
+            MAC signer = (MAC)authenticator;
+            macLen = signer.MAClen();
+            if (macLen != 0) {
+                byte[] hash = signer.compute(contentType,
+                        buf, position, (count - position), false);
+
+                write(hash, 0, hash.length);
+            }
         }
 
-        /*
-         * If this is the initial ClientHello on this connection and
-         * we're not trying to resume a (V3) session then send a V2
-         * ClientHello instead so we can detect V2 servers cleanly.
-         */
-         if (firstMessage && useV2Hello()) {
-            byte[] v3Msg = new byte[length - 4];
-            System.arraycopy(buf, headerPlusMaxIVSize + 4,
-                                        v3Msg, 0, v3Msg.length);
-            headerOffset = 0;   // reset the header offset
-            V3toV2ClientHello(v3Msg);
-            handshakeHash.reset();
-            lastHashed = 2;
-            doHashes();
-            if (debug != null && Debug.isOn("record"))  {
-                System.out.println(
-                    Thread.currentThread().getName()
-                    + ", WRITE: SSLv2 client hello message"
-                    + ", length = " + (count - 2)); // 2 byte SSLv2 header
+        if (!encCipher.isNullCipher()) {
+            // Requires explicit IV/nonce for CBC/AEAD cipher suites for
+            // TLS 1.1 or later.
+            if (protocolVersion.useTLS11PlusSpec() &&
+                    (encCipher.isCBCMode() || encCipher.isAEADMode())) {
+
+                byte[] nonce = encCipher.createExplicitNonce(
+                        authenticator, contentType, (count - position));
+                int noncePos = position - nonce.length;
+                System.arraycopy(nonce, 0, buf, noncePos, nonce.length);
+            }
+
+            if (!encCipher.isAEADMode()) {
+                // The explicit IV in TLS 1.1 and later can be encrypted.
+                position = headerSize;
+            }   // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode
+
+            // increase buf capacity if necessary
+            int fragSize = count - position;
+            int packetSize =
+                    encCipher.calculatePacketSize(fragSize, macLen, headerSize);
+            if (packetSize > (buf.length - position)) {
+                byte[] newBuf = new byte[position + packetSize];
+                System.arraycopy(buf, 0, newBuf, 0, count);
+                buf = newBuf;
             }
-        } else {
-            /*
-             * Fill out the header, write it and the message.
-             */
-            buf[headerOffset + 0] = contentType;
-            buf[headerOffset + 1] = protocolVersion.major;
-            buf[headerOffset + 2] = protocolVersion.minor;
-            buf[headerOffset + 3] = (byte)(length >> 8);
-            buf[headerOffset + 4] = (byte)(length);
+
+            // Encrypt may pad, so again the count may be changed.
+            count = position +
+                    encCipher.encrypt(buf, position, (count - position));
         }
-        firstMessage = false;
+
+        // Fill out the header, write it and the message.
+        int fragLen = count - headerSize;
+        buf[0] = contentType;
+        buf[1] = protocolVersion.major;
+        buf[2] = protocolVersion.minor;
+        buf[3] = (byte)((fragLen >> 8) & 0xFF);
+        buf[4] = (byte)(fragLen & 0xFF);
+    }
+
+    static ByteBuffer encodeV2ClientHello(
+            byte[] fragment, int offset, int length) throws IOException {
+
+        int v3SessIdLenOffset = offset + 34;      //  2: client_version
+                                                  // 32: random
+
+        int v3SessIdLen = fragment[v3SessIdLenOffset];
+        int v3CSLenOffset = v3SessIdLenOffset + 1 + v3SessIdLen;
+        int v3CSLen = ((fragment[v3CSLenOffset] & 0xff) << 8) +
+                       (fragment[v3CSLenOffset + 1] & 0xff);
+        int cipherSpecs = v3CSLen / 2;        // 2: cipher spec size
+
+        // Estimate the max V2ClientHello message length
+        //
+        // 11: header size
+        // (cipherSpecs * 6): cipher_specs
+        //    6: one cipher suite may need 6 bytes, see V3toV2CipherSuite.
+        // 3: placeholder for the TLS_EMPTY_RENEGOTIATION_INFO_SCSV
+        //    signaling cipher suite
+        // 32: challenge size
+        int v2MaxMsgLen = 11 + (cipherSpecs * 6) + 3 + 32;
+
+        // Create a ByteBuffer backed by an accessible byte array.
+        byte[] dstBytes = new byte[v2MaxMsgLen];
+        ByteBuffer dstBuf = ByteBuffer.wrap(dstBytes);
 
         /*
-         * The upper levels may want us to delay sending this packet so
-         * multiple TLS Records can be sent in one (or more) TCP packets.
-         * If so, add this packet to the heldRecordBuffer.
-         *
-         * NOTE:  all writes have been synchronized by upper levels.
+         * Copy over the cipher specs. We don't care about actually
+         * translating them for use with an actual V2 server since
+         * we only talk V3.  Therefore, just copy over the V3 cipher
+         * spec values with a leading 0.
          */
-        int debugOffset = 0;
-        if (holdRecord) {
-            /*
-             * If holdRecord is true, we must have a heldRecordBuffer.
-             *
-             * Don't worry about the override of writeBuffer(), because
-             * when holdRecord is true, the implementation in this class
-             * will be used.
-             */
-            writeBuffer(heldRecordBuffer,
-                        buf, headerOffset, count - headerOffset, debugOffset);
-        } else {
-            // It's time to send, do we have buffered data?
-            // May or may not have a heldRecordBuffer.
-            if (heldRecordBuffer != null && heldRecordBuffer.size() > 0) {
-                int heldLen = heldRecordBuffer.size();
-
-                // Ensure the capacity of this buffer.
-                int newCount = count + heldLen - headerOffset;
-                ensureCapacity(newCount);
-
-                // Slide everything in the buffer to the right.
-                System.arraycopy(buf, headerOffset,
-                                    buf, heldLen, count - headerOffset);
-
-                // Prepend the held record to the buffer.
-                System.arraycopy(
-                    heldRecordBuffer.toByteArray(), 0, buf, 0, heldLen);
-                count = newCount;
-                headerOffset = 0;
-
-                // Clear the held buffer.
-                heldRecordBuffer.reset();
-
-                // The held buffer has been dumped, set the debug dump offset.
-                debugOffset = heldLen;
-            }
-            writeBuffer(s, buf, headerOffset,
-                        count - headerOffset, debugOffset);
-        }
-
-        reset();
-    }
+        int v3CSOffset = v3CSLenOffset + 2;   // skip length field
+        int v2CSLen = 0;
 
-    /*
-     * Actually do the write here.  For SSLEngine's HS data,
-     * we'll override this method and let it take the appropriate
-     * action.
-     */
-    void writeBuffer(OutputStream s, byte [] buf, int off, int len,
-            int debugOffset) throws IOException {
-        s.write(buf, off, len);
-        s.flush();
-
-        // Output only the record from the specified debug offset.
-        if (debug != null && Debug.isOn("packet")) {
-            try {
-                HexDumpEncoder hd = new HexDumpEncoder();
-
-                System.out.println("[Raw write]: length = " +
-                                                    (len - debugOffset));
-                hd.encodeBuffer(new ByteArrayInputStream(buf,
-                    off + debugOffset, len - debugOffset), System.out);
-            } catch (IOException e) { }
-        }
-    }
-
-    /*
-     * Return whether the buffer contains a ClientHello message that should
-     * be converted to V2 format.
-     */
-    private boolean useV2Hello() {
-        return firstMessage
-            && (helloVersion == ProtocolVersion.SSL20Hello)
-            && (contentType == ct_handshake)
-            && (buf[headerOffset + 5] == HandshakeMessage.ht_client_hello)
-                                            //  5: recode header size
-            && (buf[headerPlusMaxIVSize + 4 + 2 + 32] == 0);
-                                            // V3 session ID is empty
-                                            //  4: handshake header size
-                                            //  2: client_version in ClientHello
-                                            // 32: random in ClientHello
-    }
-
-    /*
-     * Detect "old" servers which are capable of SSL V2.0 protocol ... for
-     * example, Netscape Commerce 1.0 servers.  The V3 message is in the
-     * header and the bytes passed as parameter.  This routine translates
-     * the V3 message into an equivalent V2 one.
-     *
-     * Note that the translation will strip off all hello extensions as
-     * SSL V2.0 does not support hello extension.
-     */
-    private void V3toV2ClientHello(byte v3Msg []) throws SSLException {
-        int v3SessionIdLenOffset = 2 + 32; // version + nonce
-        int v3SessionIdLen = v3Msg[v3SessionIdLenOffset];
-        int v3CipherSpecLenOffset = v3SessionIdLenOffset + 1 + v3SessionIdLen;
-        int v3CipherSpecLen = ((v3Msg[v3CipherSpecLenOffset] & 0xff) << 8) +
-          (v3Msg[v3CipherSpecLenOffset + 1] & 0xff);
-        int cipherSpecs = v3CipherSpecLen / 2; // 2 bytes each in V3
-
-        /*
-         * Copy over the cipher specs. We don't care about actually translating
-         * them for use with an actual V2 server since we only talk V3.
-         * Therefore, just copy over the V3 cipher spec values with a leading
-         * 0.
-         */
-        int v3CipherSpecOffset = v3CipherSpecLenOffset + 2; // skip length
-        int v2CipherSpecLen = 0;
-        count = 11;
+        dstBuf.position(11);
         boolean containsRenegoInfoSCSV = false;
         for (int i = 0; i < cipherSpecs; i++) {
             byte byte1, byte2;
 
-            byte1 = v3Msg[v3CipherSpecOffset++];
-            byte2 = v3Msg[v3CipherSpecOffset++];
-            v2CipherSpecLen += V3toV2CipherSuite(byte1, byte2);
+            byte1 = fragment[v3CSOffset++];
+            byte2 = fragment[v3CSOffset++];
+            v2CSLen += V3toV2CipherSuite(dstBuf, byte1, byte2);
             if (!containsRenegoInfoSCSV &&
-                        byte1 == (byte)0x00 && byte2 == (byte)0xFF) {
+                    byte1 == (byte)0x00 && byte2 == (byte)0xFF) {
                 containsRenegoInfoSCSV = true;
             }
         }
 
         if (!containsRenegoInfoSCSV) {
-            v2CipherSpecLen += V3toV2CipherSuite((byte)0x00, (byte)0xFF);
+            v2CSLen += V3toV2CipherSuite(dstBuf, (byte)0x00, (byte)0xFF);
         }
 
         /*
+         * Copy in the nonce.
+         */
+        dstBuf.put(fragment, (offset + 2), 32);
+
+        /*
          * Build the first part of the V3 record header from the V2 one
          * that's now buffered up.  (Lengths are fixed up later).
          */
-        buf[2] = HandshakeMessage.ht_client_hello;
-        buf[3] = v3Msg[0];      // major version
-        buf[4] = v3Msg[1];      // minor version
-        buf[5] = (byte)(v2CipherSpecLen >>> 8);
-        buf[6] = (byte)v2CipherSpecLen;
-        buf[7] = 0;
-        buf[8] = 0;             // always no session
-        buf[9] = 0;
-        buf[10] = 32;           // nonce length (always 32 in V3)
+        int msgLen = dstBuf.position() - 2;   // Exclude the legth field itself
+        dstBuf.position(0);
+        dstBuf.put((byte)(0x80 | ((msgLen >>> 8) & 0xFF)));  // pos: 0
+        dstBuf.put((byte)(msgLen & 0xFF));                   // pos: 1
+        dstBuf.put(HandshakeMessage.ht_client_hello);        // pos: 2
+        dstBuf.put(fragment[offset]);         // major version, pos: 3
+        dstBuf.put(fragment[offset + 1]);     // minor version, pos: 4
+        dstBuf.put((byte)(v2CSLen >>> 8));                   // pos: 5
+        dstBuf.put((byte)(v2CSLen & 0xFF));                  // pos: 6
+        dstBuf.put((byte)0x00);           // session_id_length, pos: 7
+        dstBuf.put((byte)0x00);                              // pos: 8
+        dstBuf.put((byte)0x00);           // challenge_length,  pos: 9
+        dstBuf.put((byte)32);                                // pos: 10
 
-        /*
-         * Copy in the nonce.
-         */
-        System.arraycopy(v3Msg, 2, buf, count, 32);
-        count += 32;
+        dstBuf.position(0);
+        dstBuf.limit(msgLen + 2);
 
-        /*
-         * Set the length of the message.
-         */
-        count -= 2; // don't include length field itself
-        buf[0] = (byte)(count >>> 8);
-        buf[0] |= 0x80;
-        buf[1] = (byte)(count);
-        count += 2;
+        return dstBuf;
     }
 
-    /*
-     * Mappings from V3 cipher suite encodings to their pure V2 equivalents.
-     * This is taken from the SSL V3 specification, Appendix E.
-     */
-    private static int[] V3toV2CipherMap1 =
-        {-1, -1, -1, 0x02, 0x01, -1, 0x04, 0x05, -1, 0x06, 0x07};
-    private static int[] V3toV2CipherMap3 =
-        {-1, -1, -1, 0x80, 0x80, -1, 0x80, 0x80, -1, 0x40, 0xC0};
+    private static int V3toV2CipherSuite(ByteBuffer dstBuf,
+            byte byte1, byte byte2) {
+        dstBuf.put((byte)0);
+        dstBuf.put(byte1);
+        dstBuf.put(byte2);
 
-    /*
-     * See which matching pure-V2 cipher specs we need to include.
-     * We are including these not because we are actually prepared
-     * to talk V2 but because the Oracle Web Server insists on receiving
-     * at least 1 "pure V2" cipher suite that it supports and returns an
-     * illegal_parameter alert unless one is present. Rather than mindlessly
-     * claiming to implement all documented pure V2 cipher suites the code below
-     * just claims to implement the V2 cipher suite that is "equivalent"
-     * in terms of cipher algorithm & exportability with the actual V3 cipher
-     * suite that we do support.
-     */
-    private int V3toV2CipherSuite(byte byte1, byte byte2) {
-        buf[count++] = 0;
-        buf[count++] = byte1;
-        buf[count++] = byte2;
-
-        if (((byte2 & 0xff) > 0xA) ||
-                (V3toV2CipherMap1[byte2] == -1)) {
+        if (((byte2 & 0xff) > 0xA) || (V3toV2CipherMap1[byte2] == -1)) {
             return 3;
         }
 
-        buf[count++] = (byte)V3toV2CipherMap1[byte2];
-        buf[count++] = 0;
-        buf[count++] = (byte)V3toV2CipherMap3[byte2];
+        dstBuf.put((byte)V3toV2CipherMap1[byte2]);
+        dstBuf.put((byte)0);
+        dstBuf.put((byte)V3toV2CipherMap3[byte2]);
 
         return 6;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/Plaintext.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.security.ssl;
+
+import java.nio.ByteBuffer;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+
+/*
+ * Plaintext
+ */
+final class Plaintext {
+    final static Plaintext PLAINTEXT_NULL = new Plaintext();
+
+    byte            contentType;
+    byte            majorVersion;
+    byte            minorVersion;
+    int             recordEpoch;    // incremented on every cipher state change
+    long            recordSN;
+    ByteBuffer      fragment;       // null if need to be reassembled
+
+    HandshakeStatus handshakeStatus;    // null if not used or not handshaking
+
+    Plaintext() {
+        this.contentType = 0;
+        this.majorVersion = 0;
+        this.minorVersion = 0;
+        this.recordEpoch = -1;
+        this.recordSN = -1;
+        this.fragment = null;
+        this.handshakeStatus = null;
+    }
+
+    Plaintext(byte contentType, byte majorVersion, byte minorVersion,
+            int recordEpoch, long recordSN, ByteBuffer fragment) {
+
+        this.contentType = contentType;
+        this.majorVersion = majorVersion;
+        this.minorVersion = minorVersion;
+        this.recordEpoch = recordEpoch;
+        this.recordSN = recordSN;
+        this.fragment = fragment;
+
+        this.handshakeStatus = null;
+    }
+
+    public String toString() {
+        return "contentType: " + contentType + "/" +
+               "majorVersion: " + majorVersion + "/" +
+               "minorVersion: " + minorVersion + "/" +
+               "recordEpoch: " + recordEpoch + "/" +
+               "recordSN: 0x" + Long.toHexString(recordSN) + "/" +
+               "fragment: " + fragment;
+    }
+}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ProtocolList.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ProtocolList.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -124,8 +124,9 @@
     ProtocolVersion selectProtocolVersion(ProtocolVersion protocolVersion) {
         ProtocolVersion selectedVersion = null;
         for (ProtocolVersion pv : protocols) {
-            if (pv.v > protocolVersion.v) {
-                break;  // Safe to break here as this.protocols is sorted
+            if (pv.compareTo(protocolVersion) > 0) {
+                break;      // Safe to break here as this.protocols is sorted,
+                            // and DTLS and SSL/TLS protocols are not mixed.
             }
             selectedVersion = pv;
         }
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ProtocolVersion.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ProtocolVersion.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,7 @@
 
 import java.util.*;
 import java.security.CryptoPrimitive;
+import sun.security.ssl.CipherSuite.*;
 
 /**
  * Type safe enum for an SSL/TLS protocol version. Instances are obtained
@@ -61,9 +62,9 @@
     // Dummy protocol version value for invalid SSLSession
     final static ProtocolVersion NONE = new ProtocolVersion(-1, "NONE");
 
-    // If enabled, send/ accept SSLv2 hello messages
-    final static ProtocolVersion SSL20Hello = new ProtocolVersion(0x0002,
-                                                                "SSLv2Hello");
+    // If enabled, send/accept SSLv2 hello messages
+    final static ProtocolVersion SSL20Hello =
+                                new ProtocolVersion(0x0002, "SSLv2Hello");
 
     // SSL 3.0
     final static ProtocolVersion SSL30 = new ProtocolVersion(0x0300, "SSLv3");
@@ -77,6 +78,19 @@
     // TLS 1.2
     final static ProtocolVersion TLS12 = new ProtocolVersion(0x0303, "TLSv1.2");
 
+    // DTLS 1.0
+    // {254, 255}, the version value of DTLS 1.0.
+    final static ProtocolVersion DTLS10 =
+                                new ProtocolVersion(0xFEFF, "DTLSv1.0");
+
+    // No DTLS 1.1, that version number was skipped in order to harmonize
+    // version numbers with TLS.
+
+    // DTLS 1.2
+    // {254, 253}, the version value of DTLS 1.2.
+    final static ProtocolVersion DTLS12 =
+                                new ProtocolVersion(0xFEFD, "DTLSv1.2");
+
     private static final boolean FIPS = SunJSSE.isFIPS();
 
     // minimum version we implement (SSL 3.0)
@@ -85,8 +99,11 @@
     // maximum version we implement (TLS 1.2)
     final static ProtocolVersion MAX = TLS12;
 
-    // ProtocolVersion to use by default (TLS 1.2)
-    final static ProtocolVersion DEFAULT = TLS12;
+    // SSL/TLS ProtocolVersion to use by default (TLS 1.2)
+    final static ProtocolVersion DEFAULT_TLS = TLS12;
+
+    // DTLS ProtocolVersion to use by default (TLS 1.2)
+    final static ProtocolVersion DEFAULT_DTLS = DTLS12;
 
     // Default version for hello messages (SSLv2Hello)
     final static ProtocolVersion DEFAULT_HELLO = FIPS ? TLS10 : SSL30;
@@ -108,10 +125,10 @@
 
     // Initialize the available protocols.
     static {
-        Set<ProtocolVersion> protocols = new HashSet<>(5);
+        Set<ProtocolVersion> protocols = new HashSet<>(7);
 
         ProtocolVersion[] pvs = new ProtocolVersion[] {
-                SSL20Hello, SSL30, TLS10, TLS11, TLS12};
+                SSL20Hello, SSL30, TLS10, TLS11, TLS12, DTLS10, DTLS12};
         EnumSet<CryptoPrimitive> cryptoPrimitives =
             EnumSet.<CryptoPrimitive>of(CryptoPrimitive.KEY_AGREEMENT);
         for (ProtocolVersion p : pvs) {
@@ -145,6 +162,10 @@
             return TLS12;
         } else if (v == SSL20Hello.v) {
             return SSL20Hello;
+        } else if (v == DTLS10.v) {
+            return DTLS10;
+        } else if (v == DTLS12.v) {
+            return DTLS12;
         } else {
             int major = (v >>> 8) & 0xFF;
             int minor = v & 0xFF;
@@ -172,8 +193,8 @@
         }
 
         if (FIPS && (name.equals(SSL30.name) || name.equals(SSL20Hello.name))) {
-            throw new IllegalArgumentException
-                ("Only TLS 1.0 or later allowed in FIPS mode");
+            throw new IllegalArgumentException(
+                    "Only TLS 1.0 or later allowed in FIPS mode");
         }
 
         if (name.equals(SSL30.name)) {
@@ -186,6 +207,10 @@
             return TLS12;
         } else if (name.equals(SSL20Hello.name)) {
             return SSL20Hello;
+        } else if (name.equals(DTLS10.name)) {
+            return DTLS10;
+        } else if (name.equals(DTLS12.name)) {
+            return DTLS12;
         } else {
             throw new IllegalArgumentException(name);
         }
@@ -201,6 +226,90 @@
      */
     @Override
     public int compareTo(ProtocolVersion protocolVersion) {
-        return this.v - protocolVersion.v;
+        if (maybeDTLSProtocol()) {
+            if (!protocolVersion.maybeDTLSProtocol()) {
+                throw new IllegalArgumentException("Not DTLS protocol");
+            }
+
+            return protocolVersion.v - this.v;
+        } else {
+            if (protocolVersion.maybeDTLSProtocol()) {
+                throw new IllegalArgumentException("Not TLS protocol");
+            }
+
+            return this.v - protocolVersion.v;
+        }
+    }
+
+    /**
+     * Returns true if a ProtocolVersion represents a DTLS protocol.
+     */
+    boolean isDTLSProtocol() {
+        return this.v == DTLS12.v || this.v == DTLS10.v;
+    }
+
+    /**
+     * Returns true if a ProtocolVersion may represent a DTLS protocol.
+     */
+    boolean maybeDTLSProtocol() {
+        return (this.major & 0x80) != 0;
+    }
+
+    boolean useTLS12PlusSpec() {
+        return maybeDTLSProtocol() ? (this.v <= DTLS12.v) : (this.v >= TLS12.v);
+    }
+
+    boolean useTLS11PlusSpec() {
+        return maybeDTLSProtocol() ? true : (this.v >= TLS11.v);
+    }
+
+    boolean useTLS10PlusSpec() {
+        return maybeDTLSProtocol() ? true : (this.v >= TLS10.v);
+    }
+
+    boolean obsoletes(CipherSuite suite) {
+        ProtocolVersion proto = this;
+        if (proto.isDTLSProtocol()) {
+            // DTLS bans stream ciphers.
+            if (suite.cipher.cipherType == CipherType.STREAM_CIPHER) {
+                return true;
+            }
+
+            proto = mapToTLSProtocol(this);
+        }
+
+        return (proto.v >= suite.obsoleted);
+    }
+
+    boolean supports(CipherSuite suite) {
+        ProtocolVersion proto = this;
+        if (proto.isDTLSProtocol()) {
+            // DTLS bans stream ciphers.
+            if (suite.cipher.cipherType == CipherType.STREAM_CIPHER) {
+                return false;
+            }
+
+            proto = mapToTLSProtocol(this);
+        }
+
+        return (proto.v >= suite.supported);
+    }
+
+    // Map a specified protocol to the corresponding TLS version.
+    //
+    // DTLS 1.2 -> TLS 1.2
+    // DTLS 1.0 -> TLS 1.1
+    private static ProtocolVersion mapToTLSProtocol(
+            ProtocolVersion protocolVersion) {
+
+        if (protocolVersion.isDTLSProtocol()) {
+            if (protocolVersion.v == DTLS10.v) {
+                protocolVersion = TLS11;
+            } else {    // DTLS12
+                protocolVersion = TLS12;
+            }
+        }
+
+        return protocolVersion;
     }
 }
--- a/jdk/src/java.base/share/classes/sun/security/ssl/RSAClientKeyExchange.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/RSAClientKeyExchange.java	Wed Jul 05 20:37:09 2017 +0200
@@ -73,8 +73,8 @@
         this.protocolVersion = protocolVersion;
 
         try {
-            String s = ((protocolVersion.v >= ProtocolVersion.TLS12.v) ?
-                "SunTls12RsaPremasterSecret" : "SunTlsRsaPremasterSecret");
+            String s = protocolVersion.useTLS12PlusSpec() ?
+                "SunTls12RsaPremasterSecret" : "SunTlsRsaPremasterSecret";
             KeyGenerator kg = JsseJce.getKeyGenerator(s);
             kg.init(new TlsRsaPremasterSecretParameterSpec(
                     maxVersion.v, protocolVersion.v), generator);
@@ -103,7 +103,7 @@
             throw new SSLKeyException("Private key not of type RSA");
         }
 
-        if (currentVersion.v >= ProtocolVersion.TLS10.v) {
+        if (currentVersion.useTLS10PlusSpec()) {
             encrypted = input.getBytes16();
         } else {
             encrypted = new byte [messageSize];
@@ -142,7 +142,7 @@
 
     @Override
     int messageLength() {
-        if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
+        if (protocolVersion.useTLS10PlusSpec()) {
             return encrypted.length + 2;
         } else {
             return encrypted.length;
@@ -151,7 +151,7 @@
 
     @Override
     void send(HandshakeOutStream s) throws IOException {
-        if (protocolVersion.v >= ProtocolVersion.TLS10.v) {
+        if (protocolVersion.useTLS10PlusSpec()) {
             s.putBytes16(encrypted);
         } else {
             s.write(encrypted);
--- a/jdk/src/java.base/share/classes/sun/security/ssl/RandomCookie.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/RandomCookie.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -70,10 +70,10 @@
     void print(PrintStream s) {
         int i, gmt_unix_time;
 
-        gmt_unix_time = random_bytes[0] << 24;
-        gmt_unix_time += random_bytes[1] << 16;
-        gmt_unix_time += random_bytes[2] << 8;
-        gmt_unix_time += random_bytes[3];
+        gmt_unix_time = ((random_bytes[0] & 0xFF) << 24) |
+                        ((random_bytes[1] & 0xFF) << 16) |
+                        ((random_bytes[2] & 0xFF) << 8) |
+                         (random_bytes[3] & 0xFF);
 
         s.print("GMT: " + gmt_unix_time + " ");
         s.print("bytes = { ");
--- a/jdk/src/java.base/share/classes/sun/security/ssl/Record.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/Record.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,21 +23,20 @@
  * questions.
  */
 
-
 package sun.security.ssl;
 
-
 /**
- * SSL/TLS records, as pulled off (and put onto) a TCP stream.  This is
+ * SSL/TLS/DTLS records, as pulled off (and put onto) a TCP stream.  This is
  * the base interface, which defines common information and interfaces
  * used by both Input and Output records.
  *
  * @author David Brownell
  */
 interface Record {
+
     /*
-     * There are four SSL record types, which are part of the interface
-     * to this level (along with the maximum record size)
+     * There are four record types, which are part of the interface
+     * to this level (along with the maximum record size).
      *
      * enum { change_cipher_spec(20), alert(21), handshake(22),
      *      application_data(23), (255) } ContentType;
@@ -47,75 +46,20 @@
     static final byte   ct_handshake = 22;
     static final byte   ct_application_data = 23;
 
-    static final int    headerSize = 5;         // SSLv3 record header
-    static final int    maxExpansion = 1024;    // for bad compression
-    static final int    trailerSize = 20;       // SHA1 hash size
+    static final int    maxMacSize = 48;        // the max supported MAC or
+                                                // AEAD tag size
     static final int    maxDataSize = 16384;    // 2^14 bytes of data
     static final int    maxPadding = 256;       // block cipher padding
-    static final int    maxIVLength = 256;      // IV length
-
-    /*
-     * The size of the header plus the max IV length
-     */
-    static final int    headerPlusMaxIVSize =
-                                      headerSize        // header
-                                    + maxIVLength;      // iv
+    static final int    maxIVLength = 16;       // the max supported IV length
 
-    /*
-     * SSL has a maximum record size.  It's header, (compressed) data,
-     * padding, and a trailer for the message authentication information (MAC
-     * for block and stream ciphers, and message authentication tag for AEAD
-     * ciphers).
-     *
-     * Some compression algorithms have rare cases where they expand the data.
-     * As we don't support compression at this time, leave that out.
-     */
-    static final int    maxRecordSize =
-                                      headerPlusMaxIVSize   // header + iv
-                                    + maxDataSize           // data
-                                    + maxPadding            // padding
-                                    + trailerSize;          // MAC or AEAD tag
-
-    static final boolean enableCBCProtection =
-            Debug.getBooleanProperty("jsse.enableCBCProtection", true);
+    static final int    maxFragmentSize = 18432;    // the max fragment size
+                                                    // 2^14 + 2048
 
     /*
-     * For CBC protection in SSL3/TLS1, we break some plaintext into two
-     * packets.  Max application data size for the second packet.
+     * System property to enable/disable CBC protection in SSL3/TLS1.
      */
-    static final int    maxDataSizeMinusOneByteRecord =
-                                  maxDataSize       // max data size
-                                - (                 // max one byte record size
-                                      headerPlusMaxIVSize   // header + iv
-                                    + 1             // one byte data
-                                    + maxPadding    // padding
-                                    + trailerSize   // MAC
-                                  );
-
-    /*
-     * The maximum large record size.
-     *
-     * Some SSL/TLS implementations support large fragment upto 2^15 bytes,
-     * such as Microsoft. We support large incoming fragments.
-     *
-     * The maximum large record size is defined as maxRecordSize plus 2^14,
-     * this is the amount OpenSSL is using.
-     */
-    static final int    maxLargeRecordSize =
-                maxRecordSize   // Max size with a conforming implementation
-              + maxDataSize;    // extra 2^14 bytes for large data packets.
-
-
-    /*
-     * Maximum record size for alert and change cipher spec records.
-     * They only contain 2 and 1 bytes of data, respectively.
-     * Allocate a smaller array.
-     */
-    static final int    maxAlertRecordSize =
-                                      headerPlusMaxIVSize   // header + iv
-                                    + 2                     // alert
-                                    + maxPadding            // padding
-                                    + trailerSize;          // MAC
+    static final boolean enableCBCProtection =
+            Debug.getBooleanProperty("jsse.enableCBCProtection", true);
 
     /*
      * The overflow values of integers of 8, 16 and 24 bits.
@@ -123,4 +67,27 @@
     static final int OVERFLOW_OF_INT08 = (1 << 8);
     static final int OVERFLOW_OF_INT16 = (1 << 16);
     static final int OVERFLOW_OF_INT24 = (1 << 24);
+
+    /**
+     * Return a description for the given content type.
+     */
+    static String contentName(byte contentType) {
+        switch (contentType) {
+        case ct_change_cipher_spec:
+            return "Change Cipher Spec";
+        case ct_alert:
+            return "Alert";
+        case ct_handshake:
+            return "Handshake";
+        case ct_application_data:
+            return "Application Data";
+        default:
+            return "contentType = " + contentType;
+        }
+    }
+
+    static boolean isValidContentType(byte contentType) {
+        return (contentType == 20) || (contentType == 21) ||
+               (contentType == 22) || (contentType == 23);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/RecordType.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.security.ssl;
+
+/*
+ * enumation of record type
+ */
+enum RecordType {
+
+    RECORD_CHANGE_CIPHER_SPEC   (Record.ct_change_cipher_spec,
+                                    HandshakeMessage.ht_not_applicable),
+    RECORD_ALERT                (Record.ct_alert,
+                                    HandshakeMessage.ht_not_applicable),
+    RECORD_HELLO_REQUEST        (Record.ct_handshake,
+                                    HandshakeMessage.ht_hello_request),
+    RECORD_CLIENT_HELLO         (Record.ct_handshake,
+                                    HandshakeMessage.ht_client_hello),
+    RECORD_SERVER_HELLO         (Record.ct_handshake,
+                                    HandshakeMessage.ht_server_hello),
+    RECORD_HELLO_VERIFY_REQUEST (Record.ct_handshake,
+                                    HandshakeMessage.ht_hello_verify_request),
+    RECORD_NEW_SESSION_TICKET   (Record.ct_handshake,
+                                    HandshakeMessage.ht_new_session_ticket),
+    RECORD_CERTIFICATE          (Record.ct_handshake,
+                                    HandshakeMessage.ht_certificate),
+    RECORD_SERVER_KEY_EXCHANGE  (Record.ct_handshake,
+                                    HandshakeMessage.ht_server_key_exchange),
+    RECORD_CERTIFICATE_REQUEST  (Record.ct_handshake,
+                                    HandshakeMessage.ht_certificate_request),
+    RECORD_SERVER_HELLO_DONE    (Record.ct_handshake,
+                                    HandshakeMessage.ht_server_hello_done),
+    RECORD_CERTIFICATE_VERIFY   (Record.ct_handshake,
+                                    HandshakeMessage.ht_certificate_verify),
+    RECORD_CLIENT_KEY_EXCHANGE  (Record.ct_handshake,
+                                    HandshakeMessage.ht_client_key_exchange),
+    RECORD_FINISHED             (Record.ct_handshake,
+                                    HandshakeMessage.ht_finished),
+    RECORD_CERTIFICATE_URL      (Record.ct_handshake,
+                                    HandshakeMessage.ht_certificate_url),
+    RECORD_CERTIFICATE_STATUS   (Record.ct_handshake,
+                                    HandshakeMessage.ht_certificate_status),
+    RECORD_SUPPLIEMENTAL_DATA   (Record.ct_handshake,
+                                    HandshakeMessage.ht_supplemental_data),
+    RECORD_APPLICATION_DATA     (Record.ct_application_data,
+                                    HandshakeMessage.ht_not_applicable);
+
+    byte            contentType;
+    byte            handshakeType;
+
+    private RecordType(byte contentType, byte handshakeType) {
+        this.contentType = contentType;
+        this.handshakeType = handshakeType;
+    }
+
+    static RecordType valueOf(byte contentType, byte handshakeType) {
+        if (contentType == Record.ct_change_cipher_spec) {
+            return RECORD_CHANGE_CIPHER_SPEC;
+        } else if (contentType == Record.ct_alert) {
+            return RECORD_ALERT;
+        } else if (contentType == Record.ct_application_data) {
+            return RECORD_APPLICATION_DATA;
+        } else if (handshakeType == HandshakeMessage.ht_hello_request) {
+            return RECORD_HELLO_REQUEST;
+        } else if (handshakeType == HandshakeMessage.ht_client_hello) {
+            return RECORD_CLIENT_HELLO;
+        } else if (handshakeType == HandshakeMessage.ht_server_hello) {
+            return RECORD_SERVER_HELLO;
+        } else if (handshakeType == HandshakeMessage.ht_hello_verify_request) {
+            return RECORD_HELLO_VERIFY_REQUEST;
+        } else if (handshakeType == HandshakeMessage.ht_new_session_ticket) {
+            return RECORD_NEW_SESSION_TICKET;
+        } else if (handshakeType == HandshakeMessage.ht_certificate) {
+            return RECORD_CERTIFICATE;
+        } else if (handshakeType == HandshakeMessage.ht_server_key_exchange) {
+            return RECORD_SERVER_KEY_EXCHANGE;
+        } else if (handshakeType == HandshakeMessage.ht_certificate_request) {
+            return RECORD_CERTIFICATE_REQUEST;
+        } else if (handshakeType == HandshakeMessage.ht_server_hello_done) {
+            return RECORD_SERVER_HELLO_DONE;
+        } else if (handshakeType == HandshakeMessage.ht_certificate_verify) {
+            return RECORD_CERTIFICATE_VERIFY;
+        } else if (handshakeType == HandshakeMessage.ht_client_key_exchange) {
+            return RECORD_CLIENT_KEY_EXCHANGE;
+        } else if (handshakeType == HandshakeMessage.ht_finished) {
+            return RECORD_FINISHED;
+        } else if (handshakeType == HandshakeMessage.ht_certificate_url) {
+            return RECORD_CERTIFICATE_URL;
+        } else if (handshakeType == HandshakeMessage.ht_certificate_status) {
+            return RECORD_CERTIFICATE_STATUS;
+        } else if (handshakeType == HandshakeMessage.ht_supplemental_data) {
+            return RECORD_SUPPLIEMENTAL_DATA;
+        }
+
+        // otherwise, invalid record type
+        throw new IllegalArgumentException(
+                "Invalid record type (ContentType:" + contentType +
+                ", HandshakeType:" + handshakeType + ")");
+    }
+}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLAlgorithmConstraints.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLAlgorithmConstraints.java	Wed Jul 05 20:37:09 2017 +0200
@@ -352,18 +352,13 @@
                         components.add("ECDH_ANON");
                     }
                     break;
-                case K_KRB5:
-                    if (!forCertPathOnly) {
-                        components.add("KRB5");
+                default:
+                    if (ClientKeyExchangeService.find(keyExchange.name) != null) {
+                        if (!forCertPathOnly) {
+                            components.add(keyExchange.name);
+                        }
                     }
-                    break;
-                case K_KRB5_EXPORT:
-                    if (!forCertPathOnly) {
-                        components.add("KRB5_EXPORT");
-                    }
-                    break;
-                default:
-                    // ignore
+                    // otherwise ignore
             }
 
             return components;
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -62,6 +62,9 @@
     private CipherSuiteList defaultClientCipherSuiteList;
     private CipherSuiteList supportedCipherSuiteList;
 
+    // DTLS cookie exchange manager
+    private HelloCookieManager helloCookieManager;
+
     SSLContextImpl() {
         ephemeralKeyManager = new EphemeralKeyManager();
         clientCache = new SSLSessionContextImpl();
@@ -175,11 +178,29 @@
         return DummyX509KeyManager.INSTANCE;
     }
 
+    abstract SSLEngine createSSLEngineImpl();
+    abstract SSLEngine createSSLEngineImpl(String host, int port);
+
+    @Override
+    protected SSLEngine engineCreateSSLEngine() {
+        if (!isInitialized) {
+            throw new IllegalStateException("SSLContext is not initialized");
+        }
+        return createSSLEngineImpl();
+    }
+
+    @Override
+    protected SSLEngine engineCreateSSLEngine(String host, int port) {
+        if (!isInitialized) {
+            throw new IllegalStateException("SSLContext is not initialized");
+        }
+        return createSSLEngineImpl(host, port);
+    }
+
     @Override
     protected SSLSocketFactory engineGetSocketFactory() {
         if (!isInitialized) {
-            throw new IllegalStateException(
-                "SSLContextImpl is not initialized");
+            throw new IllegalStateException("SSLContext is not initialized");
         }
        return new SSLSocketFactoryImpl(this);
     }
@@ -193,24 +214,6 @@
     }
 
     @Override
-    protected SSLEngine engineCreateSSLEngine() {
-        if (!isInitialized) {
-            throw new IllegalStateException(
-                "SSLContextImpl is not initialized");
-        }
-        return new SSLEngineImpl(this);
-    }
-
-    @Override
-    protected SSLEngine engineCreateSSLEngine(String host, int port) {
-        if (!isInitialized) {
-            throw new IllegalStateException(
-                "SSLContextImpl is not initialized");
-        }
-        return new SSLEngineImpl(this, host, port);
-    }
-
-    @Override
     protected SSLSessionContext engineGetClientSessionContext() {
         return clientCache;
     }
@@ -236,6 +239,23 @@
         return ephemeralKeyManager;
     }
 
+    HelloCookieManager getHelloCookieManager() {
+        if (!isInitialized) {
+            throw new IllegalStateException("SSLContext is not initialized");
+        }
+
+        if (helloCookieManager == null) {
+            helloCookieManager = getHelloCookieManager(secureRandom);
+        }
+
+        return helloCookieManager;
+    }
+
+    HelloCookieManager getHelloCookieManager(SecureRandom secureRandom) {
+        throw new UnsupportedOperationException(
+                "Cookie exchange applies to DTLS only");
+    }
+
     abstract SSLParameters getDefaultServerSSLParams();
     abstract SSLParameters getDefaultClientSSLParams();
     abstract SSLParameters getSupportedSSLParams();
@@ -319,12 +339,20 @@
                (protocols == defaultClientProtocolList);
     }
 
+    /**
+     * Return whether a protocol list is the original default enabled
+     * protocols.  See: SSLSocket/SSLEngine.setEnabledProtocols()
+     */
+    boolean isDefaultCipherSuiteList(CipherSuiteList cipherSuites) {
+        return (cipherSuites == defaultClientCipherSuiteList) ||
+               (cipherSuites == defaultServerCipherSuiteList);
+    }
 
     /*
      * Return the list of all available CipherSuites with a priority of
      * minPriority or above.
      */
-    private CipherSuiteList getApplicableCipherSuiteList(
+    private static CipherSuiteList getApplicableCipherSuiteList(
             ProtocolList protocols, boolean onlyEnabled) {
 
         int minPriority = CipherSuite.SUPPORTED_SUITES_PRIORITY;
@@ -344,8 +372,8 @@
                 }
 
                 if (suite.isAvailable() &&
-                        suite.obsoleted > protocols.min.v &&
-                        suite.supported <= protocols.max.v) {
+                        !protocols.min.obsoletes(suite) &&
+                        protocols.max.supports(suite)) {
                     if (SSLAlgorithmConstraints.DEFAULT.permits(
                             EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
                             suite.name, null)) {
@@ -353,10 +381,10 @@
                     }
                 } else if (debug != null &&
                         Debug.isOn("sslctx") && Debug.isOn("verbose")) {
-                    if (suite.obsoleted <= protocols.min.v) {
+                    if (protocols.min.obsoletes(suite)) {
                         System.out.println(
                             "Ignoring obsoleted cipher suite: " + suite);
-                    } else if (suite.supported > protocols.max.v) {
+                    } else if (!protocols.max.supports(suite)) {
                         System.out.println(
                             "Ignoring unsupported cipher suite: " + suite);
                     } else {
@@ -388,8 +416,25 @@
         }
     }
 
+    private static String[] getAvailableProtocols(
+            ProtocolVersion[] protocolCandidates) {
+
+        List<String> availableProtocols = Collections.<String>emptyList();
+        if (protocolCandidates !=  null && protocolCandidates.length != 0) {
+            availableProtocols = new ArrayList<>(protocolCandidates.length);
+            for (ProtocolVersion p : protocolCandidates) {
+                if (ProtocolVersion.availableProtocols.contains(p)) {
+                    availableProtocols.add(p.name);
+                }
+            }
+        }
+
+        return availableProtocols.toArray(new String[0]);
+    }
+
+
     /*
-     * The SSLContext implementation for TLS/SSL algorithm
+     * The SSLContext implementation for SSL/(D)TLS algorithm
      *
      * SSL/TLS protocols specify the forward compatibility and version
      * roll-back attack protections, however, a number of SSL/TLS server
@@ -418,14 +463,15 @@
      */
 
     /*
-     * The base abstract SSLContext implementation.
+     * The base abstract SSLContext implementation for the Transport Layer
+     * Security (TLS) protocols.
      *
      * This abstract class encapsulates supported and the default server
-     * SSL parameters.
+     * SSL/TLS parameters.
      *
      * @see SSLContext
      */
-    private abstract static class AbstractSSLContext extends SSLContextImpl {
+    private abstract static class AbstractTLSContext extends SSLContextImpl {
         // parameters
         private static final SSLParameters defaultServerSSLParams;
         private static final SSLParameters supportedSSLParams;
@@ -482,20 +528,14 @@
             return supportedSSLParams;
         }
 
-        static String[] getAvailableProtocols(
-                ProtocolVersion[] protocolCandidates) {
+        @Override
+        SSLEngine createSSLEngineImpl() {
+            return new SSLEngineImpl(this, false);
+        }
 
-            List<String> availableProtocols = Collections.<String>emptyList();
-            if (protocolCandidates !=  null && protocolCandidates.length != 0) {
-                availableProtocols = new ArrayList<>(protocolCandidates.length);
-                for (ProtocolVersion p : protocolCandidates) {
-                    if (ProtocolVersion.availableProtocols.contains(p)) {
-                        availableProtocols.add(p.name);
-                    }
-                }
-            }
-
-            return availableProtocols.toArray(new String[0]);
+        @Override
+        SSLEngine createSSLEngineImpl(String host, int port) {
+            return new SSLEngineImpl(this, host, port, false);
         }
     }
 
@@ -504,7 +544,7 @@
      *
      * @see SSLContext
      */
-    public static final class TLS10Context extends AbstractSSLContext {
+    public static final class TLS10Context extends AbstractTLSContext {
         private static final SSLParameters defaultClientSSLParams;
 
         static {
@@ -537,7 +577,7 @@
      *
      * @see SSLContext
      */
-    public static final class TLS11Context extends AbstractSSLContext {
+    public static final class TLS11Context extends AbstractTLSContext {
         private static final SSLParameters defaultClientSSLParams;
 
         static {
@@ -572,7 +612,7 @@
      *
      * @see SSLContext
      */
-    public static final class TLS12Context extends AbstractSSLContext {
+    public static final class TLS12Context extends AbstractTLSContext {
         private static final SSLParameters defaultClientSSLParams;
 
         static {
@@ -605,12 +645,73 @@
     }
 
     /*
+     * The interface for the customized SSL/(D)TLS SSLContext.
+     *
+     * @see SSLContext
+     */
+    private static class CustomizedSSLProtocols {
+        private final static String PROPERTY_NAME = "jdk.tls.client.protocols";
+        static IllegalArgumentException reservedException = null;
+        static ArrayList<ProtocolVersion>
+                                customizedProtocols = new ArrayList<>();
+
+        // Don't want a java.lang.LinkageError for illegal system property.
+        //
+        // Please don't throw exception in this static block.  Otherwise,
+        // java.lang.LinkageError may be thrown during the instantiation of
+        // the provider service. Instead, please handle the initialization
+        // exception in the caller's constructor.
+        static {
+            String property = AccessController.doPrivileged(
+                    new GetPropertyAction(PROPERTY_NAME));
+            if (property != null && property.length() != 0) {
+                // remove double quote marks from beginning/end of the property
+                if (property.length() > 1 && property.charAt(0) == '"' &&
+                        property.charAt(property.length() - 1) == '"') {
+                    property = property.substring(1, property.length() - 1);
+                }
+            }
+
+            if (property != null && property.length() != 0) {
+                String[] protocols = property.split(",");
+                for (int i = 0; i < protocols.length; i++) {
+                    protocols[i] = protocols[i].trim();
+                    // Is it a supported protocol name?
+                    try {
+                        ProtocolVersion pro =
+                                ProtocolVersion.valueOf(protocols[i]);
+
+                        if (SunJSSE.isFIPS() &&
+                                ((pro.v == ProtocolVersion.SSL30.v) ||
+                                 (pro.v == ProtocolVersion.SSL20Hello.v))) {
+                            reservedException = new IllegalArgumentException(
+                                    PROPERTY_NAME + ": " + pro +
+                                    " is not FIPS compliant");
+
+                            break;
+                        }
+
+                        // ignore duplicated protocols
+                        if (!customizedProtocols.contains(pro)) {
+                            customizedProtocols.add(pro);
+                        }
+                    } catch (IllegalArgumentException iae) {
+                        reservedException = new IllegalArgumentException(
+                                PROPERTY_NAME + ": " + protocols[i] +
+                                " is not a standard SSL protocol name", iae);
+                    }
+                }
+            }
+        }
+    }
+
+    /*
      * The SSLContext implementation for customized TLS protocols
      *
      * @see SSLContext
      */
-    private static class CustomizedSSLContext extends AbstractSSLContext {
-        private static final String PROPERTY_NAME = "jdk.tls.client.protocols";
+    private static class CustomizedTLSContext extends AbstractTLSContext {
+
         private static final SSLParameters defaultClientSSLParams;
         private static IllegalArgumentException reservedException = null;
 
@@ -621,78 +722,52 @@
         // the provider service. Instead, let's handle the initialization
         // exception in constructor.
         static {
-            // candidates for available protocols
-            ProtocolVersion[] candidates;
-
-            String property = AccessController.doPrivileged(
-                    new GetPropertyAction(PROPERTY_NAME));
-            if (property == null || property.length() == 0) {
-                // the default enabled client TLS protocols
-                if (SunJSSE.isFIPS()) {
-                    candidates = new ProtocolVersion[] {
-                        ProtocolVersion.TLS10,
-                        ProtocolVersion.TLS11,
-                        ProtocolVersion.TLS12
-                    };
-                } else {
-                    candidates = new ProtocolVersion[] {
-                        ProtocolVersion.SSL30,
-                        ProtocolVersion.TLS10,
-                        ProtocolVersion.TLS11,
-                        ProtocolVersion.TLS12
-                    };
-                }
-            } else {
-                // remove double quote marks from beginning/end of the property
-                if (property.length() > 1 && property.charAt(0) == '"' &&
-                        property.charAt(property.length() - 1) == '"') {
-                    property = property.substring(1, property.length() - 1);
-                }
-
-                String[] protocols = null;
-                if (property != null && property.length() != 0) {
-                    protocols = property.split(",");
-                } else {
-                    reservedException = new IllegalArgumentException(
-                        "No protocol specified in " +
-                        PROPERTY_NAME + " system property");
-                    protocols = new String[0];
-                }
-
-                candidates = new ProtocolVersion[protocols.length];
-                for (int i = 0; i < protocols.length; i++) {
-                    protocols[i] = protocols[i].trim();
-                    // Is it a supported protocol name?
-                    try {
-                        candidates[i] = ProtocolVersion.valueOf(protocols[i]);
-                    } catch (IllegalArgumentException iae) {
-                        reservedException = new IllegalArgumentException(
-                            PROPERTY_NAME + ": " + protocols[i] +
-                            " is not a standard SSL/TLS protocol name", iae);
-                        break;
+            reservedException = CustomizedSSLProtocols.reservedException;
+            if (reservedException == null) {
+                ArrayList<ProtocolVersion>
+                        customizedTLSProtocols = new ArrayList<>();
+                for (ProtocolVersion protocol :
+                        CustomizedSSLProtocols.customizedProtocols) {
+                    if (!protocol.isDTLSProtocol()) {
+                        customizedTLSProtocols.add(protocol);
                     }
                 }
 
-                if ((reservedException == null) && SunJSSE.isFIPS()) {
-                    for (ProtocolVersion protocolVersion : candidates) {
-                        if (ProtocolVersion.SSL20Hello.v == protocolVersion.v ||
-                                ProtocolVersion.SSL30.v == protocolVersion.v) {
-                            reservedException = new IllegalArgumentException(
-                                    PROPERTY_NAME + ": " + protocolVersion +
-                                    " is not FIPS compliant");
-                        }
+                // candidates for available protocols
+                ProtocolVersion[] candidates;
+                if (customizedTLSProtocols.isEmpty()) {
+                    // Use the default enabled client protocols if no
+                    // customized TLS protocols.
+                    if (SunJSSE.isFIPS()) {
+                        candidates = new ProtocolVersion[] {
+                            ProtocolVersion.TLS10,
+                            ProtocolVersion.TLS11,
+                            ProtocolVersion.TLS12
+                        };
+                    } else {
+                        candidates = new ProtocolVersion[] {
+                            ProtocolVersion.SSL30,
+                            ProtocolVersion.TLS10,
+                            ProtocolVersion.TLS11,
+                            ProtocolVersion.TLS12
+                        };
                     }
+                } else {
+                    // Use the customized TLS protocols.
+                    candidates =
+                            new ProtocolVersion[customizedTLSProtocols.size()];
+                    candidates = customizedTLSProtocols.toArray(candidates);
                 }
-            }
 
-            defaultClientSSLParams = new SSLParameters();
-            if (reservedException == null) {
+                defaultClientSSLParams = new SSLParameters();
                 defaultClientSSLParams.setProtocols(
                         getAvailableProtocols(candidates));
+            } else {
+                defaultClientSSLParams = null;  // unlikely to be used
             }
         }
 
-        protected CustomizedSSLContext() {
+        protected CustomizedTLSContext() {
             if (reservedException != null) {
                 throw reservedException;
             }
@@ -709,7 +784,7 @@
      *
      * @see SSLContext
      */
-    public static final class TLSContext extends CustomizedSSLContext {
+    public static final class TLSContext extends CustomizedTLSContext {
         // use the default constructor and methods
     }
 
@@ -718,7 +793,7 @@
      *
      * @see SSLContext
      */
-    public static final class DefaultSSLContext extends CustomizedSSLContext {
+    public static final class DefaultSSLContext extends CustomizedTLSContext {
         private static final String NONE = "NONE";
         private static final String P11KEYSTORE = "PKCS11";
 
@@ -879,6 +954,193 @@
         }
     }
 
+    /*
+     * The base abstract SSLContext implementation for the Datagram Transport
+     * Layer Security (DTLS) protocols.
+     *
+     * This abstract class encapsulates supported and the default server DTLS
+     * parameters.
+     *
+     * @see SSLContext
+     */
+    private abstract static class AbstractDTLSContext extends SSLContextImpl {
+        // parameters
+        private static final SSLParameters defaultServerSSLParams;
+        private static final SSLParameters supportedSSLParams;
+
+        static {
+            // supported SSL parameters
+            supportedSSLParams = new SSLParameters();
+
+            // Both DTLSv1.0 and DTLSv1.2 can be used in FIPS mode.
+            supportedSSLParams.setProtocols(new String[] {
+                ProtocolVersion.DTLS10.name,
+                ProtocolVersion.DTLS12.name
+            });
+
+            // candidates for available protocols
+            ProtocolVersion[] candidates = new ProtocolVersion[] {
+                ProtocolVersion.DTLS10,
+                ProtocolVersion.DTLS12
+            };
+
+            defaultServerSSLParams = new SSLParameters();
+            defaultServerSSLParams.setProtocols(
+                    getAvailableProtocols(candidates));
+        }
+
+        @Override
+        SSLParameters getDefaultServerSSLParams() {
+            return defaultServerSSLParams;
+        }
+
+        @Override
+        SSLParameters getSupportedSSLParams() {
+            return supportedSSLParams;
+        }
+
+        @Override
+        SSLEngine createSSLEngineImpl() {
+            return new SSLEngineImpl(this, true);
+        }
+
+        @Override
+        SSLEngine createSSLEngineImpl(String host, int port) {
+            return new SSLEngineImpl(this, host, port, true);
+        }
+
+        @Override
+        HelloCookieManager getHelloCookieManager(SecureRandom secureRandom) {
+            return new HelloCookieManager(secureRandom);
+        }
+    }
+
+    /*
+     * The SSLContext implementation for DTLSv1.0 algorithm.
+     *
+     * @see SSLContext
+     */
+    public static final class DTLS10Context extends AbstractDTLSContext {
+        private final static SSLParameters defaultClientSSLParams;
+
+        static {
+            // candidates for available protocols
+            ProtocolVersion[] candidates = new ProtocolVersion[] {
+                ProtocolVersion.DTLS10
+            };
+
+            defaultClientSSLParams = new SSLParameters();
+            defaultClientSSLParams.setProtocols(
+                    getAvailableProtocols(candidates));
+        }
+
+        @Override
+        SSLParameters getDefaultClientSSLParams() {
+            return defaultClientSSLParams;
+        }
+    }
+
+    /*
+     * The SSLContext implementation for DTLSv1.2 algorithm.
+     *
+     * @see SSLContext
+     */
+    public static final class DTLS12Context extends AbstractDTLSContext {
+        private final static SSLParameters defaultClientSSLParams;
+
+        static {
+            // candidates for available protocols
+            ProtocolVersion[] candidates = new ProtocolVersion[] {
+                ProtocolVersion.DTLS10,
+                ProtocolVersion.DTLS12
+            };
+
+            defaultClientSSLParams = new SSLParameters();
+            defaultClientSSLParams.setProtocols(
+                    getAvailableProtocols(candidates));
+        }
+
+        @Override
+        SSLParameters getDefaultClientSSLParams() {
+            return defaultClientSSLParams;
+        }
+    }
+
+    /*
+     * The SSLContext implementation for customized TLS protocols
+     *
+     * @see SSLContext
+     */
+    private static class CustomizedDTLSContext extends AbstractDTLSContext {
+        private final static SSLParameters defaultClientSSLParams;
+        private static IllegalArgumentException reservedException = null;
+
+        // Don't want a java.lang.LinkageError for illegal system property.
+        //
+        // Please don't throw exception in this static block.  Otherwise,
+        // java.lang.LinkageError may be thrown during the instantiation of
+        // the provider service. Instead, let's handle the initialization
+        // exception in constructor.
+        static {
+            reservedException = CustomizedSSLProtocols.reservedException;
+            if (reservedException == null) {
+                ArrayList<ProtocolVersion>
+                        customizedDTLSProtocols = new ArrayList<>();
+                for (ProtocolVersion protocol :
+                        CustomizedSSLProtocols.customizedProtocols) {
+                    if (protocol.isDTLSProtocol()) {
+                        customizedDTLSProtocols.add(protocol);
+                    }
+                }
+
+                // candidates for available protocols
+                ProtocolVersion[] candidates;
+                if (customizedDTLSProtocols.isEmpty()) {
+                    // Use the default enabled client protocols if no
+                    // customized TLS protocols.
+                    //
+                    // Both DTLSv1.0 and DTLSv1.2 can be used in FIPS mode.
+                    candidates = new ProtocolVersion[] {
+                        ProtocolVersion.DTLS10,
+                        ProtocolVersion.DTLS12
+                    };
+
+                } else {
+                    // Use the customized TLS protocols.
+                    candidates =
+                            new ProtocolVersion[customizedDTLSProtocols.size()];
+                    candidates = customizedDTLSProtocols.toArray(candidates);
+                }
+
+                defaultClientSSLParams = new SSLParameters();
+                defaultClientSSLParams.setProtocols(
+                        getAvailableProtocols(candidates));
+            } else {
+                defaultClientSSLParams = null;   // unlikely to be used
+            }
+        }
+
+        protected CustomizedDTLSContext() {
+            if (reservedException != null) {
+                throw reservedException;
+            }
+        }
+
+        @Override
+        SSLParameters getDefaultClientSSLParams() {
+            return defaultClientSSLParams;
+        }
+    }
+
+    /*
+     * The SSLContext implementation for default "DTLS" algorithm
+     *
+     * @see SSLContext
+     */
+    public static final class DTLSContext extends CustomizedDTLSContext {
+        // use the default constructor and methods
+    }
+
 }
 
 
@@ -961,7 +1223,7 @@
             ProtocolVersion protocolVersion =
                 ProtocolVersion.valueOf(session.getProtocol());
             AlgorithmConstraints constraints = null;
-            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (protocolVersion.useTLS12PlusSpec()) {
                 if (session instanceof ExtendedSSLSession) {
                     ExtendedSSLSession extSession =
                                     (ExtendedSSLSession)session;
@@ -1003,7 +1265,7 @@
             ProtocolVersion protocolVersion =
                 ProtocolVersion.valueOf(session.getProtocol());
             AlgorithmConstraints constraints = null;
-            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (protocolVersion.useTLS12PlusSpec()) {
                 if (session instanceof ExtendedSSLSession) {
                     ExtendedSSLSession extSession =
                                     (ExtendedSSLSession)session;
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -54,57 +54,6 @@
  * before thread1, and sends the data.  The receiving side would see an
  * out-of-order error.
  *
- * Handshaking is still done the same way as SSLSocket using the normal
- * InputStream/OutputStream abstactions.  We create
- * ClientHandshakers/ServerHandshakers, which produce/consume the
- * handshaking data.  The transfer of the data is largely handled by the
- * HandshakeInStream/HandshakeOutStreams.  Lastly, the
- * InputRecord/OutputRecords still have the same functionality, except
- * that they are overridden with EngineInputRecord/EngineOutputRecord,
- * which provide SSLEngine-specific functionality.
- *
- * Some of the major differences are:
- *
- * EngineInputRecord/EngineOutputRecord/EngineWriter:
- *
- *      In order to avoid writing whole new control flows for
- *      handshaking, and to reuse most of the same code, we kept most
- *      of the actual handshake code the same.  As usual, reading
- *      handshake data may trigger output of more handshake data, so
- *      what we do is write this data to internal buffers, and wait for
- *      wrap() to be called to give that data a ride.
- *
- *      All data is routed through
- *      EngineInputRecord/EngineOutputRecord.  However, all handshake
- *      data (ct_alert/ct_change_cipher_spec/ct_handshake) are passed
- *      through to the underlying InputRecord/OutputRecord, and
- *      the data uses the internal buffers.
- *
- *      Application data is handled slightly different, we copy the data
- *      directly from the src to the dst buffers, and do all operations
- *      on those buffers, saving the overhead of multiple copies.
- *
- *      In the case of an inbound record, unwrap passes the inbound
- *      ByteBuffer to the InputRecord.  If the data is handshake data,
- *      the data is read into the InputRecord's internal buffer.  If
- *      the data is application data, the data is decoded directly into
- *      the dst buffer.
- *
- *      In the case of an outbound record, when the write to the
- *      "real" OutputStream's would normally take place, instead we
- *      call back up to the EngineOutputRecord's version of
- *      writeBuffer, at which time we capture the resulting output in a
- *      ByteBuffer, and send that back to the EngineWriter for internal
- *      storage.
- *
- *      EngineWriter is responsible for "handling" all outbound
- *      data, be it handshake or app data, and for returning the data
- *      to wrap() in the proper order.
- *
- * ClientHandshaker/ServerHandshaker/Handshaker:
- *      Methods which relied on SSLSocket now have work on either
- *      SSLSockets or SSLEngines.
- *
  * @author Brad Wetmore
  */
 final public class SSLEngineImpl extends SSLEngine {
@@ -175,11 +124,10 @@
     /*
      * Once we're in state cs_CLOSED, we can continue to
      * wrap/unwrap until we finish sending/receiving the messages
-     * for close_notify.  EngineWriter handles outboundDone.
+     * for close_notify.
      */
     private boolean             inboundDone = false;
-
-    EngineWriter                writer;
+    private boolean             outboundDone = false;
 
     /*
      * The authentication context holds all information used to establish
@@ -201,21 +149,6 @@
     private SSLSessionImpl              sess;
     private volatile SSLSessionImpl     handshakeSession;
 
-
-    /*
-     * Client authentication be off, requested, or required.
-     *
-     * This will be used by both this class and SSLSocket's variants.
-     */
-    static final byte           clauth_none = 0;
-    static final byte           clauth_requested = 1;
-    static final byte           clauth_required = 2;
-
-    /*
-     * Flag indicating that the engine has received a ChangeCipherSpec message.
-     */
-    private boolean             receivedCCS;
-
     /*
      * Flag indicating if the next record we receive MUST be a Finished
      * message. Temporarily set during the handshake to ensure that
@@ -243,11 +176,12 @@
      * Per-connection private state that doesn't change when the
      * session is changed.
      */
-    private byte                        doClientAuth;
-    private boolean                     enableSessionCreation = true;
-    EngineInputRecord                   inputRecord;
-    EngineOutputRecord                  outputRecord;
-    private AccessControlContext        acc;
+    private ClientAuthType          doClientAuth =
+                                            ClientAuthType.CLIENT_AUTH_NONE;
+    private boolean                 enableSessionCreation = true;
+    InputRecord                     inputRecord;
+    OutputRecord                    outputRecord;
+    private AccessControlContext    acc;
 
     // The cipher suites enabled for use on this connection.
     private CipherSuiteList             enabledCipherSuites;
@@ -280,14 +214,7 @@
     /*
      * The SSL version associated with this connection.
      */
-    private ProtocolVersion     protocolVersion = ProtocolVersion.DEFAULT;
-
-    /*
-     * Crypto state that's reinitialized when the session changes.
-     */
-    private Authenticator       readAuthenticator, writeAuthenticator;
-    private CipherBox           readCipher, writeCipher;
-    // NOTE: compression state would be saved here
+    private ProtocolVersion     protocolVersion;
 
     /*
      * security parameters for secure renegotiation.
@@ -320,17 +247,27 @@
     Object                      writeLock;
 
     /*
-     * Is it the first application record to write?
-     */
-    private boolean isFirstAppOutputRecord = true;
-
-    /*
      * Whether local cipher suites preference in server side should be
      * honored during handshaking?
      */
     private boolean preferLocalCipherSuites = false;
 
     /*
+     * whether DTLS handshake retransmissions should be enabled?
+     */
+    private boolean enableRetransmissions = false;
+
+    /*
+     * The maximum expected network packet size for SSL/TLS/DTLS records.
+     */
+    private int maximumPacketSize = 0;
+
+    /*
+     * Is this an instance for Datagram Transport Layer Security (DTLS)?
+     */
+    private final boolean isDTLS;
+
+    /*
      * Class and subclass dynamic debugging support
      */
     private static final Debug debug = Debug.getInstance("ssl");
@@ -344,23 +281,25 @@
      * host/port hints.  This Engine will not be able to cache
      * sessions, but must renegotiate everything by hand.
      */
-    SSLEngineImpl(SSLContextImpl ctx) {
+    SSLEngineImpl(SSLContextImpl ctx, boolean isDTLS) {
         super();
-        init(ctx);
+        this.isDTLS = isDTLS;
+        init(ctx, isDTLS);
     }
 
     /**
      * Constructor for an SSLEngine from SSLContext.
      */
-    SSLEngineImpl(SSLContextImpl ctx, String host, int port) {
+    SSLEngineImpl(SSLContextImpl ctx, String host, int port, boolean isDTLS) {
         super(host, port);
-        init(ctx);
+        this.isDTLS = isDTLS;
+        init(ctx, isDTLS);
     }
 
     /**
      * Initializes the Engine
      */
-    private void init(SSLContextImpl ctx) {
+    private void init(SSLContextImpl ctx, boolean isDTLS) {
         if (debug != null && Debug.isOn("ssl")) {
             System.out.println("Using SSLEngineImpl.");
         }
@@ -368,6 +307,8 @@
         sslContext = ctx;
         sess = SSLSessionImpl.nullSession;
         handshakeSession = null;
+        protocolVersion = isDTLS ?
+                ProtocolVersion.DEFAULT_DTLS : ProtocolVersion.DEFAULT_TLS;
 
         /*
          * State is cs_START until we initialize the handshaker.
@@ -377,22 +318,11 @@
          */
         roleIsServer = true;
         connectionState = cs_START;
-        receivedCCS = false;
 
         // default server name indication
         serverNames =
             Utilities.addToSNIServerNameList(serverNames, getPeerHost());
 
-        /*
-         * default read and write side cipher and MAC support
-         *
-         * Note:  compression support would go here too
-         */
-        readCipher = CipherBox.NULL;
-        readAuthenticator = MAC.NULL;
-        writeCipher = CipherBox.NULL;
-        writeAuthenticator = MAC.NULL;
-
         // default security parameters for secure renegotiation
         secureRenegotiation = false;
         clientVerifyData = new byte[0];
@@ -421,12 +351,19 @@
          * elsewhere.  All inbound data goes through this one
          * input record.
          */
-        outputRecord =
-            new EngineOutputRecord(Record.ct_application_data, this);
-        inputRecord = new EngineInputRecord(this);
-        inputRecord.enableFormatChecks();
+        if (isDTLS) {
+            enableRetransmissions = true;
+
+            // SSLEngine needs no record local buffer
+            outputRecord = new DTLSOutputRecord();
+            inputRecord = new DTLSInputRecord();
 
-        writer = new EngineWriter();
+        } else {
+            outputRecord = new SSLEngineOutputRecord();
+            inputRecord = new SSLEngineInputRecord();
+        }
+
+        maximumPacketSize = outputRecord.getMaxPacketSize();
     }
 
     /**
@@ -480,18 +417,23 @@
             handshaker = new ServerHandshaker(this, sslContext,
                     enabledProtocols, doClientAuth,
                     protocolVersion, connectionState == cs_HANDSHAKE,
-                    secureRenegotiation, clientVerifyData, serverVerifyData);
+                    secureRenegotiation, clientVerifyData, serverVerifyData,
+                    isDTLS);
             handshaker.setSNIMatchers(sniMatchers);
             handshaker.setUseCipherSuitesOrder(preferLocalCipherSuites);
         } else {
             handshaker = new ClientHandshaker(this, sslContext,
                     enabledProtocols,
                     protocolVersion, connectionState == cs_HANDSHAKE,
-                    secureRenegotiation, clientVerifyData, serverVerifyData);
+                    secureRenegotiation, clientVerifyData, serverVerifyData,
+                    isDTLS);
             handshaker.setSNIServerNames(serverNames);
         }
+        handshaker.setMaximumPacketSize(maximumPacketSize);
         handshaker.setEnabledCipherSuites(enabledCipherSuites);
         handshaker.setEnableSessionCreation(enableSessionCreation);
+
+        outputRecord.initHandshaker();
     }
 
     /*
@@ -504,11 +446,14 @@
         }
 
         synchronized (this) {
-            if (writer.hasOutboundData()) {
+            if (!outputRecord.isEmpty()) {
+                // If no handshaking, special case to wrap alters.
                 return HandshakeStatus.NEED_WRAP;
             } else if (handshaker != null) {
                 if (handshaker.taskOutstanding()) {
                     return HandshakeStatus.NEED_TASK;
+                } else if (isDTLS && !inputRecord.isEmpty()) {
+                    return HandshakeStatus.NEED_UNWRAP_AGAIN;
                 } else {
                     return HandshakeStatus.NEED_UNWRAP;
                 }
@@ -572,67 +517,15 @@
     }
 
     /*
-     * When a connection finishes handshaking by enabling use of a newly
-     * negotiated session, each end learns about it in two halves (read,
-     * and write).  When both read and write ciphers have changed, and the
-     * last handshake message has been read, the connection has joined
-     * (rejoined) the new session.
-     *
-     * NOTE:  The SSLv3 spec is rather unclear on the concepts here.
-     * Sessions don't change once they're established (including cipher
-     * suite and master secret) but connections can join them (and leave
-     * them).  They're created by handshaking, though sometime handshaking
-     * causes connections to join up with pre-established sessions.
-     *
-     * Synchronized on "this" from readRecord.
-     */
-    private void changeReadCiphers() throws SSLException {
-        if (connectionState != cs_HANDSHAKE
-                && connectionState != cs_RENEGOTIATE) {
-            throw new SSLProtocolException(
-                "State error, change cipher specs");
-        }
-
-        // ... create decompressor
-
-        CipherBox oldCipher = readCipher;
-
-        try {
-            readCipher = handshaker.newReadCipher();
-            readAuthenticator = handshaker.newReadAuthenticator();
-        } catch (GeneralSecurityException e) {
-            // "can't happen"
-            throw new SSLException("Algorithm missing:  ", e);
-        }
-
-        /*
-         * Dispose of any intermediate state in the underlying cipher.
-         * For PKCS11 ciphers, this will release any attached sessions,
-         * and thus make finalization faster.
-         *
-         * Since MAC's doFinal() is called for every SSL/TLS packet, it's
-         * not necessary to do the same with MAC's.
-         */
-        oldCipher.dispose();
-    }
-
-    /*
      * used by Handshaker to change the active write cipher, follows
      * the output of the CCS message.
      *
      * Also synchronized on "this" from readRecord/delegatedTask.
      */
-    void changeWriteCiphers() throws SSLException {
-        if (connectionState != cs_HANDSHAKE
-                && connectionState != cs_RENEGOTIATE) {
-            throw new SSLProtocolException(
-                "State error, change cipher specs");
-        }
+    void changeWriteCiphers() throws IOException {
 
-        // ... create compressor
-
-        CipherBox oldCipher = writeCipher;
-
+        Authenticator writeAuthenticator;
+        CipherBox writeCipher;
         try {
             writeCipher = handshaker.newWriteCipher();
             writeAuthenticator = handshaker.newWriteAuthenticator();
@@ -641,11 +534,7 @@
             throw new SSLException("Algorithm missing:  ", e);
         }
 
-        // See comment above.
-        oldCipher.dispose();
-
-        // reset the flag of the first application record
-        isFirstAppOutputRecord = true;
+        outputRecord.changeWriteCiphers(writeAuthenticator, writeCipher);
     }
 
     /*
@@ -716,10 +605,6 @@
         //
         // Kickstart handshake state machine if we need to ...
         //
-        // Note that handshaker.kickstart() writes the message
-        // to its HandshakeOutStream, which calls back into
-        // SSLSocketImpl.writeRecord() to send it.
-        //
         if (!handshaker.activated()) {
              // prior to handshaking, activate the handshake
             if (connectionState == cs_RENEGOTIATE) {
@@ -738,10 +623,6 @@
                 } else {
                     // we want to renegotiate, send hello request
                     handshaker.kickstart();
-
-                    // hello request is not included in the handshake
-                    // hashes, reset them
-                    handshaker.handshakeHash.reset();
                 }
             }
         }
@@ -771,15 +652,20 @@
      * the unwrapLock, which blocks multiple unwraps from occurring.
      */
     @Override
-    public SSLEngineResult unwrap(ByteBuffer netData, ByteBuffer [] appData,
+    public SSLEngineResult unwrap(ByteBuffer netData, ByteBuffer[] appData,
             int offset, int length) throws SSLException {
 
-        EngineArgs ea = new EngineArgs(netData, appData, offset, length);
+        // check engine parameters
+        checkEngineParas(netData, appData, offset, length, false);
 
         try {
             synchronized (unwrapLock) {
-                return readNetRecord(ea);
+                return readNetRecord(netData, appData, offset, length);
             }
+        } catch (SSLProtocolException spe) {
+            // may be an unexpected handshake message
+            fatal(Alerts.alert_unexpected_message, spe.getMessage(), spe);
+            return null;  // make compiler happy
         } catch (Exception e) {
             /*
              * Don't reset position so it looks like we didn't
@@ -790,11 +676,39 @@
             fatal(Alerts.alert_internal_error,
                 "problem unwrapping net record", e);
             return null;  // make compiler happy
-        } finally {
+        }
+    }
+
+    private static void checkEngineParas(ByteBuffer netData,
+            ByteBuffer[] appData, int offset, int len, boolean isForWrap) {
+
+        if ((netData == null) || (appData == null)) {
+            throw new IllegalArgumentException("src/dst is null");
+        }
+
+        if ((offset < 0) || (len < 0) || (offset > appData.length - len)) {
+            throw new IndexOutOfBoundsException();
+        }
+
+        /*
+         * If wrapping, make sure the destination bufffer is writable.
+         */
+        if (isForWrap && netData.isReadOnly()) {
+            throw new ReadOnlyBufferException();
+        }
+
+        for (int i = offset; i < offset + len; i++) {
+            if (appData[i] == null) {
+                throw new IllegalArgumentException(
+                        "appData[" + i + "] == null");
+            }
+
             /*
-             * Just in case something failed to reset limits properly.
+             * If unwrapping, make sure the destination bufffers are writable.
              */
-            ea.resetLim();
+            if (!isForWrap && appData[i].isReadOnly()) {
+                throw new ReadOnlyBufferException();
+            }
         }
     }
 
@@ -802,7 +716,8 @@
      * Makes additional checks for unwrap, but this time more
      * specific to this packet and the current state of the machine.
      */
-    private SSLEngineResult readNetRecord(EngineArgs ea) throws IOException {
+    private SSLEngineResult readNetRecord(ByteBuffer netData,
+            ByteBuffer[] appData, int offset, int length) throws IOException {
 
         Status status = null;
         HandshakeStatus hsStatus = null;
@@ -857,54 +772,117 @@
          * message which would change the ciphers.
          */
         if (hsStatus == HandshakeStatus.NEED_TASK) {
+            return new SSLEngineResult(Status.OK, hsStatus, 0, 0);
+        }
+
+        if (hsStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP_AGAIN) {
+            Plaintext plainText = null;
+            try {
+                plainText = readRecord(null, null, 0, 0);
+            } catch (SSLException e) {
+                throw e;
+            } catch (IOException e) {
+                throw new SSLException("readRecord", e);
+            }
+
+            status = (isInboundDone() ? Status.CLOSED : Status.OK);
+            hsStatus = getHSStatus(plainText.handshakeStatus);
+
             return new SSLEngineResult(
-                Status.OK, hsStatus, 0, 0);
+                    status, hsStatus, 0, 0, plainText.recordSN);
         }
 
         /*
          * Check the packet to make sure enough is here.
          * This will also indirectly check for 0 len packets.
          */
-        int packetLen = inputRecord.bytesInCompletePacket(ea.netData);
+        int packetLen = 0;
+        try {
+            packetLen = inputRecord.bytesInCompletePacket(netData);
+        } catch (SSLException ssle) {
+            // Need to discard invalid records for DTLS protocols.
+            if (isDTLS) {
+                if (debug != null && Debug.isOn("ssl")) {
+                    System.out.println(
+                        Thread.currentThread().getName() +
+                        " discard invalid record: " + ssle);
+                }
+
+                // invalid, discard the entire data [section 4.1.2.7, RFC 6347]
+                int deltaNet = netData.remaining();
+                netData.position(netData.limit());
+
+                status = (isInboundDone() ? Status.CLOSED : Status.OK);
+                hsStatus = getHSStatus(hsStatus);
+
+                return new SSLEngineResult(status, hsStatus, deltaNet, 0, -1L);
+            } else {
+                throw ssle;
+            }
+        }
 
         // Is this packet bigger than SSL/TLS normally allows?
         if (packetLen > sess.getPacketBufferSize()) {
-            if (packetLen > Record.maxLargeRecordSize) {
-                throw new SSLProtocolException(
-                    "Input SSL/TLS record too big: max = " +
-                    Record.maxLargeRecordSize +
-                    " len = " + packetLen);
-            } else {
+            int largestRecordSize = isDTLS ?
+                    DTLSRecord.maxRecordSize : SSLRecord.maxLargeRecordSize;
+            if ((packetLen <= largestRecordSize) && !isDTLS) {
                 // Expand the expected maximum packet/application buffer
                 // sizes.
+                //
+                // Only apply to SSL/TLS protocols.
+
+                // Old behavior: shall we honor the System Property
+                // "jsse.SSLEngine.acceptLargeFragments" if it is "false"?
                 sess.expandBufferSizes();
             }
+
+            // check the packet again
+            largestRecordSize = sess.getPacketBufferSize();
+            if (packetLen > largestRecordSize) {
+                throw new SSLProtocolException(
+                        "Input record too big: max = " +
+                        largestRecordSize + " len = " + packetLen);
+            }
+        }
+
+        int netPos = netData.position();
+        int appRemains = 0;
+        for (int i = offset; i < offset + length; i++) {
+            if (appData[i] == null) {
+                throw new IllegalArgumentException(
+                        "appData[" + i + "] == null");
+            }
+            appRemains += appData[i].remaining();
         }
 
         /*
          * Check for OVERFLOW.
          *
-         * To be considered: We could delay enforcing the application buffer
-         * free space requirement until after the initial handshaking.
+         * Delay enforcing the application buffer free space requirement
+         * until after the initial handshaking.
          */
-        if ((packetLen - Record.headerSize) > ea.getAppRemaining()) {
-            return new SSLEngineResult(Status.BUFFER_OVERFLOW, hsStatus, 0, 0);
+        // synchronize connectionState?
+        if ((connectionState == cs_DATA) ||
+                (connectionState == cs_RENEGOTIATE)) {
+
+            int FragLen = inputRecord.estimateFragmentSize(packetLen);
+            if (FragLen > appRemains) {
+                return new SSLEngineResult(
+                        Status.BUFFER_OVERFLOW, hsStatus, 0, 0);
+            }
         }
 
         // check for UNDERFLOW.
-        if ((packetLen == -1) || (ea.netData.remaining() < packetLen)) {
-            return new SSLEngineResult(
-                Status.BUFFER_UNDERFLOW, hsStatus, 0, 0);
+        if ((packetLen == -1) || (netData.remaining() < packetLen)) {
+            return new SSLEngineResult(Status.BUFFER_UNDERFLOW, hsStatus, 0, 0);
         }
 
         /*
          * We're now ready to actually do the read.
-         * The only result code we really need to be exactly
-         * right is the HS finished, for signaling to
-         * HandshakeCompletedListeners.
          */
+        Plaintext plainText = null;
         try {
-            hsStatus = readRecord(ea);
+            plainText = readRecord(netData, appData, offset, length);
         } catch (SSLException e) {
             throw e;
         } catch (IOException e) {
@@ -922,10 +900,21 @@
          * status above should cover:  FINISHED, NEED_TASK
          */
         status = (isInboundDone() ? Status.CLOSED : Status.OK);
-        hsStatus = getHSStatus(hsStatus);
+        hsStatus = getHSStatus(plainText.handshakeStatus);
+
+        int deltaNet = netData.position() - netPos;
+        int deltaApp = appRemains;
+        for (int i = offset; i < offset + length; i++) {
+            deltaApp -= appData[i].remaining();
+        }
 
-        return new SSLEngineResult(status, hsStatus,
-            ea.deltaNet(), ea.deltaApp());
+        return new SSLEngineResult(
+                status, hsStatus, deltaNet, deltaApp, plainText.recordSN);
+    }
+
+    // the caller have synchronized readLock
+    void expectingFinishFlight() {
+        inputRecord.expectingFinishFlight();
     }
 
     /*
@@ -936,220 +925,266 @@
      * that a handshake just completed.
      *
      * It would be nice to be symmetrical with the write side and move
-     * the majority of this to EngineInputRecord, but there's too much
+     * the majority of this to SSLInputRecord, but there's too much
      * SSLEngine state to do that cleanly.  It must still live here.
      */
-    private HandshakeStatus readRecord(EngineArgs ea) throws IOException {
-
-        HandshakeStatus hsStatus = null;
+    private Plaintext readRecord(ByteBuffer netData,
+            ByteBuffer[] appData, int offset, int length) throws IOException {
 
         /*
          * The various operations will return new sliced BB's,
          * this will avoid having to worry about positions and
          * limits in the netBB.
          */
-        ByteBuffer readBB = null;
-        ByteBuffer decryptedBB = null;
+        Plaintext plainText = null;
 
-        if (getConnectionState() != cs_ERROR) {
+        if (getConnectionState() == cs_ERROR) {
+            return Plaintext.PLAINTEXT_NULL;
+        }
 
-            /*
-             * Read a record ... maybe emitting an alert if we get a
-             * comprehensible but unsupported "hello" message during
-             * format checking (e.g. V2).
-             */
-            try {
-                readBB = inputRecord.read(ea.netData);
-            } catch (IOException e) {
-                fatal(Alerts.alert_unexpected_message, e);
+        /*
+         * Read a record ... maybe emitting an alert if we get a
+         * comprehensible but unsupported "hello" message during
+         * format checking (e.g. V2).
+         */
+        try {
+            if (isDTLS) {
+                // Don't process the incoming record until all of the
+                // buffered records get handled.
+                plainText = inputRecord.acquirePlaintext();
             }
 
+            if ((!isDTLS || plainText == null) && netData != null) {
+                plainText = inputRecord.decode(netData);
+            }
+        } catch (UnsupportedOperationException unsoe) {         // SSLv2Hello
+            // Hack code to deliver SSLv2 error message for SSL/TLS connections.
+            if (!isDTLS) {
+                outputRecord.encodeV2NoCipher();
+            }
+
+            fatal(Alerts.alert_unexpected_message, unsoe);
+        } catch (BadPaddingException e) {
             /*
              * The basic SSLv3 record protection involves (optional)
              * encryption for privacy, and an integrity check ensuring
              * data origin authentication.  We do them both here, and
              * throw a fatal alert if the integrity check fails.
              */
-            try {
-                decryptedBB = inputRecord.decrypt(
-                                    readAuthenticator, readCipher, readBB);
-            } catch (BadPaddingException e) {
-                byte alertType = (inputRecord.contentType() ==
-                    Record.ct_handshake) ?
-                        Alerts.alert_handshake_failure :
-                        Alerts.alert_bad_record_mac;
-                fatal(alertType, e.getMessage(), e);
-            }
+            byte alertType = (connectionState != cs_DATA) ?
+                    Alerts.alert_handshake_failure :
+                    Alerts.alert_bad_record_mac;
+            fatal(alertType, e.getMessage(), e);
+        } catch (SSLHandshakeException she) {
+            // may be record sequence number overflow
+            fatal(Alerts.alert_handshake_failure, she);
+        } catch (IOException ioe) {
+            fatal(Alerts.alert_unexpected_message, ioe);
+        }
+
+        // plainText should never be null for TLS protocols
+        HandshakeStatus hsStatus = null;
+        if (!isDTLS || plainText != null) {
+            hsStatus = processInputRecord(plainText, appData, offset, length);
+        }
 
-            // if (!inputRecord.decompress(c))
-            //     fatal(Alerts.alert_decompression_failure,
-            //     "decompression failure");
+        if (hsStatus == null) {
+            hsStatus = getHSStatus(null);
+        }
+
+        if (plainText == null) {
+            plainText = new Plaintext();
+        }
+        plainText.handshakeStatus = hsStatus;
 
+        return plainText;
+    }
 
-            /*
-             * Process the record.
-             */
+    /*
+     * Process the record.
+     */
+    private synchronized HandshakeStatus processInputRecord(
+            Plaintext plainText,
+            ByteBuffer[] appData, int offset, int length) throws IOException {
 
-            synchronized (this) {
-                switch (inputRecord.contentType()) {
-                case Record.ct_handshake:
-                    /*
-                     * Handshake messages always go to a pending session
-                     * handshaker ... if there isn't one, create one.  This
-                     * must work asynchronously, for renegotiation.
-                     *
-                     * NOTE that handshaking will either resume a session
-                     * which was in the cache (and which might have other
-                     * connections in it already), or else will start a new
-                     * session (new keys exchanged) with just this connection
-                     * in it.
-                     */
-                    initHandshaker();
-                    if (!handshaker.activated()) {
-                        // prior to handshaking, activate the handshake
-                        if (connectionState == cs_RENEGOTIATE) {
-                            // don't use SSLv2Hello when renegotiating
-                            handshaker.activate(protocolVersion);
-                        } else {
-                            handshaker.activate(null);
-                        }
+        HandshakeStatus hsStatus = null;
+        switch (plainText.contentType) {
+            case Record.ct_handshake:
+                /*
+                 * Handshake messages always go to a pending session
+                 * handshaker ... if there isn't one, create one.  This
+                 * must work asynchronously, for renegotiation.
+                 *
+                 * NOTE that handshaking will either resume a session
+                 * which was in the cache (and which might have other
+                 * connections in it already), or else will start a new
+                 * session (new keys exchanged) with just this connection
+                 * in it.
+                 */
+                initHandshaker();
+                if (!handshaker.activated()) {
+                    // prior to handshaking, activate the handshake
+                    if (connectionState == cs_RENEGOTIATE) {
+                        // don't use SSLv2Hello when renegotiating
+                        handshaker.activate(protocolVersion);
+                    } else {
+                        handshaker.activate(null);
+                    }
+                }
+
+                /*
+                 * process the handshake record ... may contain just
+                 * a partial handshake message or multiple messages.
+                 *
+                 * The handshaker state machine will ensure that it's
+                 * a finished message.
+                 */
+                handshaker.processRecord(plainText.fragment, expectingFinished);
+                expectingFinished = false;
+
+                if (handshaker.invalidated) {
+                    finishHandshake();
+
+                    // if state is cs_RENEGOTIATE, revert it to cs_DATA
+                    if (connectionState == cs_RENEGOTIATE) {
+                        connectionState = cs_DATA;
+                    }
+                } else if (handshaker.isDone()) {
+                    // reset the parameters for secure renegotiation.
+                    secureRenegotiation =
+                                handshaker.isSecureRenegotiation();
+                    clientVerifyData = handshaker.getClientVerifyData();
+                    serverVerifyData = handshaker.getServerVerifyData();
+
+                    sess = handshaker.getSession();
+                    handshakeSession = null;
+                    if (outputRecord.isEmpty()) {
+                        hsStatus = finishHandshake();
+                        connectionState = cs_DATA;
                     }
 
-                    /*
-                     * process the handshake record ... may contain just
-                     * a partial handshake message or multiple messages.
-                     *
-                     * The handshaker state machine will ensure that it's
-                     * a finished message.
-                     */
-                    handshaker.process_record(inputRecord, expectingFinished);
-                    expectingFinished = false;
+                    // No handshakeListeners here.  That's a
+                    // SSLSocket thing.
+                } else if (handshaker.taskOutstanding()) {
+                    hsStatus = HandshakeStatus.NEED_TASK;
+                }
+                break;
 
-                    if (handshaker.invalidated) {
-                        handshaker = null;
-                        receivedCCS = false;
-                        // if state is cs_RENEGOTIATE, revert it to cs_DATA
-                        if (connectionState == cs_RENEGOTIATE) {
-                            connectionState = cs_DATA;
-                        }
-                    } else if (handshaker.isDone()) {
-                        // reset the parameters for secure renegotiation.
-                        secureRenegotiation =
-                                        handshaker.isSecureRenegotiation();
-                        clientVerifyData = handshaker.getClientVerifyData();
-                        serverVerifyData = handshaker.getServerVerifyData();
-
-                        sess = handshaker.getSession();
-                        handshakeSession = null;
-                        if (!writer.hasOutboundData()) {
-                            hsStatus = HandshakeStatus.FINISHED;
-                        }
-                        handshaker = null;
-                        connectionState = cs_DATA;
-                        receivedCCS = false;
-
-                        // No handshakeListeners here.  That's a
-                        // SSLSocket thing.
-                    } else if (handshaker.taskOutstanding()) {
-                        hsStatus = HandshakeStatus.NEED_TASK;
-                    }
-                    break;
-
-                case Record.ct_application_data:
-                    // Pass this right back up to the application.
-                    if ((connectionState != cs_DATA)
-                            && (connectionState != cs_RENEGOTIATE)
-                            && (connectionState != cs_CLOSED)) {
-                        throw new SSLProtocolException(
+            case Record.ct_application_data:
+                // Pass this right back up to the application.
+                if ((connectionState != cs_DATA)
+                        && (connectionState != cs_RENEGOTIATE)
+                        && (connectionState != cs_CLOSED)) {
+                    throw new SSLProtocolException(
                             "Data received in non-data state: " +
                             connectionState);
-                    }
-
-                    if (expectingFinished) {
-                        throw new SSLProtocolException
-                                ("Expecting finished message, received data");
-                    }
-
-                    /*
-                     * Don't return data once the inbound side is
-                     * closed.
-                     */
-                    if (!inboundDone) {
-                        ea.scatter(decryptedBB.slice());
-                    }
-                    break;
-
-                case Record.ct_alert:
-                    recvAlert();
-                    break;
+                }
 
-                case Record.ct_change_cipher_spec:
-                    if ((connectionState != cs_HANDSHAKE
-                                && connectionState != cs_RENEGOTIATE)
-                            || !handshaker.sessionKeysCalculated()
-                            || receivedCCS) {
-                        // For the CCS message arriving in the wrong state
-                        fatal(Alerts.alert_unexpected_message,
-                                "illegal change cipher spec msg, conn state = "
-                                + connectionState + ", handshake state = "
-                                + handshaker.state);
-                    } else if (inputRecord.available() != 1
-                            || inputRecord.read() != 1) {
-                        // For structural/content issues with the CCS
-                        fatal(Alerts.alert_unexpected_message,
-                                "Malformed change cipher spec msg");
-                    }
-
-                    // Once we've received CCS, update the flag.
-                    // If the remote endpoint sends it again in this handshake
-                    // we won't process it.
-                    receivedCCS = true;
+                if (expectingFinished) {
+                    throw new SSLProtocolException
+                            ("Expecting finished message, received data");
+                }
 
-                    //
-                    // The first message after a change_cipher_spec
-                    // record MUST be a "Finished" handshake record,
-                    // else it's a protocol violation.  We force this
-                    // to be checked by a minor tweak to the state
-                    // machine.
-                    //
-                    changeReadCiphers();
-                    // next message MUST be a finished message
-                    expectingFinished = true;
-                    break;
+                if (!inboundDone) {
+                    ByteBuffer fragment = plainText.fragment;
+                    int remains = fragment.remaining();
 
-                default:
-                    //
-                    // TLS requires that unrecognized records be ignored.
-                    //
-                    if (debug != null && Debug.isOn("ssl")) {
-                        System.out.println(Thread.currentThread().getName() +
-                            ", Received record type: "
-                            + inputRecord.contentType());
-                    }
-                    break;
-                } // switch
-
-                /*
-                 * We only need to check the sequence number state for
-                 * non-handshaking record.
-                 *
-                 * Note that in order to maintain the handshake status
-                 * properly, we check the sequence number after the last
-                 * record reading process. As we request renegotiation
-                 * or close the connection for wrapped sequence number
-                 * when there is enough sequence number space left to
-                 * handle a few more records, so the sequence number
-                 * of the last record cannot be wrapped.
-                 */
-                hsStatus = getHSStatus(hsStatus);
-                if (connectionState < cs_ERROR && !isInboundDone() &&
-                        (hsStatus == HandshakeStatus.NOT_HANDSHAKING)) {
-                    if (checkSequenceNumber(readAuthenticator,
-                            inputRecord.contentType())) {
-                        hsStatus = getHSStatus(null);
+                    // Should have enough room in appData.
+                    for (int i = offset;
+                            ((i < (offset + length)) && (remains > 0)); i++) {
+                        int amount = Math.min(appData[i].remaining(), remains);
+                        fragment.limit(fragment.position() + amount);
+                        appData[i].put(fragment);
+                        remains -= amount;
                     }
                 }
-            } // synchronized (this)
+
+                break;
+
+            case Record.ct_alert:
+                recvAlert(plainText.fragment);
+                break;
+
+            case Record.ct_change_cipher_spec:
+                if ((connectionState != cs_HANDSHAKE
+                        && connectionState != cs_RENEGOTIATE)) {
+                    // For the CCS message arriving in the wrong state
+                    fatal(Alerts.alert_unexpected_message,
+                            "illegal change cipher spec msg, conn state = "
+                            + connectionState);
+                } else if (plainText.fragment.remaining() != 1
+                        || plainText.fragment.get() != 1) {
+                    // For structural/content issues with the CCS
+                    fatal(Alerts.alert_unexpected_message,
+                            "Malformed change cipher spec msg");
+                }
+
+                //
+                // The first message after a change_cipher_spec
+                // record MUST be a "Finished" handshake record,
+                // else it's a protocol violation.  We force this
+                // to be checked by a minor tweak to the state
+                // machine.
+                //
+                handshaker.receiveChangeCipherSpec();
+
+                CipherBox readCipher;
+                Authenticator readAuthenticator;
+                try {
+                    readCipher = handshaker.newReadCipher();
+                    readAuthenticator = handshaker.newReadAuthenticator();
+                } catch (GeneralSecurityException e) {
+                    // can't happen
+                    throw new SSLException("Algorithm missing:  ", e);
+                }
+                inputRecord.changeReadCiphers(readAuthenticator, readCipher);
+
+                // next message MUST be a finished message
+                expectingFinished = true;
+                break;
+
+            default:
+                //
+                // TLS requires that unrecognized records be ignored.
+                //
+                if (debug != null && Debug.isOn("ssl")) {
+                    System.out.println(Thread.currentThread().getName() +
+                            ", Received record type: " + plainText.contentType);
+                }
+                break;
+        } // switch
+
+        /*
+         * We only need to check the sequence number state for
+         * non-handshaking record.
+         *
+         * Note that in order to maintain the handshake status
+         * properly, we check the sequence number after the last
+         * record reading process. As we request renegotiation
+         * or close the connection for wrapped sequence number
+         * when there is enough sequence number space left to
+         * handle a few more records, so the sequence number
+         * of the last record cannot be wrapped.
+         */
+        hsStatus = getHSStatus(hsStatus);
+        if (connectionState < cs_ERROR && !isInboundDone() &&
+                (hsStatus == HandshakeStatus.NOT_HANDSHAKING) &&
+                (inputRecord.seqNumIsHuge())) {
+            /*
+             * Ask for renegotiation when need to renew sequence number.
+             *
+             * Don't bother to kickstart the renegotiation when the local is
+             * asking for it.
+             */
+            if (debug != null && Debug.isOn("ssl")) {
+                System.out.println(Thread.currentThread().getName() +
+                        ", request renegotiation " +
+                        "to avoid sequence number overflow");
+            }
+
+            beginHandshake();
+
+            hsStatus = getHSStatus(null);
         }
 
         return hsStatus;
@@ -1166,36 +1201,33 @@
      * the wrapLock, which blocks multiple wraps from occurring.
      */
     @Override
-    public SSLEngineResult wrap(ByteBuffer [] appData,
+    public SSLEngineResult wrap(ByteBuffer[] appData,
             int offset, int length, ByteBuffer netData) throws SSLException {
 
-        EngineArgs ea = new EngineArgs(appData, offset, length, netData);
+        // check engine parameters
+        checkEngineParas(netData, appData, offset, length, true);
 
         /*
          * We can be smarter about using smaller buffer sizes later.
-         * For now, force it to be large enough to handle any
-         * valid SSL/TLS record.
+         * For now, force it to be large enough to handle any valid record.
          */
-        if (netData.remaining() < EngineOutputRecord.maxRecordSize) {
+        if (netData.remaining() < sess.getPacketBufferSize()) {
             return new SSLEngineResult(
                 Status.BUFFER_OVERFLOW, getHSStatus(null), 0, 0);
         }
 
         try {
             synchronized (wrapLock) {
-                return writeAppRecord(ea);
+                return writeAppRecord(appData, offset, length, netData);
             }
+        } catch (SSLProtocolException spe) {
+            // may be an unexpected handshake message
+            fatal(Alerts.alert_unexpected_message, spe.getMessage(), spe);
+            return null;  // make compiler happy
         } catch (Exception e) {
-            ea.resetPos();
-
             fatal(Alerts.alert_internal_error,
                 "problem wrapping app data", e);
             return null;  // make compiler happy
-        } finally {
-            /*
-             * Just in case something didn't reset limits properly.
-             */
-            ea.resetLim();
         }
     }
 
@@ -1203,7 +1235,8 @@
      * Makes additional checks for unwrap, but this time more
      * specific to this packet and the current state of the machine.
      */
-    private SSLEngineResult writeAppRecord(EngineArgs ea) throws IOException {
+    private SSLEngineResult writeAppRecord(ByteBuffer[] appData,
+            int offset, int length, ByteBuffer netData) throws IOException {
 
         Status status = null;
         HandshakeStatus hsStatus = null;
@@ -1216,7 +1249,7 @@
         /*
          * short circuit if we're closed/closing.
          */
-        if (writer.isOutboundDone()) {
+        if (isOutboundDone()) {
             return new SSLEngineResult(Status.CLOSED, getHSStatus(null), 0, 0);
         }
 
@@ -1226,7 +1259,8 @@
          */
         synchronized (this) {
             if ((connectionState == cs_HANDSHAKE) ||
-                    (connectionState == cs_START)) {
+                (connectionState == cs_START)) {
+
                 kickstartHandshake();
 
                 /*
@@ -1234,9 +1268,18 @@
                  * without trying to wrap anything.
                  */
                 hsStatus = getHSStatus(null);
+                if (hsStatus == HandshakeStatus.NEED_UNWRAP) {
+                    /*
+                     * For DTLS, if the handshake state is
+                     * HandshakeStatus.NEED_UNWRAP, a call to SSLEngine.wrap()
+                     * means that the previous handshake packets (if delivered)
+                     * get lost, and need retransmit the handshake messages.
+                     */
+                    if (!isDTLS || !enableRetransmissions ||
+                            (handshaker == null) || outputRecord.firstMessage) {
 
-                if (hsStatus == HandshakeStatus.NEED_UNWRAP) {
-                    return new SSLEngineResult(Status.OK, hsStatus, 0, 0);
+                        return new SSLEngineResult(Status.OK, hsStatus, 0, 0);
+                    }   // otherwise, need retransmission
                 }
             }
         }
@@ -1258,17 +1301,33 @@
          * message which would change the ciphers.
          */
         if (hsStatus == HandshakeStatus.NEED_TASK) {
-            return new SSLEngineResult(
-                Status.OK, hsStatus, 0, 0);
+            return new SSLEngineResult(Status.OK, hsStatus, 0, 0);
         }
 
         /*
          * This will obtain any waiting outbound data, or will
          * process the outbound appData.
          */
+        int netPos = netData.position();
+        int appRemains = 0;
+        for (int i = offset; i < offset + length; i++) {
+            if (appData[i] == null) {
+                throw new IllegalArgumentException(
+                        "appData[" + i + "] == null");
+            }
+            appRemains += appData[i].remaining();
+        }
+
+        Ciphertext ciphertext = null;
         try {
-            synchronized (writeLock) {
-                hsStatus = writeRecord(outputRecord, ea);
+            if (appRemains != 0) {
+                synchronized (writeLock) {
+                    ciphertext = writeRecord(appData, offset, length, netData);
+                }
+            } else {
+                synchronized (writeLock) {
+                    ciphertext = writeRecord(null, 0, 0, netData);
+                }
             }
         } catch (SSLException e) {
             throw e;
@@ -1283,21 +1342,62 @@
          * status above should cover:  NEED_WRAP/FINISHED
          */
         status = (isOutboundDone() ? Status.CLOSED : Status.OK);
-        hsStatus = getHSStatus(hsStatus);
+        hsStatus = getHSStatus(ciphertext.handshakeStatus);
 
-        return new SSLEngineResult(status, hsStatus,
-            ea.deltaApp(), ea.deltaNet());
+        int deltaNet = netData.position() - netPos;
+        int deltaApp = appRemains;
+        for (int i = offset; i < offset + length; i++) {
+            deltaApp -= appData[i].remaining();
+        }
+
+        return new SSLEngineResult(
+                status, hsStatus, deltaApp, deltaNet, ciphertext.recordSN);
     }
 
     /*
      * Central point to write/get all of the outgoing data.
      */
-    private HandshakeStatus writeRecord(EngineOutputRecord eor,
-            EngineArgs ea) throws IOException {
+    private Ciphertext writeRecord(ByteBuffer[] appData,
+            int offset, int length, ByteBuffer netData) throws IOException {
+
+        Ciphertext ciphertext = null;
+        try {
+            // Acquire the buffered to-be-delivered records or retransmissions.
+            //
+            // May have buffered records, or need retransmission if handshaking.
+            if (!outputRecord.isEmpty() || (handshaker != null)) {
+                ciphertext = outputRecord.acquireCiphertext(netData);
+            }
+
+            if ((ciphertext == null) && (appData != null)) {
+                ciphertext = outputRecord.encode(
+                        appData, offset, length, netData);
+            }
+        } catch (SSLHandshakeException she) {
+            // may be record sequence number overflow
+            fatal(Alerts.alert_handshake_failure, she);
 
-        // eventually compress as well.
-        HandshakeStatus hsStatus =
-                writer.writeRecord(eor, ea, writeAuthenticator, writeCipher);
+            return Ciphertext.CIPHERTEXT_NULL;   // make the complier happy
+        } catch (IOException e) {
+            fatal(Alerts.alert_unexpected_message, e);
+
+            return Ciphertext.CIPHERTEXT_NULL;   // make the complier happy
+        }
+
+        if (ciphertext == null) {
+            return Ciphertext.CIPHERTEXT_NULL;
+        }
+
+        HandshakeStatus hsStatus = null;
+        Ciphertext.RecordType recordType = ciphertext.recordType;
+        if ((handshaker != null) &&
+                (recordType.contentType == Record.ct_handshake) &&
+                (recordType.handshakeType == HandshakeMessage.ht_finished) &&
+                handshaker.isDone() && outputRecord.isEmpty()) {
+
+            hsStatus = finishHandshake();
+            connectionState = cs_DATA;
+        }   // Otherwise, the followed call to getHSStatus() will help.
 
         /*
          * We only need to check the sequence number state for
@@ -1313,129 +1413,41 @@
          */
         hsStatus = getHSStatus(hsStatus);
         if (connectionState < cs_ERROR && !isOutboundDone() &&
-                (hsStatus == HandshakeStatus.NOT_HANDSHAKING)) {
-            if (checkSequenceNumber(writeAuthenticator, eor.contentType())) {
-                hsStatus = getHSStatus(null);
-            }
-        }
-
-        /*
-         * turn off the flag of the first application record if we really
-         * consumed at least byte.
-         */
-        if (isFirstAppOutputRecord && ea.deltaApp() > 0) {
-            isFirstAppOutputRecord = false;
-        }
-
-        return hsStatus;
-    }
-
-    /*
-     * Need to split the payload except the following cases:
-     *
-     * 1. protocol version is TLS 1.1 or later;
-     * 2. bulk cipher does not use CBC mode, including null bulk cipher suites.
-     * 3. the payload is the first application record of a freshly
-     *    negotiated TLS session.
-     * 4. the CBC protection is disabled;
-     *
-     * More details, please refer to
-     * EngineOutputRecord.write(EngineArgs, MAC, CipherBox).
-     */
-    boolean needToSplitPayload(CipherBox cipher, ProtocolVersion protocol) {
-        return (protocol.v <= ProtocolVersion.TLS10.v) &&
-                cipher.isCBCMode() && !isFirstAppOutputRecord &&
-                Record.enableCBCProtection;
-    }
-
-    /*
-     * Non-application OutputRecords go through here.
-     */
-    void writeRecord(EngineOutputRecord eor) throws IOException {
-        // eventually compress as well.
-        writer.writeRecord(eor, writeAuthenticator, writeCipher);
-
-        /*
-         * Check the sequence number state
-         *
-         * Note that in order to maintain the connection I/O
-         * properly, we check the sequence number after the last
-         * record writing process. As we request renegotiation
-         * or close the connection for wrapped sequence number
-         * when there is enough sequence number space left to
-         * handle a few more records, so the sequence number
-         * of the last record cannot be wrapped.
-         */
-        if ((connectionState < cs_ERROR) && !isOutboundDone()) {
-            checkSequenceNumber(writeAuthenticator, eor.contentType());
-        }
-    }
-
-    //
-    // Close code
-    //
-
-    /**
-     * Check the sequence number state
-     *
-     * RFC 4346 states that, "Sequence numbers are of type uint64 and
-     * may not exceed 2^64-1.  Sequence numbers do not wrap. If a TLS
-     * implementation would need to wrap a sequence number, it must
-     * renegotiate instead."
-     *
-     * Return true if the handshake status may be changed.
-     */
-    private boolean checkSequenceNumber(Authenticator authenticator, byte type)
-            throws IOException {
-
-        /*
-         * Don't bother to check the sequence number for error or
-         * closed connections, or NULL MAC
-         */
-        if (connectionState >= cs_ERROR || authenticator == MAC.NULL) {
-            return false;
-        }
-
-        /*
-         * Conservatively, close the connection immediately when the
-         * sequence number is close to overflow
-         */
-        if (authenticator.seqNumOverflow()) {
+                (hsStatus == HandshakeStatus.NOT_HANDSHAKING) &&
+                (outputRecord.seqNumIsHuge())) {
             /*
-             * TLS protocols do not define a error alert for sequence
-             * number overflow. We use handshake_failure error alert
-             * for handshaking and bad_record_mac for other records.
+             * Ask for renegotiation when need to renew sequence number.
+             *
+             * Don't bother to kickstart the renegotiation when the local is
+             * asking for it.
              */
             if (debug != null && Debug.isOn("ssl")) {
                 System.out.println(Thread.currentThread().getName() +
-                    ", sequence number extremely close to overflow " +
-                    "(2^64-1 packets). Closing connection.");
-            }
-
-            fatal(Alerts.alert_handshake_failure, "sequence number overflow");
-
-            return true; // make the compiler happy
-        }
-
-        /*
-         * Ask for renegotiation when need to renew sequence number.
-         *
-         * Don't bother to kickstart the renegotiation when the local is
-         * asking for it.
-         */
-        if ((type != Record.ct_handshake) && authenticator.seqNumIsHuge()) {
-            if (debug != null && Debug.isOn("ssl")) {
-                System.out.println(Thread.currentThread().getName() +
                         ", request renegotiation " +
                         "to avoid sequence number overflow");
             }
 
             beginHandshake();
-            return true;
+
+            hsStatus = getHSStatus(null);
         }
+        ciphertext.handshakeStatus = hsStatus;
+
+        return ciphertext;
+    }
 
-        return false;
-    }
+    private HandshakeStatus finishHandshake() {
+        handshaker = null;
+        inputRecord.setHandshakeHash(null);
+        outputRecord.setHandshakeHash(null);
+        connectionState = cs_DATA;
+
+       return HandshakeStatus.FINISHED;
+   }
+
+    //
+    // Close code
+    //
 
     /**
      * Signals that no more outbound application data will be sent
@@ -1451,7 +1463,7 @@
         /*
          * Already closed, ignore
          */
-        if (writer.isOutboundDone()) {
+        if (outboundDone) {
             return;
         }
 
@@ -1461,7 +1473,18 @@
          * If we haven't even started yet, don't bother reading inbound.
          */
         case cs_START:
-            writer.closeOutbound();
+            try {
+                outputRecord.close();
+            } catch (IOException ioe) {
+               // ignore
+            }
+            outboundDone = true;
+
+            try {
+                inputRecord.close();
+            } catch (IOException ioe) {
+               // ignore
+            }
             inboundDone = true;
             break;
 
@@ -1477,13 +1500,15 @@
         // case cs_RENEGOTIATE:
         default:
             warning(Alerts.alert_close_notify);
-            writer.closeOutbound();
+            try {
+                outputRecord.close();
+            } catch (IOException ioe) {
+               // ignore
+            }
+            outboundDone = true;
             break;
         }
 
-        // See comment in changeReadCiphers()
-        writeCipher.dispose();
-
         connectionState = cs_CLOSED;
     }
 
@@ -1505,7 +1530,7 @@
      */
     @Override
     public boolean isOutboundDone() {
-        return writer.isOutboundDone();
+        return outboundDone && outputRecord.isEmpty();
     }
 
     /**
@@ -1527,11 +1552,14 @@
         }
 
         closeOutboundInternal();
+
+        try {
+            inputRecord.close();
+        } catch (IOException ioe) {
+           // ignore
+        }
         inboundDone = true;
 
-        // See comment in changeReadCiphers()
-        readCipher.dispose();
-
         connectionState = cs_CLOSED;
     }
 
@@ -1602,6 +1630,10 @@
     }
 
     synchronized void setHandshakeSession(SSLSessionImpl session) {
+        // update the fragment size, which may be negotiated during handshaking
+        inputRecord.changeFragmentSize(session.getNegotiatedMaxFragSize());
+        outputRecord.changeFragmentSize(session.getNegotiatedMaxFragSize());
+
         handshakeSession = session;
     }
 
@@ -1701,6 +1733,11 @@
         int oldState = connectionState;
         connectionState = cs_ERROR;
 
+        try {
+            inputRecord.close();
+        } catch (IOException ioe) {
+           // ignore
+        }
         inboundDone = true;
 
         sess.invalidate();
@@ -1728,14 +1765,15 @@
                 Alerts.getSSLException(description, cause, diagnostic);
         }
 
-        writer.closeOutbound();
+        try {
+            outputRecord.close();
+        } catch (IOException ioe) {
+           // ignore
+        }
+        outboundDone = true;
 
         connectionState = cs_CLOSED;
 
-        // See comment in changeReadCiphers()
-        readCipher.dispose();
-        writeCipher.dispose();
-
         if (cause instanceof RuntimeException) {
             throw (RuntimeException)cause;
         } else {
@@ -1747,9 +1785,10 @@
      * Process an incoming alert ... caller must already have synchronized
      * access to "this".
      */
-    private void recvAlert() throws IOException {
-        byte level = (byte)inputRecord.read();
-        byte description = (byte)inputRecord.read();
+    private void recvAlert(ByteBuffer fragment) throws IOException {
+        byte level = fragment.get();
+        byte description = fragment.get();
+
         if (description == -1) { // check for short message
             fatal(Alerts.alert_illegal_parameter, "Short alert message");
         }
@@ -1813,40 +1852,18 @@
 
         // For initial handshaking, don't send alert message to peer if
         // handshaker has not started.
-        if (connectionState == cs_HANDSHAKE &&
-            (handshaker == null || !handshaker.started())) {
+        //
+        // Shall we send an fatal alter to terminate the connection gracefully?
+        if (connectionState <= cs_HANDSHAKE &&
+                (handshaker == null || !handshaker.started() ||
+                        !handshaker.activated())) {
             return;
         }
 
-        EngineOutputRecord r = new EngineOutputRecord(Record.ct_alert, this);
-        r.setVersion(protocolVersion);
-
-        boolean useDebug = debug != null && Debug.isOn("ssl");
-        if (useDebug) {
-            synchronized (System.out) {
-                System.out.print(Thread.currentThread().getName());
-                System.out.print(", SEND " + protocolVersion + " ALERT:  ");
-                if (level == Alerts.alert_fatal) {
-                    System.out.print("fatal, ");
-                } else if (level == Alerts.alert_warning) {
-                    System.out.print("warning, ");
-                } else {
-                    System.out.print("<level = " + (0x0ff & level) + ">, ");
-                }
-                System.out.println("description = "
-                        + Alerts.alertDescription(description));
-            }
-        }
-
-        r.write(level);
-        r.write(description);
         try {
-            writeRecord(r);
-        } catch (IOException e) {
-            if (useDebug) {
-                System.out.println(Thread.currentThread().getName() +
-                    ", Exception sending alert: " + e);
-            }
+            outputRecord.encodeAlert(level, description);
+        } catch (IOException ioe) {
+            // ignore
         }
     }
 
@@ -1894,7 +1911,8 @@
     @Override
     synchronized public void setNeedClientAuth(boolean flag) {
         doClientAuth = (flag ?
-            SSLEngineImpl.clauth_required : SSLEngineImpl.clauth_none);
+                ClientAuthType.CLIENT_AUTH_REQUIRED :
+                ClientAuthType.CLIENT_AUTH_NONE);
 
         if ((handshaker != null) &&
                 (handshaker instanceof ServerHandshaker) &&
@@ -1905,7 +1923,7 @@
 
     @Override
     synchronized public boolean getNeedClientAuth() {
-        return (doClientAuth == SSLEngineImpl.clauth_required);
+        return (doClientAuth == ClientAuthType.CLIENT_AUTH_REQUIRED);
     }
 
     /**
@@ -1919,7 +1937,8 @@
     @Override
     synchronized public void setWantClientAuth(boolean flag) {
         doClientAuth = (flag ?
-            SSLEngineImpl.clauth_requested : SSLEngineImpl.clauth_none);
+                ClientAuthType.CLIENT_AUTH_REQUESTED :
+                ClientAuthType.CLIENT_AUTH_NONE);
 
         if ((handshaker != null) &&
                 (handshaker instanceof ServerHandshaker) &&
@@ -1930,7 +1949,7 @@
 
     @Override
     synchronized public boolean getWantClientAuth() {
-        return (doClientAuth == SSLEngineImpl.clauth_requested);
+        return (doClientAuth == ClientAuthType.CLIENT_AUTH_REQUESTED);
     }
 
 
@@ -1946,13 +1965,21 @@
 
         case cs_START:
             /*
-             * If we need to change the engine mode and the enabled
-             * protocols haven't specifically been set by the user,
-             * change them to the corresponding default ones.
+             * If we need to change the socket mode and the enabled
+             * protocols and cipher suites haven't specifically been
+             * set by the user, change them to the corresponding
+             * default ones.
              */
-            if (roleIsServer != (!flag) &&
-                    sslContext.isDefaultProtocolList(enabledProtocols)) {
-                enabledProtocols = sslContext.getDefaultProtocolList(!flag);
+            if (roleIsServer != (!flag)) {
+                if (sslContext.isDefaultProtocolList(enabledProtocols)) {
+                    enabledProtocols =
+                            sslContext.getDefaultProtocolList(!flag);
+                }
+
+                if (sslContext.isDefaultCipherSuiteList(enabledCipherSuites)) {
+                    enabledCipherSuites =
+                            sslContext.getDefaultCipherSuiteList(!flag);
+                }
             }
 
             roleIsServer = !flag;
@@ -1970,13 +1997,22 @@
             assert(handshaker != null);
             if (!handshaker.activated()) {
                 /*
-                 * If we need to change the engine mode and the enabled
-                 * protocols haven't specifically been set by the user,
-                 * change them to the corresponding default ones.
+                 * If we need to change the socket mode and the enabled
+                 * protocols and cipher suites haven't specifically been
+                 * set by the user, change them to the corresponding
+                 * default ones.
                  */
-                if (roleIsServer != (!flag) &&
-                        sslContext.isDefaultProtocolList(enabledProtocols)) {
-                    enabledProtocols = sslContext.getDefaultProtocolList(!flag);
+                if (roleIsServer != (!flag)) {
+                    if (sslContext.isDefaultProtocolList(enabledProtocols)) {
+                        enabledProtocols =
+                                sslContext.getDefaultProtocolList(!flag);
+                    }
+
+                    if (sslContext.isDefaultCipherSuiteList(
+                                                    enabledCipherSuites)) {
+                        enabledCipherSuites =
+                            sslContext.getDefaultCipherSuiteList(!flag);
+                    }
                 }
 
                 roleIsServer = !flag;
@@ -2102,6 +2138,8 @@
         params.setSNIMatchers(sniMatchers);
         params.setServerNames(serverNames);
         params.setUseCipherSuitesOrder(preferLocalCipherSuites);
+        params.setEnableRetransmissions(enableRetransmissions);
+        params.setMaximumPacketSize(maximumPacketSize);
 
         return params;
     }
@@ -2117,6 +2155,15 @@
         identificationProtocol = params.getEndpointIdentificationAlgorithm();
         algorithmConstraints = params.getAlgorithmConstraints();
         preferLocalCipherSuites = params.getUseCipherSuitesOrder();
+        enableRetransmissions = params.getEnableRetransmissions();
+        maximumPacketSize = params.getMaximumPacketSize();
+
+        if (maximumPacketSize != 0) {
+            outputRecord.changePacketSize(maximumPacketSize);
+        } else {
+            // use the implicit maximum packet size.
+            maximumPacketSize = outputRecord.getMaxPacketSize();
+        }
 
         List<SNIServerName> sniNames = params.getServerNames();
         if (sniNames != null) {
@@ -2131,6 +2178,7 @@
         if ((handshaker != null) && !handshaker.started()) {
             handshaker.setIdentificationProtocol(identificationProtocol);
             handshaker.setAlgorithmConstraints(algorithmConstraints);
+            handshaker.setMaximumPacketSize(maximumPacketSize);
             if (roleIsServer) {
                 handshaker.setSNIMatchers(sniMatchers);
                 handshaker.setUseCipherSuitesOrder(preferLocalCipherSuites);
@@ -2141,14 +2189,6 @@
     }
 
     /**
-     * Returns a boolean indicating whether the ChangeCipherSpec message
-     * has been received for this handshake.
-     */
-    boolean receivedChangeCipherSpec() {
-        return receivedCCS;
-    }
-
-    /**
      * Returns a printable representation of this end of the connection.
      */
     @Override
@@ -2162,6 +2202,7 @@
         retval.append((host == null) ? "null" : host);
         retval.append(" port=");
         retval.append(Integer.toString(getPeerPort()));
+        retval.append(" role=" + (roleIsServer ? "Server" : "Client"));
         retval.append("] ");
         retval.append(getSession().getCipherSuite());
         retval.append("]");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineInputRecord.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 1996, 2014, 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.security.ssl;
+
+import java.io.*;
+import java.nio.*;
+
+import javax.crypto.BadPaddingException;
+
+import javax.net.ssl.*;
+
+import sun.misc.HexDumpEncoder;
+
+
+/**
+ * {@code InputRecord} implementation for {@code SSLEngine}.
+ */
+final class SSLEngineInputRecord extends InputRecord implements SSLRecord {
+    // used by handshake hash computation for handshake fragment
+    private byte prevType = -1;
+    private int hsMsgOff = 0;
+    private int hsMsgLen = 0;
+
+    private boolean formatVerified = false;     // SSLv2 ruled out?
+
+    SSLEngineInputRecord() {
+        this.readAuthenticator = MAC.TLS_NULL;
+    }
+
+    @Override
+    int estimateFragmentSize(int packetSize) {
+        int macLen = 0;
+        if (readAuthenticator instanceof MAC) {
+            macLen = ((MAC)readAuthenticator).MAClen();
+        }
+
+        if (packetSize > 0) {
+            return readCipher.estimateFragmentSize(
+                    packetSize, macLen, headerSize);
+        } else {
+            return Record.maxDataSize;
+        }
+    }
+
+    @Override
+    int bytesInCompletePacket(ByteBuffer packet) throws SSLException {
+        /*
+         * SSLv2 length field is in bytes 0/1
+         * SSLv3/TLS length field is in bytes 3/4
+         */
+        if (packet.remaining() < 5) {
+            return -1;
+        }
+
+        int pos = packet.position();
+        byte byteZero = packet.get(pos);
+
+        int len = 0;
+
+        /*
+         * If we have already verified previous packets, we can
+         * ignore the verifications steps, and jump right to the
+         * determination.  Otherwise, try one last hueristic to
+         * see if it's SSL/TLS.
+         */
+        if (formatVerified ||
+                (byteZero == ct_handshake) || (byteZero == ct_alert)) {
+            /*
+             * Last sanity check that it's not a wild record
+             */
+            ProtocolVersion recordVersion = ProtocolVersion.valueOf(
+                                    packet.get(pos + 1), packet.get(pos + 2));
+
+            // check the record version
+            checkRecordVersion(recordVersion, false);
+
+            /*
+             * Reasonably sure this is a V3, disable further checks.
+             * We can't do the same in the v2 check below, because
+             * read still needs to parse/handle the v2 clientHello.
+             */
+            formatVerified = true;
+
+            /*
+             * One of the SSLv3/TLS message types.
+             */
+            len = ((packet.get(pos + 3) & 0xFF) << 8) +
+                   (packet.get(pos + 4) & 0xFF) + headerSize;
+
+        } else {
+            /*
+             * Must be SSLv2 or something unknown.
+             * Check if it's short (2 bytes) or
+             * long (3) header.
+             *
+             * Internals can warn about unsupported SSLv2
+             */
+            boolean isShort = ((byteZero & 0x80) != 0);
+
+            if (isShort &&
+                    ((packet.get(pos + 2) == 1) || packet.get(pos + 2) == 4)) {
+
+                ProtocolVersion recordVersion = ProtocolVersion.valueOf(
+                                    packet.get(pos + 3), packet.get(pos + 4));
+
+                // check the record version
+                checkRecordVersion(recordVersion, true);
+
+                /*
+                 * Client or Server Hello
+                 */
+                int mask = (isShort ? 0x7F : 0x3F);
+                len = ((byteZero & mask) << 8) +
+                        (packet.get(pos + 1) & 0xFF) + (isShort ? 2 : 3);
+
+            } else {
+                // Gobblygook!
+                throw new SSLException(
+                        "Unrecognized SSL message, plaintext connection?");
+            }
+        }
+
+        return len;
+    }
+
+    @Override
+    void checkRecordVersion(ProtocolVersion recordVersion,
+            boolean allowSSL20Hello) throws SSLException {
+
+        if (recordVersion.maybeDTLSProtocol()) {
+            throw new SSLException(
+                    "Unrecognized record version " + recordVersion +
+                    " , DTLS packet?");
+        }
+
+        // Check if the record version is too old.
+        if ((recordVersion.v < ProtocolVersion.MIN.v)) {
+            // if it's not SSLv2, we're out of here.
+            if (!allowSSL20Hello ||
+                    (recordVersion.v != ProtocolVersion.SSL20Hello.v)) {
+                throw new SSLException(
+                    "Unsupported record version " + recordVersion);
+            }
+        }
+    }
+
+    @Override
+    Plaintext decode(ByteBuffer packet)
+            throws IOException, BadPaddingException {
+
+        if (isClosed) {
+            return null;
+        }
+
+        if (debug != null && Debug.isOn("packet")) {
+             Debug.printHex(
+                    "[Raw read]: length = " + packet.remaining(), packet);
+        }
+
+        // The caller should have validated the record.
+        if (!formatVerified) {
+            formatVerified = true;
+
+            /*
+             * The first record must either be a handshake record or an
+             * alert message. If it's not, it is either invalid or an
+             * SSLv2 message.
+             */
+            int pos = packet.position();
+            byte byteZero = packet.get(pos);
+            if (byteZero != ct_handshake && byteZero != ct_alert) {
+                return handleUnknownRecord(packet);
+            }
+        }
+
+        return decodeInputRecord(packet);
+    }
+
+    private Plaintext decodeInputRecord(ByteBuffer packet)
+            throws IOException, BadPaddingException {
+
+        //
+        // The packet should be a complete record, or more.
+        //
+
+        int srcPos = packet.position();
+        int srcLim = packet.limit();
+
+        byte contentType = packet.get();                   // pos: 0
+        byte majorVersion = packet.get();                  // pos: 1
+        byte minorVersion = packet.get();                  // pos: 2
+        int contentLen = ((packet.get() & 0xFF) << 8) +
+                          (packet.get() & 0xFF);           // pos: 3, 4
+
+        if (debug != null && Debug.isOn("record")) {
+             System.out.println(Thread.currentThread().getName() +
+                    ", READ: " +
+                    ProtocolVersion.valueOf(majorVersion, minorVersion) +
+                    " " + Record.contentName(contentType) + ", length = " +
+                    contentLen);
+        }
+
+        //
+        // Check for upper bound.
+        //
+        // Note: May check packetSize limit in the future.
+        if (contentLen < 0 || contentLen > maxLargeRecordSize - headerSize) {
+            throw new SSLProtocolException(
+                "Bad input record size, TLSCiphertext.length = " + contentLen);
+        }
+
+        //
+        // check for handshake fragment
+        //
+        if ((contentType != ct_handshake) && (hsMsgOff != hsMsgLen)) {
+            throw new SSLProtocolException(
+                    "Expected to get a handshake fragment");
+        }
+
+        //
+        // Decrypt the fragment
+        //
+        int recLim = srcPos + SSLRecord.headerSize + contentLen;
+        packet.limit(recLim);
+        packet.position(srcPos + SSLRecord.headerSize);
+
+        ByteBuffer plaintext;
+        try {
+            plaintext =
+                decrypt(readAuthenticator, readCipher, contentType, packet);
+        } finally {
+            // comsume a complete record
+            packet.limit(srcLim);
+            packet.position(recLim);
+        }
+
+        //
+        // handshake hashing
+        //
+        if (contentType == ct_handshake) {
+            int pltPos = plaintext.position();
+            int pltLim = plaintext.limit();
+            int frgPos = pltPos;
+            for (int remains = plaintext.remaining(); remains > 0;) {
+                int howmuch;
+                byte handshakeType;
+                if (hsMsgOff < hsMsgLen) {
+                    // a fragment of the handshake message
+                    howmuch = Math.min((hsMsgLen - hsMsgOff), remains);
+                    handshakeType = prevType;
+
+                    hsMsgOff += howmuch;
+                    if (hsMsgOff == hsMsgLen) {
+                        // Now is a complete handshake message.
+                        hsMsgOff = 0;
+                        hsMsgLen = 0;
+                    }
+                } else {    // hsMsgOff == hsMsgLen, a new handshake message
+                    handshakeType = plaintext.get();
+                    int handshakeLen = ((plaintext.get() & 0xFF) << 16) |
+                                       ((plaintext.get() & 0xFF) << 8) |
+                                        (plaintext.get() & 0xFF);
+                    plaintext.position(frgPos);
+                    if (remains < (handshakeLen + 1)) { // 1: handshake type
+                        // This handshake message is fragmented.
+                        prevType = handshakeType;
+                        hsMsgOff = remains - 4;         // 4: handshake header
+                        hsMsgLen = handshakeLen;
+                    }
+
+                    howmuch = Math.min(handshakeLen + 4, remains);
+                }
+
+                plaintext.limit(frgPos + howmuch);
+
+                if (handshakeType == HandshakeMessage.ht_hello_request) {
+                    // omitted from handshake hash computation
+                } else if ((handshakeType != HandshakeMessage.ht_finished) &&
+                    (handshakeType != HandshakeMessage.ht_certificate_verify)) {
+
+                    if (handshakeHash == null) {
+                        // used for cache only
+                        handshakeHash = new HandshakeHash(false);
+                    }
+                    handshakeHash.update(plaintext);
+                } else {
+                    // Reserve until this handshake message has been processed.
+                    if (handshakeHash == null) {
+                        // used for cache only
+                        handshakeHash = new HandshakeHash(false);
+                    }
+                    handshakeHash.reserve(plaintext);
+                }
+
+                plaintext.position(frgPos + howmuch);
+                plaintext.limit(pltLim);
+
+                frgPos += howmuch;
+                remains -= howmuch;
+            }
+
+            plaintext.position(pltPos);
+        }
+
+        return new Plaintext(contentType,
+                majorVersion, minorVersion, -1, -1L, plaintext);
+                // recordEpoch, recordSeq, plaintext);
+    }
+
+    private Plaintext handleUnknownRecord(ByteBuffer packet)
+            throws IOException, BadPaddingException {
+
+        //
+        // The packet should be a complete record.
+        //
+        int srcPos = packet.position();
+        int srcLim = packet.limit();
+
+        byte firstByte = packet.get(srcPos);
+        byte thirdByte = packet.get(srcPos + 2);
+
+        // Does it look like a Version 2 client hello (V2ClientHello)?
+        if (((firstByte & 0x80) != 0) && (thirdByte == 1)) {
+            /*
+             * If SSLv2Hello is not enabled, throw an exception.
+             */
+            if (helloVersion != ProtocolVersion.SSL20Hello) {
+                throw new SSLHandshakeException("SSLv2Hello is not enabled");
+            }
+
+            byte majorVersion = packet.get(srcPos + 3);
+            byte minorVersion = packet.get(srcPos + 4);
+
+            if ((majorVersion == ProtocolVersion.SSL20Hello.major) &&
+                (minorVersion == ProtocolVersion.SSL20Hello.minor)) {
+
+                /*
+                 * Looks like a V2 client hello, but not one saying
+                 * "let's talk SSLv3".  So we need to send an SSLv2
+                 * error message, one that's treated as fatal by
+                 * clients (Otherwise we'll hang.)
+                 */
+                if (debug != null && Debug.isOn("record")) {
+                     System.out.println(Thread.currentThread().getName() +
+                            "Requested to negotiate unsupported SSLv2!");
+                }
+
+                // hack code, the exception is caught in SSLEngineImpl
+                // so that SSLv2 error message can be delivered properly.
+                throw new UnsupportedOperationException(        // SSLv2Hello
+                        "Unsupported SSL v2.0 ClientHello");
+            }
+
+            /*
+             * If we can map this into a V3 ClientHello, read and
+             * hash the rest of the V2 handshake, turn it into a
+             * V3 ClientHello message, and pass it up.
+             */
+            packet.position(srcPos + 2);        // exclude the header
+
+            if (handshakeHash == null) {
+                // used for cache only
+                handshakeHash = new HandshakeHash(false);
+            }
+            handshakeHash.update(packet);
+            packet.position(srcPos);
+
+            ByteBuffer converted = convertToClientHello(packet);
+
+            if (debug != null && Debug.isOn("packet")) {
+                 Debug.printHex(
+                        "[Converted] ClientHello", converted);
+            }
+
+            return new Plaintext(ct_handshake,
+                majorVersion, minorVersion, -1, -1L, converted);
+        } else {
+            if (((firstByte & 0x80) != 0) && (thirdByte == 4)) {
+                throw new SSLException("SSL V2.0 servers are not supported.");
+            }
+
+            throw new SSLException("Unsupported or unrecognized SSL message");
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,570 @@
+/*
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.security.ssl;
+
+import java.io.*;
+import java.nio.*;
+import java.util.*;
+
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLHandshakeException;
+import sun.misc.HexDumpEncoder;
+import static sun.security.ssl.Ciphertext.RecordType;
+
+/**
+ * {@code OutputRecord} implementation for {@code SSLEngine}.
+ */
+final class SSLEngineOutputRecord extends OutputRecord implements SSLRecord {
+
+    private HandshakeFragment fragmenter = null;
+    private LinkedList<RecordMemo> alertMemos = new LinkedList<>();
+    private boolean isTalkingToV2 = false;      // SSLv2Hello
+    private ByteBuffer v2ClientHello = null;    // SSLv2Hello
+
+    private boolean isCloseWaiting = false;
+
+    SSLEngineOutputRecord() {
+        this.writeAuthenticator = MAC.TLS_NULL;
+
+        this.packetSize = SSLRecord.maxRecordSize;
+        this.protocolVersion = ProtocolVersion.DEFAULT_TLS;
+    }
+
+    @Override
+    synchronized public void close() throws IOException {
+        if (!isClosed) {
+            if (alertMemos != null && !alertMemos.isEmpty()) {
+                isCloseWaiting = true;
+            } else {
+                super.close();
+            }
+        }
+    }
+
+    @Override
+    void encodeAlert(byte level, byte description) throws IOException {
+        RecordMemo memo = new RecordMemo();
+
+        memo.contentType = Record.ct_alert;
+        memo.majorVersion = protocolVersion.major;
+        memo.minorVersion = protocolVersion.minor;
+        memo.encodeCipher = writeCipher;
+        memo.encodeAuthenticator = writeAuthenticator;
+
+        memo.fragment = new byte[2];
+        memo.fragment[0] = level;
+        memo.fragment[1] = description;
+
+        alertMemos.add(memo);
+    }
+
+    @Override
+    void encodeHandshake(byte[] source,
+            int offset, int length) throws IOException {
+
+        if (fragmenter == null) {
+           fragmenter = new HandshakeFragment();
+        }
+
+        if (firstMessage) {
+            firstMessage = false;
+
+            if ((helloVersion == ProtocolVersion.SSL20Hello) &&
+                (source[offset] == HandshakeMessage.ht_client_hello) &&
+                                            //  5: recode header size
+                (source[offset + 4 + 2 + 32] == 0)) {
+                                            // V3 session ID is empty
+                                            //  4: handshake header size
+                                            //  2: client_version in ClientHello
+                                            // 32: random in ClientHello
+
+                // Double space should be big enough for the converted message.
+                v2ClientHello = encodeV2ClientHello(
+                        source, (offset + 4), (length - 4));
+
+                v2ClientHello.position(2);     // exclude the header
+                handshakeHash.update(v2ClientHello);
+                v2ClientHello.position(0);
+
+                return;
+            }
+        }
+
+        byte handshakeType = source[offset];
+        if (handshakeType != HandshakeMessage.ht_hello_request) {
+            handshakeHash.update(source, offset, length);
+        }
+
+        fragmenter.queueUpFragment(source, offset, length);
+    }
+
+    @Override
+    void encodeChangeCipherSpec() throws IOException {
+        if (fragmenter == null) {
+           fragmenter = new HandshakeFragment();
+        }
+        fragmenter.queueUpChangeCipherSpec();
+    }
+
+    @Override
+    void encodeV2NoCipher() throws IOException {
+        isTalkingToV2 = true;
+    }
+
+    @Override
+    Ciphertext encode(ByteBuffer[] sources, int offset, int length,
+            ByteBuffer destination) throws IOException {
+
+        if (writeAuthenticator.seqNumOverflow()) {
+            if (debug != null && Debug.isOn("ssl")) {
+                System.out.println(Thread.currentThread().getName() +
+                    ", sequence number extremely close to overflow " +
+                    "(2^64-1 packets). Closing connection.");
+            }
+
+            throw new SSLHandshakeException("sequence number overflow");
+        }
+
+        int macLen = 0;
+        if (writeAuthenticator instanceof MAC) {
+            macLen = ((MAC)writeAuthenticator).MAClen();
+        }
+
+        int dstLim = destination.limit();
+        boolean isFirstRecordOfThePayload = true;
+        int packetLeftSize = Math.min(maxRecordSize, packetSize);
+        boolean needMorePayload = true;
+        long recordSN = 0L;
+        while (needMorePayload) {
+            int fragLen;
+            if (isFirstRecordOfThePayload && needToSplitPayload()) {
+                needMorePayload = true;
+
+                fragLen = 1;
+                isFirstRecordOfThePayload = false;
+            } else {
+                needMorePayload = false;
+
+                if (packetLeftSize > 0) {
+                    fragLen = writeCipher.calculateFragmentSize(
+                            packetLeftSize, macLen, headerSize);
+
+                    fragLen = Math.min(fragLen, Record.maxDataSize);
+                } else {
+                    fragLen = Record.maxDataSize;
+                }
+
+                if (fragmentSize > 0) {
+                    fragLen = Math.min(fragLen, fragmentSize);
+                }
+            }
+
+            int dstPos = destination.position();
+            int dstContent = dstPos + headerSize +
+                                writeCipher.getExplicitNonceSize();
+            destination.position(dstContent);
+
+            int remains = Math.min(fragLen, destination.remaining());
+            fragLen = 0;
+            int srcsLen = offset + length;
+            for (int i = offset; (i < srcsLen) && (remains > 0); i++) {
+                int amount = Math.min(sources[i].remaining(), remains);
+                int srcLimit = sources[i].limit();
+                sources[i].limit(sources[i].position() + amount);
+                destination.put(sources[i]);
+                sources[i].limit(srcLimit);         // restore the limit
+                remains -= amount;
+                fragLen += amount;
+
+                if (remains > 0) {
+                    offset++;
+                    length--;
+                }
+            }
+
+            destination.limit(destination.position());
+            destination.position(dstContent);
+
+            if ((debug != null) && Debug.isOn("record")) {
+                System.out.println(Thread.currentThread().getName() +
+                        ", WRITE: " + protocolVersion + " " +
+                        Record.contentName(Record.ct_application_data) +
+                        ", length = " + destination.remaining());
+            }
+
+            // Encrypt the fragment and wrap up a record.
+            recordSN = encrypt(writeAuthenticator, writeCipher,
+                    Record.ct_application_data, destination,
+                    dstPos, dstLim, headerSize,
+                    protocolVersion, false);
+
+            if ((debug != null) && Debug.isOn("packet")) {
+                ByteBuffer temporary = destination.duplicate();
+                temporary.limit(temporary.position());
+                temporary.position(dstPos);
+                Debug.printHex(
+                        "[Raw write]: length = " + temporary.remaining(),
+                        temporary);
+            }
+
+            packetLeftSize -= destination.position() - dstPos;
+
+            // remain the limit unchanged
+            destination.limit(dstLim);
+
+            if (isFirstAppOutputRecord) {
+                isFirstAppOutputRecord = false;
+            }
+        }
+
+        return new Ciphertext(RecordType.RECORD_APPLICATION_DATA, recordSN);
+    }
+
+    @Override
+    Ciphertext acquireCiphertext(ByteBuffer destination) throws IOException {
+        if (isTalkingToV2) {              // SSLv2Hello
+            // We don't support SSLv2.  Send an SSLv2 error message
+            // so that the connection can be closed gracefully.
+            //
+            // Please don't change the limit of the destination buffer.
+            destination.put(SSLRecord.v2NoCipher);
+            if (debug != null && Debug.isOn("packet")) {
+                Debug.printHex(
+                        "[Raw write]: length = " + SSLRecord.v2NoCipher.length,
+                        SSLRecord.v2NoCipher);
+            }
+
+            isTalkingToV2 = false;
+
+            return new Ciphertext(RecordType.RECORD_ALERT, -1L);
+        }
+
+        if (v2ClientHello != null) {
+            // deliver the SSLv2 format ClientHello message
+            //
+            // Please don't change the limit of the destination buffer.
+            if (debug != null) {
+                if (Debug.isOn("record")) {
+                     System.out.println(Thread.currentThread().getName() +
+                            ", WRITE: SSLv2 ClientHello message" +
+                            ", length = " + v2ClientHello.remaining());
+                }
+
+                if (Debug.isOn("packet")) {
+                    Debug.printHex(
+                        "[Raw write]: length = " + v2ClientHello.remaining(),
+                        v2ClientHello);
+                }
+            }
+
+            destination.put(v2ClientHello);
+            v2ClientHello = null;
+
+            return new Ciphertext(RecordType.RECORD_CLIENT_HELLO, -1L);
+        }
+
+        if (alertMemos != null && !alertMemos.isEmpty()) {
+            RecordMemo memo = alertMemos.pop();
+
+            int macLen = 0;
+            if (memo.encodeAuthenticator instanceof MAC) {
+                macLen = ((MAC)memo.encodeAuthenticator).MAClen();
+            }
+
+            int dstPos = destination.position();
+            int dstLim = destination.limit();
+            int dstContent = dstPos + headerSize +
+                                writeCipher.getExplicitNonceSize();
+            destination.position(dstContent);
+
+            destination.put(memo.fragment);
+
+            destination.limit(destination.position());
+            destination.position(dstContent);
+
+            if ((debug != null) && Debug.isOn("record")) {
+                System.out.println(Thread.currentThread().getName() +
+                        ", WRITE: " + protocolVersion + " " +
+                        Record.contentName(Record.ct_alert) +
+                        ", length = " + destination.remaining());
+            }
+
+            // Encrypt the fragment and wrap up a record.
+            long recordSN = encrypt(memo.encodeAuthenticator, memo.encodeCipher,
+                    Record.ct_alert, destination, dstPos, dstLim, headerSize,
+                    ProtocolVersion.valueOf(memo.majorVersion,
+                            memo.minorVersion), false);
+
+            if ((debug != null) && Debug.isOn("packet")) {
+                ByteBuffer temporary = destination.duplicate();
+                temporary.limit(temporary.position());
+                temporary.position(dstPos);
+                Debug.printHex(
+                        "[Raw write]: length = " + temporary.remaining(),
+                        temporary);
+            }
+
+            // remain the limit unchanged
+            destination.limit(dstLim);
+
+            if (isCloseWaiting && (memo.contentType == Record.ct_alert)) {
+                isCloseWaiting = true;
+                close();
+            }
+            return new Ciphertext(RecordType.RECORD_ALERT, recordSN);
+        }
+
+        if (fragmenter != null) {
+            return fragmenter.acquireCiphertext(destination);
+        }
+
+        return null;
+    }
+
+    @Override
+    boolean isEmpty() {
+        return (!isTalkingToV2) && (v2ClientHello == null) &&
+                ((fragmenter == null) || fragmenter.isEmpty()) &&
+                ((alertMemos == null) || alertMemos.isEmpty());
+    }
+
+    // buffered record fragment
+    private static class RecordMemo {
+        byte            contentType;
+        byte            majorVersion;
+        byte            minorVersion;
+        CipherBox       encodeCipher;
+        Authenticator   encodeAuthenticator;
+
+        byte[]          fragment;
+    }
+
+    private static class HandshakeMemo extends RecordMemo {
+        byte            handshakeType;
+        int             acquireOffset;
+    }
+
+    final class HandshakeFragment {
+        private LinkedList<RecordMemo> handshakeMemos = new LinkedList<>();
+
+        void queueUpFragment(byte[] source,
+                int offset, int length) throws IOException {
+
+            HandshakeMemo memo = new HandshakeMemo();
+
+            memo.contentType = Record.ct_handshake;
+            memo.majorVersion = protocolVersion.major;  // kick start version?
+            memo.minorVersion = protocolVersion.minor;
+            memo.encodeCipher = writeCipher;
+            memo.encodeAuthenticator = writeAuthenticator;
+
+            memo.handshakeType = source[offset];
+            memo.acquireOffset = 0;
+            memo.fragment = new byte[length - 4];       // 4: header size
+                                                        //    1: HandshakeType
+                                                        //    3: message length
+            System.arraycopy(source, offset + 4, memo.fragment, 0, length - 4);
+
+            handshakeMemos.add(memo);
+        }
+
+        void queueUpChangeCipherSpec() {
+            RecordMemo memo = new RecordMemo();
+
+            memo.contentType = Record.ct_change_cipher_spec;
+            memo.majorVersion = protocolVersion.major;
+            memo.minorVersion = protocolVersion.minor;
+            memo.encodeCipher = writeCipher;
+            memo.encodeAuthenticator = writeAuthenticator;
+
+            memo.fragment = new byte[1];
+            memo.fragment[0] = 1;
+
+            handshakeMemos.add(memo);
+        }
+
+        Ciphertext acquireCiphertext(ByteBuffer dstBuf) throws IOException {
+            if (isEmpty()) {
+                return null;
+            }
+
+            RecordMemo memo = handshakeMemos.getFirst();
+            HandshakeMemo hsMemo = null;
+            if (memo.contentType == Record.ct_handshake) {
+                hsMemo = (HandshakeMemo)memo;
+            }
+
+            int macLen = 0;
+            if (memo.encodeAuthenticator instanceof MAC) {
+                macLen = ((MAC)memo.encodeAuthenticator).MAClen();
+            }
+
+            // ChangeCipherSpec message is pretty small.  Don't worry about
+            // the fragmentation of ChangeCipherSpec record.
+            int fragLen;
+            if (packetSize > 0) {
+                fragLen = Math.min(maxRecordSize, packetSize);
+                fragLen = memo.encodeCipher.calculateFragmentSize(
+                        fragLen, macLen, headerSize);
+            } else {
+                fragLen = Record.maxDataSize;
+            }
+
+            if (fragmentSize > 0) {
+                fragLen = Math.min(fragLen, fragmentSize);
+            }
+
+            int dstPos = dstBuf.position();
+            int dstLim = dstBuf.limit();
+            int dstContent = dstPos + headerSize +
+                                    memo.encodeCipher.getExplicitNonceSize();
+            dstBuf.position(dstContent);
+
+            if (hsMemo != null) {
+                int remainingFragLen = fragLen;
+                while ((remainingFragLen > 0) && !handshakeMemos.isEmpty()) {
+                    int memoFragLen = hsMemo.fragment.length;
+                    if (hsMemo.acquireOffset == 0) {
+                        // Don't fragment handshake message header
+                        if (remainingFragLen <= 4) {
+                            break;
+                        }
+
+                        dstBuf.put(hsMemo.handshakeType);
+                        dstBuf.put((byte)((memoFragLen >> 16) & 0xFF));
+                        dstBuf.put((byte)((memoFragLen >> 8) & 0xFF));
+                        dstBuf.put((byte)(memoFragLen & 0xFF));
+
+                        remainingFragLen -= 4;
+                    } // Otherwise, handshake message is fragmented.
+
+                    int chipLen = Math.min(remainingFragLen,
+                            (memoFragLen - hsMemo.acquireOffset));
+                    dstBuf.put(hsMemo.fragment, hsMemo.acquireOffset, chipLen);
+
+                    hsMemo.acquireOffset += chipLen;
+                    if (hsMemo.acquireOffset == memoFragLen) {
+                        handshakeMemos.removeFirst();
+
+                        // still have space for more records?
+                        if ((remainingFragLen > chipLen) &&
+                                 !handshakeMemos.isEmpty()) {
+
+                            // look for the next buffered record fragment
+                            RecordMemo reMemo = handshakeMemos.getFirst();
+                            if (reMemo.contentType == Record.ct_handshake) {
+                                hsMemo = (HandshakeMemo)reMemo;
+                            } else {
+                                // not handshake message, break the loop
+                                break;
+                            }
+                        }
+                    }
+
+                    remainingFragLen -= chipLen;
+                }
+
+                fragLen -= remainingFragLen;
+            } else {
+                fragLen = Math.min(fragLen, memo.fragment.length);
+                dstBuf.put(memo.fragment, 0, fragLen);
+
+                handshakeMemos.removeFirst();
+            }
+
+            dstBuf.limit(dstBuf.position());
+            dstBuf.position(dstContent);
+
+            if ((debug != null) && Debug.isOn("record")) {
+                System.out.println(Thread.currentThread().getName() +
+                        ", WRITE: " + protocolVersion + " " +
+                        Record.contentName(memo.contentType) +
+                        ", length = " + dstBuf.remaining());
+            }
+
+            // Encrypt the fragment and wrap up a record.
+            long recordSN = encrypt(memo.encodeAuthenticator, memo.encodeCipher,
+                    memo.contentType, dstBuf,
+                    dstPos, dstLim, headerSize,
+                    ProtocolVersion.valueOf(memo.majorVersion,
+                            memo.minorVersion), false);
+
+            if ((debug != null) && Debug.isOn("packet")) {
+                ByteBuffer temporary = dstBuf.duplicate();
+                temporary.limit(temporary.position());
+                temporary.position(dstPos);
+                Debug.printHex(
+                        "[Raw write]: length = " + temporary.remaining(),
+                        temporary);
+            }
+
+            // remain the limit unchanged
+            dstBuf.limit(dstLim);
+
+            // Reset the fragmentation offset.
+            if (hsMemo != null) {
+                return new Ciphertext(RecordType.valueOf(
+                        hsMemo.contentType, hsMemo.handshakeType), recordSN);
+            } else {
+                return new Ciphertext(
+                        RecordType.RECORD_CHANGE_CIPHER_SPEC, recordSN);
+            }
+        }
+
+        boolean isEmpty() {
+            return handshakeMemos.isEmpty();
+        }
+    }
+
+    /*
+     * Need to split the payload except the following cases:
+     *
+     * 1. protocol version is TLS 1.1 or later;
+     * 2. bulk cipher does not use CBC mode, including null bulk cipher suites.
+     * 3. the payload is the first application record of a freshly
+     *    negotiated TLS session.
+     * 4. the CBC protection is disabled;
+     *
+     * By default, we counter chosen plaintext issues on CBC mode
+     * ciphersuites in SSLv3/TLS1.0 by sending one byte of application
+     * data in the first record of every payload, and the rest in
+     * subsequent record(s). Note that the issues have been solved in
+     * TLS 1.1 or later.
+     *
+     * It is not necessary to split the very first application record of
+     * a freshly negotiated TLS session, as there is no previous
+     * application data to guess.  To improve compatibility, we will not
+     * split such records.
+     *
+     * This avoids issues in the outbound direction.  For a full fix,
+     * the peer must have similar protections.
+     */
+    boolean needToSplitPayload() {
+        return (!protocolVersion.useTLS11PlusSpec()) &&
+                writeCipher.isCBCMode() && !isFirstAppOutputRecord &&
+                Record.enableCBCProtection;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLRecord.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.security.ssl;
+
+/**
+ * SSL/TLS record
+ *
+ * @author David Brownell
+ */
+interface SSLRecord extends Record {
+
+    static final int    headerSize = 5;         // SSLv3 record header
+
+    /*
+     * The size of the header plus the max IV length
+     */
+    static final int    headerPlusMaxIVSize =
+                                      headerSize        // header
+                                    + maxIVLength;      // iv
+
+    /*
+     * The maximum size that may be increased when translating plaintext to
+     * ciphertext fragment.
+     */
+    static final int    maxPlaintextPlusSize =
+                                      headerSize        // header
+                                    + maxIVLength       // iv
+                                    + maxMacSize        // MAC or AEAD tag
+                                    + maxPadding;       // block cipher padding
+
+    /*
+     * SSL has a maximum record size.  It's header, (compressed) data,
+     * padding, and a trailer for the message authentication information (MAC
+     * for block and stream ciphers, and message authentication tag for AEAD
+     * ciphers).
+     *
+     * Some compression algorithms have rare cases where they expand the data.
+     * As we don't support compression at this time, leave that out.
+     */
+    static final int    maxRecordSize =
+                                      headerPlusMaxIVSize   // header + iv
+                                    + maxDataSize           // data
+                                    + maxPadding            // padding
+                                    + maxMacSize;           // MAC or AEAD tag
+
+    /*
+     * For CBC protection in SSL3/TLS1, we break some plaintext into two
+     * packets.  Max application data size for the second packet.
+     */
+    static final int    maxDataSizeMinusOneByteRecord =
+                                  maxDataSize       // max data size
+                                - (                 // max one byte record size
+                                      headerPlusMaxIVSize   // header + iv
+                                    + 1             // one byte data
+                                    + maxPadding    // padding
+                                    + maxMacSize    // MAC
+                                  );
+
+    /*
+     * The maximum large record size.
+     *
+     * Some SSL/TLS implementations support large fragment upto 2^15 bytes,
+     * such as Microsoft. We support large incoming fragments.
+     *
+     * The maximum large record size is defined as maxRecordSize plus 2^14,
+     * this is the amount OpenSSL is using.
+     */
+    static final int    maxLargeRecordSize =
+                maxRecordSize   // Max size with a conforming implementation
+              + maxDataSize;    // extra 2^14 bytes for large data packets.
+
+
+    /*
+     * Maximum record size for alert and change cipher spec records.
+     * They only contain 2 and 1 bytes of data, respectively.
+     * Allocate a smaller array.
+     */
+    static final int    maxAlertRecordSize =
+                                      headerPlusMaxIVSize   // header + iv
+                                    + 2                     // alert
+                                    + maxPadding            // padding
+                                    + maxMacSize;           // MAC
+
+    /*
+     * We may need to send this SSL v2 "No Cipher" message back, if we
+     * are faced with an SSLv2 "hello" that's not saying "I talk v3".
+     * It's the only one documented in the V2 spec as a fatal error.
+     */
+    static final byte[] v2NoCipher = {
+        (byte)0x80, (byte)0x03, // unpadded 3 byte record
+        (byte)0x00,             // ... error message
+        (byte)0x00, (byte)0x01  // ... NO_CIPHER error
+    };
+}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLServerSocketImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLServerSocketImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -68,7 +68,7 @@
     private SSLContextImpl      sslContext;
 
     /* Do newly accepted connections require clients to authenticate? */
-    private byte                doClientAuth = SSLEngineImpl.clauth_none;
+    private ClientAuthType    clientAuthType = ClientAuthType.CLIENT_AUTH_NONE;
 
     /* Do new connections created here use the "server" mode of SSL? */
     private boolean             useServerMode = true;
@@ -230,13 +230,13 @@
      */
     @Override
     public void setNeedClientAuth(boolean flag) {
-        doClientAuth = (flag ?
-            SSLEngineImpl.clauth_required : SSLEngineImpl.clauth_none);
+        clientAuthType = (flag ? ClientAuthType.CLIENT_AUTH_REQUIRED :
+                ClientAuthType.CLIENT_AUTH_NONE);
     }
 
     @Override
     public boolean getNeedClientAuth() {
-        return (doClientAuth == SSLEngineImpl.clauth_required);
+        return (clientAuthType == ClientAuthType.CLIENT_AUTH_REQUIRED);
     }
 
     /**
@@ -245,13 +245,13 @@
      */
     @Override
     public void setWantClientAuth(boolean flag) {
-        doClientAuth = (flag ?
-            SSLEngineImpl.clauth_requested : SSLEngineImpl.clauth_none);
+        clientAuthType = (flag ? ClientAuthType.CLIENT_AUTH_REQUESTED :
+                ClientAuthType.CLIENT_AUTH_NONE);
     }
 
     @Override
     public boolean getWantClientAuth() {
-        return (doClientAuth == SSLEngineImpl.clauth_requested);
+        return (clientAuthType == ClientAuthType.CLIENT_AUTH_REQUESTED);
     }
 
     /**
@@ -341,7 +341,7 @@
     @Override
     public Socket accept() throws IOException {
         SSLSocketImpl s = new SSLSocketImpl(sslContext, useServerMode,
-            enabledCipherSuites, doClientAuth, enableSessionCreation,
+            enabledCipherSuites, clientAuthType, enableSessionCreation,
             enabledProtocols, identificationProtocol, algorithmConstraints,
             sniMatchers, preferLocalCipherSuites);
 
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -109,6 +109,8 @@
     private String[]            peerSupportedSignAlgs;
     private List<SNIServerName>    requestedServerNames;
 
+    private int                 negotiatedMaxFragLen;
+    private int                 maximumPacketSize;
 
     // Principals for non-certificate based cipher suites
     private Principal peerPrincipal;
@@ -177,6 +179,7 @@
         sessionCount = ++counter;
         localSupportedSignAlgs =
             SignatureAndHashAlgorithm.getAlgorithmNames(algorithms);
+        negotiatedMaxFragLen = -1;
 
         if (debug != null && Debug.isOn("session")) {
             System.out.println("%% Initialized:  " + this);
@@ -422,10 +425,9 @@
         // change record of peer identity even by accident, much
         // less do it intentionally.
         //
-        if ((cipherSuite.keyExchange == K_KRB5) ||
-            (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
+        if (ClientKeyExchangeService.find(cipherSuite.keyExchange.name) != null) {
             throw new SSLPeerUnverifiedException("no certificates expected"
-                        + " for Kerberos cipher suites");
+                        + " for " + cipherSuite.keyExchange + " cipher suites");
         }
         if (peerCerts == null) {
             throw new SSLPeerUnverifiedException("peer not authenticated");
@@ -478,10 +480,9 @@
         // change record of peer identity even by accident, much
         // less do it intentionally.
         //
-        if ((cipherSuite.keyExchange == K_KRB5) ||
-            (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
+        if (ClientKeyExchangeService.find(cipherSuite.keyExchange.name) != null) {
             throw new SSLPeerUnverifiedException("no certificates expected"
-                        + " for Kerberos cipher suites");
+                        + " for " + cipherSuite.keyExchange + " cipher suites");
         }
         if (peerCerts == null) {
             throw new SSLPeerUnverifiedException("peer not authenticated");
@@ -519,10 +520,9 @@
          * change record of peer identity even by accident, much
          * less do it intentionally.
          */
-        if ((cipherSuite.keyExchange == K_KRB5) ||
-            (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
+        if (ClientKeyExchangeService.find(cipherSuite.keyExchange.name) != null) {
             throw new SSLPeerUnverifiedException("no certificates expected"
-                        + " for Kerberos cipher suites");
+                        + " for " + cipherSuite.keyExchange + " cipher suites");
         }
         if (peerCerts != null) {
             return peerCerts.clone();
@@ -537,7 +537,7 @@
      *
      * @return the peer's principal. Returns an X500Principal of the
      * end-entity certificate for X509-based cipher suites, and
-     * Principal for Kerberos cipher suites.
+     * Principal for Kerberos cipher suites, etc.
      *
      * @throws SSLPeerUnverifiedException if the peer's identity has not
      *          been verified
@@ -546,12 +546,10 @@
     public Principal getPeerPrincipal()
                 throws SSLPeerUnverifiedException
     {
-        if ((cipherSuite.keyExchange == K_KRB5) ||
-            (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
+        if (ClientKeyExchangeService.find(cipherSuite.keyExchange.name) != null) {
             if (peerPrincipal == null) {
                 throw new SSLPeerUnverifiedException("peer not authenticated");
             } else {
-                // Eliminate dependency on KerberosPrincipal
                 return peerPrincipal;
             }
         }
@@ -566,15 +564,13 @@
      *
      * @return the principal sent to the peer. Returns an X500Principal
      * of the end-entity certificate for X509-based cipher suites, and
-     * Principal for Kerberos cipher suites. If no principal was
+     * Principal for Kerberos cipher suites, etc. If no principal was
      * sent, then null is returned.
      */
     @Override
     public Principal getLocalPrincipal() {
 
-        if ((cipherSuite.keyExchange == K_KRB5) ||
-            (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
-                // Eliminate dependency on KerberosPrincipal
+        if (ClientKeyExchangeService.find(cipherSuite.keyExchange.name) != null) {
                 return (localPrincipal == null ? null : localPrincipal);
         }
         return (localCerts == null ? null :
@@ -785,8 +781,30 @@
      */
     @Override
     public synchronized int getPacketBufferSize() {
-        return acceptLargeFragments ?
-                Record.maxLargeRecordSize : Record.maxRecordSize;
+        // Use the bigger packet size calculated from maximumPacketSize
+        // and negotiatedMaxFragLen.
+        int packetSize = 0;
+        if (negotiatedMaxFragLen > 0) {
+            packetSize = cipherSuite.calculatePacketSize(
+                    negotiatedMaxFragLen, protocolVersion,
+                    protocolVersion.isDTLSProtocol());
+        }
+
+        if (maximumPacketSize > 0) {
+            return (maximumPacketSize > packetSize) ?
+                    maximumPacketSize : packetSize;
+        }
+
+        if (packetSize != 0) {
+           return packetSize;
+        }
+
+        if (protocolVersion.isDTLSProtocol()) {
+            return DTLSRecord.maxRecordSize;
+        } else {
+            return acceptLargeFragments ?
+                    SSLRecord.maxLargeRecordSize : SSLRecord.maxRecordSize;
+        }
     }
 
     /**
@@ -795,7 +813,64 @@
      */
     @Override
     public synchronized int getApplicationBufferSize() {
-        return getPacketBufferSize() - Record.headerSize;
+        // Use the bigger fragment size calculated from maximumPacketSize
+        // and negotiatedMaxFragLen.
+        int fragmentSize = 0;
+        if (maximumPacketSize > 0) {
+            fragmentSize = cipherSuite.calculateFragSize(
+                    maximumPacketSize, protocolVersion,
+                    protocolVersion.isDTLSProtocol());
+        }
+
+        if (negotiatedMaxFragLen > 0) {
+            return (negotiatedMaxFragLen > fragmentSize) ?
+                    negotiatedMaxFragLen : fragmentSize;
+        }
+
+        if (fragmentSize != 0) {
+            return fragmentSize;
+        }
+
+        if (protocolVersion.isDTLSProtocol()) {
+            return Record.maxDataSize;
+        } else {
+            int maxPacketSize = acceptLargeFragments ?
+                        SSLRecord.maxLargeRecordSize : SSLRecord.maxRecordSize;
+            return (maxPacketSize - SSLRecord.headerSize);
+        }
+    }
+
+    /**
+     * Sets the negotiated maximum fragment length, as specified by the
+     * max_fragment_length ClientHello extension in RFC 6066.
+     *
+     * @param  negotiatedMaxFragLen
+     *         the negotiated maximum fragment length, or {@code -1} if
+     *         no such length has been negotiated.
+     */
+    synchronized void setNegotiatedMaxFragSize(
+            int negotiatedMaxFragLen) {
+
+        this.negotiatedMaxFragLen = negotiatedMaxFragLen;
+    }
+
+    /**
+     * Get the negotiated maximum fragment length, as specified by the
+     * max_fragment_length ClientHello extension in RFC 6066.
+     *
+     * @return the negotiated maximum fragment length, or {@code -1} if
+     *         no such length has been negotiated.
+     */
+    synchronized int getNegotiatedMaxFragSize() {
+        return negotiatedMaxFragLen;
+    }
+
+    synchronized void setMaximumPacketSize(int maximumPacketSize) {
+        this.maximumPacketSize = maximumPacketSize;
+    }
+
+    synchronized int getMaximumPacketSize() {
+        return maximumPacketSize;
     }
 
     /**
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -27,6 +27,7 @@
 package sun.security.ssl;
 
 import java.io.*;
+import java.nio.*;
 import java.net.*;
 import java.security.GeneralSecurityException;
 import java.security.AccessController;
@@ -155,30 +156,16 @@
     private static final int    cs_DATA = 2;
     private static final int    cs_RENEGOTIATE = 3;
     private static final int    cs_ERROR = 4;
-    private static final int   cs_SENT_CLOSE = 5;
+    private static final int    cs_SENT_CLOSE = 5;
     private static final int    cs_CLOSED = 6;
     private static final int    cs_APP_CLOSED = 7;
 
-
-    /*
-     * Client authentication be off, requested, or required.
-     *
-     * Migrated to SSLEngineImpl:
-     *    clauth_none/cl_auth_requested/clauth_required
-     */
-
     /*
      * Drives the protocol state machine.
      */
     private volatile int        connectionState;
 
     /*
-     * Flag indicating that the engine's handshaker has done the necessary
-     * steps so the engine may process a ChangeCipherSpec message.
-     */
-    private boolean             receivedCCS;
-
-    /*
      * Flag indicating if the next record we receive MUST be a Finished
      * message. Temporarily set during the handshake to ensure that
      * a change cipher spec message is followed by a finished message.
@@ -197,7 +184,8 @@
      * Per-connection private state that doesn't change when the
      * session is changed.
      */
-    private byte                doClientAuth;
+    private ClientAuthType      doClientAuth =
+                                        ClientAuthType.CLIENT_AUTH_NONE;
     private boolean             roleIsServer;
     private boolean             enableSessionCreation = true;
     private String              host;
@@ -284,9 +272,9 @@
      * is created, at which time the new handshaker's state is set.
      *
      * The readLock is held during readRecord(), which is responsible
-     * for reading an InputRecord, decrypting it, and processing it.
+     * for reading an SSLInputRecord, decrypting it, and processing it.
      * The readLock ensures that these three steps are done atomically
-     * and that once started, no other thread can block on InputRecord.read.
+     * and that once started, no other thread can block on SSLInputRecord.read.
      * This is necessary so that processing of close_notify alerts
      * from the peer are handled properly.
      */
@@ -294,14 +282,8 @@
     final ReentrantLock         writeLock = new ReentrantLock();
     final private Object        readLock = new Object();
 
-    private InputRecord         inrec;
-
-    /*
-     * Crypto state that's reinitialized when the session changes.
-     */
-    private Authenticator       readAuthenticator, writeAuthenticator;
-    private CipherBox           readCipher, writeCipher;
-    // NOTE: compression state would be saved here
+    InputRecord                 inputRecord;
+    OutputRecord                outputRecord;
 
     /*
      * security parameters for secure renegotiation.
@@ -368,7 +350,7 @@
     /*
      * The SSL version associated with this connection.
      */
-    private ProtocolVersion     protocolVersion = ProtocolVersion.DEFAULT;
+    private ProtocolVersion     protocolVersion = ProtocolVersion.DEFAULT_TLS;
 
     /* Class and subclass dynamic debugging support */
     private static final Debug debug = Debug.getInstance("ssl");
@@ -390,6 +372,11 @@
      */
     private boolean preferLocalCipherSuites = false;
 
+    /*
+     * The maximum expected network packet size for SSL/TLS/DTLS records.
+     */
+    private int maximumPacketSize = 0;
+
     //
     // CONSTRUCTORS AND INITIALIZATION CODE
     //
@@ -491,7 +478,7 @@
      * giving control over the use of SSL client authentication.
      */
     SSLSocketImpl(SSLContextImpl context, boolean serverMode,
-            CipherSuiteList suites, byte clientAuth,
+            CipherSuiteList suites, ClientAuthType clientAuth,
             boolean sessionCreation, ProtocolList protocols,
             String identificationProtocol,
             AlgorithmConstraints algorithmConstraints,
@@ -594,17 +581,6 @@
          */
         roleIsServer = isServer;
         connectionState = cs_START;
-        receivedCCS = false;
-
-        /*
-         * default read and write side cipher and MAC support
-         *
-         * Note:  compression support would go here too
-         */
-        readCipher = CipherBox.NULL;
-        readAuthenticator = MAC.NULL;
-        writeCipher = CipherBox.NULL;
-        writeAuthenticator = MAC.NULL;
 
         // initial security parameters for secure renegotiation
         secureRenegotiation = false;
@@ -616,7 +592,10 @@
         enabledProtocols =
                 sslContext.getDefaultProtocolList(roleIsServer);
 
-        inrec = null;
+        inputRecord = new SSLSocketInputRecord();;
+        outputRecord = new SSLSocketOutputRecord();
+
+        maximumPacketSize = outputRecord.getMaxPacketSize();
 
         // save the acc
         acc = AccessController.getContext();
@@ -672,6 +651,9 @@
         sockInput = super.getInputStream();
         sockOutput = super.getOutputStream();
 
+        inputRecord.setDeliverStream(sockOutput);
+        outputRecord.setDeliverStream(sockOutput);
+
         /*
          * Move to handshaking state, with pending session initialized
          * to defaults and the appropriate kind of handshaker set up.
@@ -696,29 +678,18 @@
     //
 
     /*
-     * AppOutputStream calls may need to buffer multiple outbound
-     * application packets.
+     * Application data record output.
      *
-     * All other writeRecord() calls will not buffer, so do not hold
-     * these records.
+     * Application data can't be sent until the first handshake establishes
+     * a session.
      */
-    void writeRecord(OutputRecord r) throws IOException {
-        writeRecord(r, false);
-    }
-
-    /*
-     * Record Output. Application data can't be sent until the first
-     * handshake establishes a session.
-     *
-     * NOTE:  we let empty records be written as a hook to force some
-     * TCP-level activity, notably handshaking, to occur.
-     */
-    void writeRecord(OutputRecord r, boolean holdRecord) throws IOException {
+    void writeRecord(byte[] source, int offset, int length) throws IOException {
         /*
          * The loop is in case of HANDSHAKE --> ERROR transitions, etc
          */
-    loop:
-        while (r.contentType() == Record.ct_application_data) {
+        // Don't bother to check the emptiness of source applicatoin data
+        // before the security connection established.
+        for (boolean readyForApp = false; !readyForApp;) {
             /*
              * Not all states support passing application data.  We
              * synchronize access to the connection state, so that
@@ -726,41 +697,43 @@
              */
             switch (getConnectionState()) {
 
-            /*
-             * We've deferred the initial handshaking till just now,
-             * when presumably a thread's decided it's OK to block for
-             * longish periods of time for I/O purposes (as well as
-             * configured the cipher suites it wants to use).
-             */
-            case cs_HANDSHAKE:
-                performInitialHandshake();
-                break;
+                /*
+                 * We've deferred the initial handshaking till just now,
+                 * when presumably a thread's decided it's OK to block for
+                 * longish periods of time for I/O purposes (as well as
+                 * configured the cipher suites it wants to use).
+                 */
+                case cs_HANDSHAKE:
+                    performInitialHandshake();
+                    break;
 
-            case cs_DATA:
-            case cs_RENEGOTIATE:
-                break loop;
+                case cs_DATA:
+                case cs_RENEGOTIATE:
+                    readyForApp = true;
+                    break;
 
-            case cs_ERROR:
-                fatal(Alerts.alert_close_notify,
-                    "error while writing to socket");
-                break; // dummy
+                case cs_ERROR:
+                    fatal(Alerts.alert_close_notify,
+                            "error while writing to socket");
+                    break; // dummy
 
-            case cs_SENT_CLOSE:
-            case cs_CLOSED:
-            case cs_APP_CLOSED:
-                // we should never get here (check in AppOutputStream)
-                // this is just a fallback
-                if (closeReason != null) {
-                    throw closeReason;
-                } else {
-                    throw new SocketException("Socket closed");
-                }
+                case cs_SENT_CLOSE:
+                case cs_CLOSED:
+                case cs_APP_CLOSED:
+                    // we should never get here (check in AppOutputStream)
+                    // this is just a fallback
+                    if (closeReason != null) {
+                        throw closeReason;
+                    } else {
+                        throw new SocketException("Socket closed");
+                    }
 
-            /*
-             * Else something's goofy in this state machine's use.
-             */
-            default:
-                throw new SSLProtocolException("State error, send app data");
+                /*
+                 * Else something's goofy in this state machine's use.
+                 */
+                default:
+                    throw new SSLProtocolException(
+                            "State error, send app data");
             }
         }
 
@@ -772,97 +745,19 @@
         // implementations are fragile and don't like to see empty
         // records, so this also increases robustness.
         //
-        if (!r.isEmpty()) {
-
-            // If the record is a close notify alert, we need to honor
-            // socket option SO_LINGER. Note that we will try to send
-            // the close notify even if the SO_LINGER set to zero.
-            if (r.isAlert(Alerts.alert_close_notify) && getSoLinger() >= 0) {
-
-                // keep and clear the current thread interruption status.
-                boolean interrupted = Thread.interrupted();
-                try {
-                    if (writeLock.tryLock(getSoLinger(), TimeUnit.SECONDS)) {
-                        try {
-                            writeRecordInternal(r, holdRecord);
-                        } finally {
-                            writeLock.unlock();
-                        }
-                    } else {
-                        SSLException ssle = new SSLException(
-                                "SO_LINGER timeout," +
-                                " close_notify message cannot be sent.");
-
-
-                        // For layered, non-autoclose sockets, we are not
-                        // able to bring them into a usable state, so we
-                        // treat it as fatal error.
-                        if (isLayered() && !autoClose) {
-                            // Note that the alert description is
-                            // specified as -1, so no message will be send
-                            // to peer anymore.
-                            fatal((byte)(-1), ssle);
-                        } else if ((debug != null) && Debug.isOn("ssl")) {
-                            System.out.println(
-                                Thread.currentThread().getName() +
-                                ", received Exception: " + ssle);
-                        }
-
-                        // RFC2246 requires that the session becomes
-                        // unresumable if any connection is terminated
-                        // without proper close_notify messages with
-                        // level equal to warning.
-                        //
-                        // RFC4346 no longer requires that a session not be
-                        // resumed if failure to properly close a connection.
-                        //
-                        // We choose to make the session unresumable if
-                        // failed to send the close_notify message.
-                        //
-                        sess.invalidate();
-                    }
-                } catch (InterruptedException ie) {
-                    // keep interrupted status
-                    interrupted = true;
-                }
-
-                // restore the interrupted status
-                if (interrupted) {
-                    Thread.currentThread().interrupt();
-                }
-            } else {
-                writeLock.lock();
-                try {
-                    writeRecordInternal(r, holdRecord);
-                } finally {
-                    writeLock.unlock();
-                }
+        if (length > 0) {
+            writeLock.lock();
+            try {
+                outputRecord.deliver(source, offset, length);
+            } catch (SSLHandshakeException she) {
+                // may be record sequence number overflow
+                fatal(Alerts.alert_handshake_failure, she);
+            } catch (IOException e) {
+                fatal(Alerts.alert_unexpected_message, e);
+            } finally {
+                writeLock.unlock();
             }
         }
-    }
-
-    private void writeRecordInternal(OutputRecord r,
-            boolean holdRecord) throws IOException {
-
-        // r.compress(c);
-        r.encrypt(writeAuthenticator, writeCipher);
-
-        if (holdRecord) {
-            // If we were requested to delay the record due to possibility
-            // of Nagle's being active when finally got to writing, and
-            // it's actually not, we don't really need to delay it.
-            if (getTcpNoDelay()) {
-                holdRecord = false;
-            } else {
-                // We need to hold the record, so let's provide
-                // a per-socket place to do it.
-                if (heldRecordBuffer == null) {
-                    // Likely only need 37 bytes.
-                    heldRecordBuffer = new ByteArrayOutputStream(40);
-                }
-            }
-        }
-        r.write(sockOutput, holdRecord, heldRecordBuffer);
 
         /*
          * Check the sequence number state
@@ -874,51 +769,173 @@
          * when there is enough sequence number space left to
          * handle a few more records, so the sequence number
          * of the last record cannot be wrapped.
+         *
+         * Don't bother to kickstart the renegotiation when the
+         * local is asking for it.
          */
-        if (connectionState < cs_ERROR) {
-            checkSequenceNumber(writeAuthenticator, r.contentType());
-        }
+        if ((connectionState == cs_DATA) && outputRecord.seqNumIsHuge()) {
+            /*
+             * Ask for renegotiation when need to renew sequence number.
+             *
+             * Don't bother to kickstart the renegotiation when the local is
+             * asking for it.
+             */
+            if (debug != null && Debug.isOn("ssl")) {
+                System.out.println(Thread.currentThread().getName() +
+                        ", request renegotiation " +
+                        "to avoid sequence number overflow");
+            }
 
-        // turn off the flag of the first application record
-        if (isFirstAppOutputRecord &&
-                r.contentType() == Record.ct_application_data) {
-            isFirstAppOutputRecord = false;
+            startHandshake();
         }
     }
 
     /*
-     * Need to split the payload except the following cases:
-     *
-     * 1. protocol version is TLS 1.1 or later;
-     * 2. bulk cipher does not use CBC mode, including null bulk cipher suites.
-     * 3. the payload is the first application record of a freshly
-     *    negotiated TLS session.
-     * 4. the CBC protection is disabled;
-     *
-     * More details, please refer to AppOutputStream.write(byte[], int, int).
+     * Alert record output.
      */
-    boolean needToSplitPayload() {
-        writeLock.lock();
-        try {
-            return (protocolVersion.v <= ProtocolVersion.TLS10.v) &&
-                    writeCipher.isCBCMode() && !isFirstAppOutputRecord &&
-                    Record.enableCBCProtection;
-        } finally {
-            writeLock.unlock();
+    void writeAlert(byte level, byte description) throws IOException {
+
+        // If the record is a close notify alert, we need to honor
+        // socket option SO_LINGER. Note that we will try to send
+        // the close notify even if the SO_LINGER set to zero.
+        if ((description == Alerts.alert_close_notify) && getSoLinger() >= 0) {
+
+            // keep and clear the current thread interruption status.
+            boolean interrupted = Thread.interrupted();
+            try {
+                if (writeLock.tryLock(getSoLinger(), TimeUnit.SECONDS)) {
+                    try {
+                        outputRecord.encodeAlert(level, description);
+                    } finally {
+                        writeLock.unlock();
+                    }
+                } else {
+                    SSLException ssle = new SSLException(
+                            "SO_LINGER timeout," +
+                            " close_notify message cannot be sent.");
+
+
+                    // For layered, non-autoclose sockets, we are not
+                    // able to bring them into a usable state, so we
+                    // treat it as fatal error.
+                    if (isLayered() && !autoClose) {
+                        // Note that the alert description is
+                        // specified as -1, so no message will be send
+                        // to peer anymore.
+                        fatal((byte)(-1), ssle);
+                    } else if ((debug != null) && Debug.isOn("ssl")) {
+                        System.out.println(
+                            Thread.currentThread().getName() +
+                            ", received Exception: " + ssle);
+                    }
+
+                    // RFC2246 requires that the session becomes
+                    // unresumable if any connection is terminated
+                    // without proper close_notify messages with
+                    // level equal to warning.
+                    //
+                    // RFC4346 no longer requires that a session not be
+                    // resumed if failure to properly close a connection.
+                    //
+                    // We choose to make the session unresumable if
+                    // failed to send the close_notify message.
+                    //
+                    sess.invalidate();
+                }
+            } catch (InterruptedException ie) {
+                // keep interrupted status
+                interrupted = true;
+            }
+
+            // restore the interrupted status
+            if (interrupted) {
+                Thread.currentThread().interrupt();
+            }
+        } else {
+            writeLock.lock();
+            try {
+                outputRecord.encodeAlert(level, description);
+            } finally {
+                writeLock.unlock();
+            }
+        }
+
+        // Don't bother to check sequence number overlap here.  If sequence
+        // number is huge, there should be enough sequence number space to
+        // request renegotiation in next application data read and write.
+    }
+
+
+    int bytesInCompletePacket() throws IOException {
+        if (getConnectionState() == cs_HANDSHAKE) {
+            performInitialHandshake();
+        }
+
+        synchronized (readLock) {
+            int state = getConnectionState();
+            if ((state == cs_CLOSED) ||
+                    (state == cs_ERROR) || (state == cs_APP_CLOSED)) {
+                return -1;
+            }
+
+            try {
+                return inputRecord.bytesInCompletePacket(sockInput);
+            } catch (EOFException eofe) {
+                boolean handshaking = (connectionState <= cs_HANDSHAKE);
+                boolean rethrow = requireCloseNotify || handshaking;
+                if ((debug != null) && Debug.isOn("ssl")) {
+                    System.out.println(Thread.currentThread().getName() +
+                        ", received EOFException: "
+                        + (rethrow ? "error" : "ignored"));
+                }
+
+                if (!rethrow) {
+                    // treat as if we had received a close_notify
+                    closeInternal(false);
+                } else {
+                    SSLException e;
+                    if (handshaking) {
+                        e = new SSLHandshakeException(
+                            "Remote host terminated the handshake");
+                    } else {
+                        e = new SSLProtocolException(
+                            "Remote host terminated the handshake");
+                    }
+                    e.initCause(eofe);
+                    throw e;
+                }
+            }
+
+            return -1;
         }
     }
 
+    // the caller have synchronized readLock
+    void expectingFinishFlight() {
+        inputRecord.expectingFinishFlight();
+    }
+
     /*
-     * Read an application data record.  Alerts and handshake
-     * messages are handled directly.
+     * Read an application data record.
+     *
+     * Alerts and handshake messages are internally handled directly.
      */
-    void readDataRecord(InputRecord r) throws IOException {
+    int readRecord(ByteBuffer buffer) throws IOException {
         if (getConnectionState() == cs_HANDSHAKE) {
             performInitialHandshake();
         }
-        readRecord(r, true);
+
+        return readRecord(buffer, true);
     }
 
+    /*
+     * Read a record, no application data input required.
+     *
+     * Alerts and handshake messages are internally handled directly.
+     */
+    int readRecord(boolean needAppData) throws IOException {
+        return readRecord(null, needAppData);
+    }
 
     /*
      * Clear the pipeline of records from the peer, optionally returning
@@ -929,11 +946,11 @@
      * Don't synchronize (this) during a blocking read() since it
      * protects data which is accessed on the write side as well.
      */
-    private void readRecord(InputRecord r, boolean needAppData)
+    private int readRecord(ByteBuffer buffer, boolean needAppData)
             throws IOException {
         int state;
 
-        // readLock protects reading and processing of an InputRecord.
+        // readLock protects reading and processing of an SSLInputRecord.
         // It keeps the reading from sockInput and processing of the record
         // atomic so that no two threads can be blocked on the
         // read from the same input stream at the same time.
@@ -944,306 +961,282 @@
         //
         // Use readLock instead of 'this' for locking because
         // 'this' also protects data accessed during writing.
-      synchronized (readLock) {
-        /*
-         * Read and handle records ... return application data
-         * ONLY if it's needed.
-         */
-
-        while (((state = getConnectionState()) != cs_CLOSED) &&
-                (state != cs_ERROR) && (state != cs_APP_CLOSED)) {
+        synchronized (readLock) {
             /*
-             * Read a record ... maybe emitting an alert if we get a
-             * comprehensible but unsupported "hello" message during
-             * format checking (e.g. V2).
-             */
-            try {
-                r.setAppDataValid(false);
-                r.read(sockInput, sockOutput);
-            } catch (SSLProtocolException e) {
-                try {
-                    fatal(Alerts.alert_unexpected_message, e);
-                } catch (IOException x) {
-                    // discard this exception
-                }
-                throw e;
-            } catch (EOFException eof) {
-                boolean handshaking = (getConnectionState() <= cs_HANDSHAKE);
-                boolean rethrow = requireCloseNotify || handshaking;
-                if ((debug != null) && Debug.isOn("ssl")) {
-                    System.out.println(Thread.currentThread().getName() +
-                        ", received EOFException: "
-                        + (rethrow ? "error" : "ignored"));
-                }
-                if (rethrow) {
-                    SSLException e;
-                    if (handshaking) {
-                        e = new SSLHandshakeException
-                            ("Remote host closed connection during handshake");
-                    } else {
-                        e = new SSLProtocolException
-                            ("Remote host closed connection incorrectly");
-                    }
-                    e.initCause(eof);
-                    throw e;
-                } else {
-                    // treat as if we had received a close_notify
-                    closeInternal(false);
-                    continue;
-                }
-            }
-
-
-            /*
-             * The basic SSLv3 record protection involves (optional)
-             * encryption for privacy, and an integrity check ensuring
-             * data origin authentication.  We do them both here, and
-             * throw a fatal alert if the integrity check fails.
-             */
-            try {
-                r.decrypt(readAuthenticator, readCipher);
-            } catch (BadPaddingException e) {
-                byte alertType = (r.contentType() == Record.ct_handshake)
-                                        ? Alerts.alert_handshake_failure
-                                        : Alerts.alert_bad_record_mac;
-                fatal(alertType, e.getMessage(), e);
-            }
-
-            // if (!r.decompress(c))
-            //     fatal(Alerts.alert_decompression_failure,
-            //         "decompression failure");
-
-            /*
-             * Process the record.
+             * Read and handle records ... return application data
+             * ONLY if it's needed.
              */
-            synchronized (this) {
-              switch (r.contentType()) {
-                case Record.ct_handshake:
-                    /*
-                     * Handshake messages always go to a pending session
-                     * handshaker ... if there isn't one, create one.  This
-                     * must work asynchronously, for renegotiation.
-                     *
-                     * NOTE that handshaking will either resume a session
-                     * which was in the cache (and which might have other
-                     * connections in it already), or else will start a new
-                     * session (new keys exchanged) with just this connection
-                     * in it.
-                     */
-                    initHandshaker();
-                    if (!handshaker.activated()) {
-                        // prior to handshaking, activate the handshake
-                        if (connectionState == cs_RENEGOTIATE) {
-                            // don't use SSLv2Hello when renegotiating
-                            handshaker.activate(protocolVersion);
-                        } else {
-                            handshaker.activate(null);
-                        }
-                    }
-
-                    /*
-                     * process the handshake record ... may contain just
-                     * a partial handshake message or multiple messages.
-                     *
-                     * The handshaker state machine will ensure that it's
-                     * a finished message.
-                     */
-                    handshaker.process_record(r, expectingFinished);
-                    expectingFinished = false;
+            Plaintext plainText = null;
+            while (((state = getConnectionState()) != cs_CLOSED) &&
+                    (state != cs_ERROR) && (state != cs_APP_CLOSED)) {
+                // clean the buffer
+                if (buffer != null) {
+                    buffer.clear();
+                }
 
-                    if (handshaker.invalidated) {
-                        handshaker = null;
-                        receivedCCS = false;
-                        // if state is cs_RENEGOTIATE, revert it to cs_DATA
-                        if (connectionState == cs_RENEGOTIATE) {
-                            connectionState = cs_DATA;
+                /*
+                 * Read a record ... maybe emitting an alert if we get a
+                 * comprehensible but unsupported "hello" message during
+                 * format checking (e.g. V2).
+                 */
+                try {
+                    plainText = inputRecord.decode(sockInput, buffer);
+                } catch (BadPaddingException bpe) {
+                    byte alertType = (state != cs_DATA) ?
+                            Alerts.alert_handshake_failure :
+                            Alerts.alert_bad_record_mac;
+                    fatal(alertType, bpe.getMessage(), bpe);
+                } catch (SSLProtocolException spe) {
+                    try {
+                        fatal(Alerts.alert_unexpected_message, spe);
+                    } catch (IOException x) {
+                        // discard this exception, throw the original exception
+                    }
+                    throw spe;
+                } catch (SSLHandshakeException she) {
+                    // may be record sequence number overflow
+                    fatal(Alerts.alert_handshake_failure, she);
+                } catch (EOFException eof) {
+                    boolean handshaking = (connectionState <= cs_HANDSHAKE);
+                    boolean rethrow = requireCloseNotify || handshaking;
+                    if ((debug != null) && Debug.isOn("ssl")) {
+                        System.out.println(Thread.currentThread().getName() +
+                            ", received EOFException: "
+                            + (rethrow ? "error" : "ignored"));
+                    }
+                    if (rethrow) {
+                        SSLException e;
+                        if (handshaking) {
+                            e = new SSLHandshakeException(
+                                    "Remote host terminated the handshake");
+                        } else {
+                            e = new SSLProtocolException(
+                                    "Remote host terminated the connection");
                         }
-                    } else if (handshaker.isDone()) {
-                        // reset the parameters for secure renegotiation.
-                        secureRenegotiation =
-                                        handshaker.isSecureRenegotiation();
-                        clientVerifyData = handshaker.getClientVerifyData();
-                        serverVerifyData = handshaker.getServerVerifyData();
-
-                        sess = handshaker.getSession();
-                        handshakeSession = null;
-                        handshaker = null;
-                        connectionState = cs_DATA;
-                        receivedCCS = false;
-
-                        //
-                        // Tell folk about handshake completion, but do
-                        // it in a separate thread.
-                        //
-                        if (handshakeListeners != null) {
-                            HandshakeCompletedEvent event =
-                                new HandshakeCompletedEvent(this, sess);
-
-                            Thread t = new ManagedLocalsThread(
-                                new NotifyHandshake(
-                                    handshakeListeners.entrySet(), event),
-                                "HandshakeCompletedNotify-Thread");
-                            t.start();
-                        }
-                    }
-
-                    if (needAppData || connectionState != cs_DATA) {
+                        e.initCause(eof);
+                        throw e;
+                    } else {
+                        // treat as if we had received a close_notify
+                        closeInternal(false);
                         continue;
                     }
-                    break;
+                }
+
+                // PlainText should never be null. Process input record.
+                int volume = processInputRecord(plainText, needAppData);
+
+                if (plainText.contentType == Record.ct_application_data) {
+                    return volume;
+                }
+
+                if (plainText.contentType == Record.ct_handshake) {
+                    if (!needAppData && connectionState == cs_DATA) {
+                        return volume;
+                    }   // otherwise, need to read more for app data.
+                }
 
-                case Record.ct_application_data:
-                    // Pass this right back up to the application.
-                    if (connectionState != cs_DATA
-                            && connectionState != cs_RENEGOTIATE
-                            && connectionState != cs_SENT_CLOSE) {
-                        throw new SSLProtocolException(
-                            "Data received in non-data state: " +
-                            connectionState);
-                    }
-                    if (expectingFinished) {
-                        throw new SSLProtocolException
-                                ("Expecting finished message, received data");
-                    }
-                    if (!needAppData) {
-                        throw new SSLException("Discarding app data");
-                    }
+                // continue to read more net data
+            }   // while
 
-                    r.setAppDataValid(true);
-                    break;
+            //
+            // couldn't read, due to some kind of error
+            //
+            return -1;
+        }  // readLock synchronization
+    }
+
+    /*
+     * Process the plainText input record.
+     */
+    private synchronized int processInputRecord(
+            Plaintext plainText, boolean needAppData) throws IOException {
 
-                case Record.ct_alert:
-                    recvAlert(r);
-                    continue;
+        /*
+         * Process the record.
+         */
+        int volume = 0;    // no application data
+        switch (plainText.contentType) {
+            case Record.ct_handshake:
+                /*
+                 * Handshake messages always go to a pending session
+                 * handshaker ... if there isn't one, create one.  This
+                 * must work asynchronously, for renegotiation.
+                 *
+                 * NOTE that handshaking will either resume a session
+                 * which was in the cache (and which might have other
+                 * connections in it already), or else will start a new
+                 * session (new keys exchanged) with just this connection
+                 * in it.
+                 */
+                initHandshaker();
+                if (!handshaker.activated()) {
+                    // prior to handshaking, activate the handshake
+                    if (connectionState == cs_RENEGOTIATE) {
+                        // don't use SSLv2Hello when renegotiating
+                        handshaker.activate(protocolVersion);
+                    } else {
+                        handshaker.activate(null);
+                    }
+                }
 
-                case Record.ct_change_cipher_spec:
-                    if ((connectionState != cs_HANDSHAKE
-                                && connectionState != cs_RENEGOTIATE)
-                            || !handshaker.sessionKeysCalculated()
-                            || receivedCCS) {
-                        // For the CCS message arriving in the wrong state
-                        fatal(Alerts.alert_unexpected_message,
-                                "illegal change cipher spec msg, conn state = "
-                                + connectionState + ", handshake state = "
-                                + handshaker.state);
-                    } else if (r.available() != 1 || r.read() != 1) {
-                        // For structural/content issues with the CCS
-                        fatal(Alerts.alert_unexpected_message,
-                                "Malformed change cipher spec msg");
+                /*
+                 * process the handshake record ... may contain just
+                 * a partial handshake message or multiple messages.
+                 *
+                 * The handshaker state machine will ensure that it's
+                 * a finished message.
+                 */
+                handshaker.processRecord(plainText.fragment, expectingFinished);
+                expectingFinished = false;
+
+                if (handshaker.invalidated) {
+                    handshaker = null;
+                    inputRecord.setHandshakeHash(null);
+                    outputRecord.setHandshakeHash(null);
+
+                    // if state is cs_RENEGOTIATE, revert it to cs_DATA
+                    if (connectionState == cs_RENEGOTIATE) {
+                        connectionState = cs_DATA;
                     }
+                } else if (handshaker.isDone()) {
+                    // reset the parameters for secure renegotiation.
+                    secureRenegotiation =
+                                    handshaker.isSecureRenegotiation();
+                    clientVerifyData = handshaker.getClientVerifyData();
+                    serverVerifyData = handshaker.getServerVerifyData();
 
-                    // Once we've received CCS, update the flag.
-                    // If the remote endpoint sends it again in this handshake
-                    // we won't process it.
-                    receivedCCS = true;
+                    sess = handshaker.getSession();
+                    handshakeSession = null;
+                    handshaker = null;
+                    inputRecord.setHandshakeHash(null);
+                    outputRecord.setHandshakeHash(null);
+                    connectionState = cs_DATA;
 
                     //
-                    // The first message after a change_cipher_spec
-                    // record MUST be a "Finished" handshake record,
-                    // else it's a protocol violation.  We force this
-                    // to be checked by a minor tweak to the state
-                    // machine.
+                    // Tell folk about handshake completion, but do
+                    // it in a separate thread.
                     //
-                    changeReadCiphers();
-                    // next message MUST be a finished message
-                    expectingFinished = true;
-                    continue;
+                    if (handshakeListeners != null) {
+                        HandshakeCompletedEvent event =
+                            new HandshakeCompletedEvent(this, sess);
+
+                        Thread thread = new ManagedLocalsThread(
+                            new NotifyHandshake(
+                                handshakeListeners.entrySet(), event),
+                            "HandshakeCompletedNotify-Thread");
+                        thread.start();
+                    }
+                }
+
+                break;
 
-                default:
-                    //
-                    // TLS requires that unrecognized records be ignored.
-                    //
-                    if (debug != null && Debug.isOn("ssl")) {
-                        System.out.println(Thread.currentThread().getName() +
-                            ", Received record type: "
-                            + r.contentType());
-                    }
-                    continue;
-              } // switch
+            case Record.ct_application_data:
+                if (connectionState != cs_DATA
+                        && connectionState != cs_RENEGOTIATE
+                        && connectionState != cs_SENT_CLOSE) {
+                    throw new SSLProtocolException(
+                        "Data received in non-data state: " +
+                        connectionState);
+                }
+                if (expectingFinished) {
+                    throw new SSLProtocolException
+                            ("Expecting finished message, received data");
+                }
+                if (!needAppData) {
+                    throw new SSLException("Discarding app data");
+                }
+
+                volume = plainText.fragment.remaining();
+                break;
+
+            case Record.ct_alert:
+                recvAlert(plainText.fragment);
+                break;
 
-              /*
-               * Check the sequence number state
-               *
-               * Note that in order to maintain the connection I/O
-               * properly, we check the sequence number after the last
-               * record reading process. As we request renegotiation
-               * or close the connection for wrapped sequence number
-               * when there is enough sequence number space left to
-               * handle a few more records, so the sequence number
-               * of the last record cannot be wrapped.
-               */
-              if (connectionState < cs_ERROR) {
-                  checkSequenceNumber(readAuthenticator, r.contentType());
-              }
+            case Record.ct_change_cipher_spec:
+                if ((connectionState != cs_HANDSHAKE
+                        && connectionState != cs_RENEGOTIATE)) {
+                    // For the CCS message arriving in the wrong state
+                    fatal(Alerts.alert_unexpected_message,
+                            "illegal change cipher spec msg, conn state = "
+                            + connectionState);
+                } else if (plainText.fragment.remaining() != 1
+                        || plainText.fragment.get() != 1) {
+                    // For structural/content issues with the CCS
+                    fatal(Alerts.alert_unexpected_message,
+                            "Malformed change cipher spec msg");
+                }
 
-              return;
-            } // synchronized (this)
-        }
+                //
+                // The first message after a change_cipher_spec
+                // record MUST be a "Finished" handshake record,
+                // else it's a protocol violation.  We force this
+                // to be checked by a minor tweak to the state
+                // machine.
+                //
+                handshaker.receiveChangeCipherSpec();
 
-        //
-        // couldn't read, due to some kind of error
-        //
-        r.close();
-        return;
-      }  // synchronized (readLock)
-    }
+                CipherBox readCipher;
+                Authenticator readAuthenticator;
+                try {
+                    readCipher = handshaker.newReadCipher();
+                    readAuthenticator = handshaker.newReadAuthenticator();
+                } catch (GeneralSecurityException e) {
+                    // can't happen
+                    throw new SSLException("Algorithm missing:  ", e);
+                }
+                inputRecord.changeReadCiphers(readAuthenticator, readCipher);
 
-    /**
-     * Check the sequence number state
-     *
-     * RFC 4346 states that, "Sequence numbers are of type uint64 and
-     * may not exceed 2^64-1.  Sequence numbers do not wrap. If a TLS
-     * implementation would need to wrap a sequence number, it must
-     * renegotiate instead."
-     */
-    private void checkSequenceNumber(Authenticator authenticator, byte type)
-            throws IOException {
+                // next message MUST be a finished message
+                expectingFinished = true;
+
+                break;
 
-        /*
-         * Don't bother to check the sequence number for error or
-         * closed connections, or NULL MAC.
-         */
-        if (connectionState >= cs_ERROR || authenticator == MAC.NULL) {
-            return;
+            default:
+                //
+                // TLS requires that unrecognized records be ignored.
+                //
+                if (debug != null && Debug.isOn("ssl")) {
+                    System.out.println(Thread.currentThread().getName() +
+                        ", Received record type: " + plainText.contentType);
+                }
+                break;
         }
 
         /*
-         * Conservatively, close the connection immediately when the
-         * sequence number is close to overflow
+         * Check the sequence number state
+         *
+         * Note that in order to maintain the connection I/O
+         * properly, we check the sequence number after the last
+         * record reading process. As we request renegotiation
+         * or close the connection for wrapped sequence number
+         * when there is enough sequence number space left to
+         * handle a few more records, so the sequence number
+         * of the last record cannot be wrapped.
+         *
+         * Don't bother to kickstart the renegotiation when the
+         * local is asking for it.
          */
-        if (authenticator.seqNumOverflow()) {
+        if ((connectionState == cs_DATA) && inputRecord.seqNumIsHuge()) {
             /*
-             * TLS protocols do not define a error alert for sequence
-             * number overflow. We use handshake_failure error alert
-             * for handshaking and bad_record_mac for other records.
+             * Ask for renegotiation when need to renew sequence number.
+             *
+             * Don't bother to kickstart the renegotiation when the local is
+             * asking for it.
              */
             if (debug != null && Debug.isOn("ssl")) {
                 System.out.println(Thread.currentThread().getName() +
-                    ", sequence number extremely close to overflow " +
-                    "(2^64-1 packets). Closing connection.");
-
-            }
-
-            fatal(Alerts.alert_handshake_failure, "sequence number overflow");
-        }
-
-        /*
-         * Ask for renegotiation when need to renew sequence number.
-         *
-         * Don't bother to kickstart the renegotiation when the local is
-         * asking for it.
-         */
-        if ((type != Record.ct_handshake) && authenticator.seqNumIsHuge()) {
-            if (debug != null && Debug.isOn("ssl")) {
-                System.out.println(Thread.currentThread().getName() +
                         ", request renegotiation " +
                         "to avoid sequence number overflow");
             }
 
             startHandshake();
         }
+
+        return volume;
     }
 
+
     //
     // HANDSHAKE RELATED CODE
     //
@@ -1323,6 +1316,7 @@
                     secureRenegotiation, clientVerifyData, serverVerifyData);
             handshaker.setSNIServerNames(serverNames);
         }
+        handshaker.setMaximumPacketSize(maximumPacketSize);
         handshaker.setEnabledCipherSuites(enabledCipherSuites);
         handshaker.setEnableSessionCreation(enableSessionCreation);
     }
@@ -1342,29 +1336,12 @@
                 kickstartHandshake();
 
                 /*
-                 * All initial handshaking goes through this
-                 * InputRecord until we have a valid SSL connection.
-                 * Once initial handshaking is finished, AppInputStream's
-                 * InputRecord can handle any future renegotiation.
+                 * All initial handshaking goes through this operation
+                 * until we have a valid SSL connection.
                  *
-                 * Keep this local so that it goes out of scope and is
-                 * eventually GC'd.
+                 * Handle handshake messages only, need no application data.
                  */
-                if (inrec == null) {
-                    inrec = new InputRecord();
-
-                    /*
-                     * Grab the characteristics already assigned to
-                     * AppInputStream's InputRecord.  Enable checking for
-                     * SSLv2 hellos on this first handshake.
-                     */
-                    inrec.setHandshakeHash(input.r.getHandshakeHash());
-                    inrec.setHelloVersion(input.r.getHelloVersion());
-                    inrec.enableFormatChecks();
-                }
-
-                readRecord(inrec, false);
-                inrec = null;
+                readRecord(false);
             }
         }
     }
@@ -1482,9 +1459,6 @@
                 } else {
                     // we want to renegotiate, send hello request
                     handshaker.kickstart();
-                    // hello request is not included in the handshake
-                    // hashes, reset them
-                    handshaker.handshakeHash.reset();
                 }
             }
         }
@@ -1547,7 +1521,7 @@
         }
     }
 
-    protected void closeSocket() throws IOException {
+    private void closeSocket() throws IOException {
 
         if ((debug != null) && Debug.isOn("ssl")) {
             System.out.println(Thread.currentThread().getName() +
@@ -1591,6 +1565,23 @@
                                                     ", called close()");
         }
         closeInternal(true);  // caller is initiating close
+
+        // Clearup the resources.
+        try {
+            synchronized (readLock) {
+                inputRecord.close();
+            }
+
+            writeLock.lock();
+            try {
+                outputRecord.close();
+            } finally {
+                writeLock.unlock();
+            }
+        } catch (IOException ioe) {
+           // ignore
+        }
+
         setConnectionState(cs_APP_CLOSED);
     }
 
@@ -1714,19 +1705,17 @@
                 // notify any threads waiting for the closing to finish
                 this.notifyAll();
             }
-            if (closeSocketCalled) {
-                // Dispose of ciphers since we've closed socket
-                disposeCiphers();
-            }
+
             if (cachedThrowable != null) {
                /*
                 * Rethrow the error to the calling method
                 * The Throwable caught can only be an Error or RuntimeException
                 */
-                if (cachedThrowable instanceof Error)
-                    throw (Error) cachedThrowable;
-                if (cachedThrowable instanceof RuntimeException)
-                    throw (RuntimeException) cachedThrowable;
+                if (cachedThrowable instanceof Error) {
+                    throw (Error)cachedThrowable;
+                } else if (cachedThrowable instanceof RuntimeException) {
+                    throw (RuntimeException)cachedThrowable;
+                }   // Otherwise, unlikely
             }
         }
     }
@@ -1750,19 +1739,14 @@
 
             while (((state = getConnectionState()) != cs_CLOSED) &&
                    (state != cs_ERROR) && (state != cs_APP_CLOSED)) {
-                // create the InputRecord if it isn't initialized.
-                if (inrec == null) {
-                    inrec = new InputRecord();
-                }
 
                 // Ask for app data and then throw it away
                 try {
-                    readRecord(inrec, true);
+                    readRecord(true);
                 } catch (SocketTimeoutException e) {
                     // if time out, ignore the exception and continue
                 }
             }
-            inrec = null;
         } catch (IOException e) {
             if (debug != null && Debug.isOn("ssl")) {
                 System.out.println(Thread.currentThread().getName() +
@@ -1774,24 +1758,6 @@
         }
     }
 
-    /**
-     * Called by closeInternal() only. Be sure to consider the
-     * synchronization locks carefully before calling it elsewhere.
-     */
-    private void disposeCiphers() {
-        // See comment in changeReadCiphers()
-        synchronized (readLock) {
-            readCipher.dispose();
-        }
-        // See comment in changeReadCiphers()
-        writeLock.lock();
-        try {
-            writeCipher.dispose();
-        } finally {
-            writeLock.unlock();
-        }
-    }
-
     //
     // EXCEPTION AND ALERT HANDLING
     //
@@ -1853,7 +1819,7 @@
 
         // need to perform error shutdown
         boolean isSSLException = (e instanceof SSLException);
-        if ((isSSLException == false) && (e instanceof IOException)) {
+        if ((!isSSLException) && (e instanceof IOException)) {
             // IOException from the socket
             // this means the TCP connection is already dead
             // we call fatal just to set the error status
@@ -1903,9 +1869,14 @@
      */
     synchronized void fatal(byte description, String diagnostic,
             Throwable cause) throws IOException {
-        if ((input != null) && (input.r != null)) {
-            input.r.close();
+
+        // Be care of deadlock. Please don't synchronize readLock.
+        try {
+            inputRecord.close();
+        } catch (IOException ioe) {
+            // ignore
         }
+
         sess.invalidate();
         if (handshakeSession != null) {
             handshakeSession.invalidate();
@@ -1945,15 +1916,12 @@
          * Clean up our side.
          */
         closeSocket();
-        // Another thread may have disposed the ciphers during closing
-        if (connectionState < cs_CLOSED) {
-            connectionState = (oldState == cs_APP_CLOSED) ? cs_APP_CLOSED
-                                                              : cs_CLOSED;
 
-            // We should lock readLock and writeLock if no deadlock risks.
-            // See comment in changeReadCiphers()
-            readCipher.dispose();
-            writeCipher.dispose();
+        // Be care of deadlock. Please don't synchronize writeLock.
+        try {
+            outputRecord.close();
+        } catch (IOException ioe) {
+            // ignore
         }
 
         throw closeReason;
@@ -1964,9 +1932,10 @@
      * Process an incoming alert ... caller must already have synchronized
      * access to "this".
      */
-    private void recvAlert(InputRecord r) throws IOException {
-        byte level = (byte)r.read();
-        byte description = (byte)r.read();
+    private void recvAlert(ByteBuffer fragment) throws IOException {
+        byte level = fragment.get();
+        byte description = fragment.get();
+
         if (description == -1) { // check for short message
             fatal(Alerts.alert_illegal_parameter, "Short alert message");
         }
@@ -2029,14 +1998,14 @@
 
         // For initial handshaking, don't send alert message to peer if
         // handshaker has not started.
-        if (connectionState == cs_HANDSHAKE &&
-            (handshaker == null || !handshaker.started())) {
+        //
+        // Shall we send an fatal alter to terminate the connection gracefully?
+        if (connectionState <= cs_HANDSHAKE &&
+                (handshaker == null || !handshaker.started() ||
+                        !handshaker.activated())) {
             return;
         }
 
-        OutputRecord r = new OutputRecord(Record.ct_alert);
-        r.setVersion(protocolVersion);
-
         boolean useDebug = debug != null && Debug.isOn("ssl");
         if (useDebug) {
             synchronized (System.out) {
@@ -2054,10 +2023,8 @@
             }
         }
 
-        r.write(level);
-        r.write(description);
         try {
-            writeRecord(r);
+            writeAlert(level, description);
         } catch (IOException e) {
             if (useDebug) {
                 System.out.println(Thread.currentThread().getName() +
@@ -2070,61 +2037,10 @@
     // VARIOUS OTHER METHODS
     //
 
-    /*
-     * When a connection finishes handshaking by enabling use of a newly
-     * negotiated session, each end learns about it in two halves (read,
-     * and write).  When both read and write ciphers have changed, and the
-     * last handshake message has been read, the connection has joined
-     * (rejoined) the new session.
-     *
-     * NOTE:  The SSLv3 spec is rather unclear on the concepts here.
-     * Sessions don't change once they're established (including cipher
-     * suite and master secret) but connections can join them (and leave
-     * them).  They're created by handshaking, though sometime handshaking
-     * causes connections to join up with pre-established sessions.
-     */
-    private void changeReadCiphers() throws SSLException {
-        if (connectionState != cs_HANDSHAKE
-                && connectionState != cs_RENEGOTIATE) {
-            throw new SSLProtocolException(
-                "State error, change cipher specs");
-        }
-
-        // ... create decompressor
-
-        CipherBox oldCipher = readCipher;
-
-        try {
-            readCipher = handshaker.newReadCipher();
-            readAuthenticator = handshaker.newReadAuthenticator();
-        } catch (GeneralSecurityException e) {
-            // "can't happen"
-            throw new SSLException("Algorithm missing:  ", e);
-        }
-
-        /*
-         * Dispose of any intermediate state in the underlying cipher.
-         * For PKCS11 ciphers, this will release any attached sessions,
-         * and thus make finalization faster.
-         *
-         * Since MAC's doFinal() is called for every SSL/TLS packet, it's
-         * not necessary to do the same with MAC's.
-         */
-        oldCipher.dispose();
-    }
-
     // used by Handshaker
-    void changeWriteCiphers() throws SSLException {
-        if (connectionState != cs_HANDSHAKE
-                && connectionState != cs_RENEGOTIATE) {
-            throw new SSLProtocolException(
-                "State error, change cipher specs");
-        }
-
-        // ... create compressor
-
-        CipherBox oldCipher = writeCipher;
-
+    void changeWriteCiphers() throws IOException {
+        Authenticator writeAuthenticator;
+        CipherBox writeCipher;
         try {
             writeCipher = handshaker.newWriteCipher();
             writeAuthenticator = handshaker.newWriteAuthenticator();
@@ -2132,12 +2048,7 @@
             // "can't happen"
             throw new SSLException("Algorithm missing:  ", e);
         }
-
-        // See comment above.
-        oldCipher.dispose();
-
-        // reset the flag of the first application record
-        isFirstAppOutputRecord = true;
+        outputRecord.changeWriteCiphers(writeAuthenticator, writeCipher);
     }
 
     /*
@@ -2146,7 +2057,7 @@
      */
     synchronized void setVersion(ProtocolVersion protocolVersion) {
         this.protocolVersion = protocolVersion;
-        output.r.setVersion(protocolVersion);
+        outputRecord.setVersion(protocolVersion);
     }
 
     synchronized String getHost() {
@@ -2245,6 +2156,10 @@
     }
 
     synchronized void setHandshakeSession(SSLSessionImpl session) {
+        // update the fragment size, which may be negotiated during handshaking
+        inputRecord.changeFragmentSize(session.getNegotiatedMaxFragSize());
+        outputRecord.changeFragmentSize(session.getNegotiatedMaxFragSize());
+
         handshakeSession = session;
     }
 
@@ -2285,8 +2200,8 @@
      */
     @Override
     synchronized public void setNeedClientAuth(boolean flag) {
-        doClientAuth = (flag ?
-            SSLEngineImpl.clauth_required : SSLEngineImpl.clauth_none);
+        doClientAuth = (flag ? ClientAuthType.CLIENT_AUTH_REQUIRED :
+                ClientAuthType.CLIENT_AUTH_NONE);
 
         if ((handshaker != null) &&
                 (handshaker instanceof ServerHandshaker) &&
@@ -2297,7 +2212,7 @@
 
     @Override
     synchronized public boolean getNeedClientAuth() {
-        return (doClientAuth == SSLEngineImpl.clauth_required);
+        return (doClientAuth == ClientAuthType.CLIENT_AUTH_REQUIRED);
     }
 
     /**
@@ -2310,8 +2225,8 @@
      */
     @Override
     synchronized public void setWantClientAuth(boolean flag) {
-        doClientAuth = (flag ?
-            SSLEngineImpl.clauth_requested : SSLEngineImpl.clauth_none);
+        doClientAuth = (flag ? ClientAuthType.CLIENT_AUTH_REQUESTED :
+                ClientAuthType.CLIENT_AUTH_NONE);
 
         if ((handshaker != null) &&
                 (handshaker instanceof ServerHandshaker) &&
@@ -2322,7 +2237,7 @@
 
     @Override
     synchronized public boolean getWantClientAuth() {
-        return (doClientAuth == SSLEngineImpl.clauth_requested);
+        return (doClientAuth == ClientAuthType.CLIENT_AUTH_REQUESTED);
     }
 
 
@@ -2339,13 +2254,22 @@
         case cs_START:
             /*
              * If we need to change the socket mode and the enabled
-             * protocols haven't specifically been set by the user,
-             * change them to the corresponding default ones.
+             * protocols and cipher suites haven't specifically been
+             * set by the user, change them to the corresponding
+             * default ones.
              */
-            if (roleIsServer != (!flag) &&
-                    sslContext.isDefaultProtocolList(enabledProtocols)) {
-                enabledProtocols = sslContext.getDefaultProtocolList(!flag);
+            if (roleIsServer != (!flag)) {
+                if (sslContext.isDefaultProtocolList(enabledProtocols)) {
+                    enabledProtocols =
+                            sslContext.getDefaultProtocolList(!flag);
+                }
+
+                if (sslContext.isDefaultCipherSuiteList(enabledCipherSuites)) {
+                    enabledCipherSuites =
+                            sslContext.getDefaultCipherSuiteList(!flag);
+                }
             }
+
             roleIsServer = !flag;
             break;
 
@@ -2361,13 +2285,23 @@
             if (!handshaker.activated()) {
                 /*
                  * If we need to change the socket mode and the enabled
-                 * protocols haven't specifically been set by the user,
-                 * change them to the corresponding default ones.
+                 * protocols and cipher suites haven't specifically been
+                 * set by the user, change them to the corresponding
+                 * default ones.
                  */
-                if (roleIsServer != (!flag) &&
-                        sslContext.isDefaultProtocolList(enabledProtocols)) {
-                    enabledProtocols = sslContext.getDefaultProtocolList(!flag);
+                if (roleIsServer != (!flag)) {
+                    if (sslContext.isDefaultProtocolList(enabledProtocols)) {
+                        enabledProtocols =
+                                sslContext.getDefaultProtocolList(!flag);
+                    }
+
+                    if (sslContext.isDefaultCipherSuiteList(
+                                                    enabledCipherSuites)) {
+                        enabledCipherSuites =
+                            sslContext.getDefaultCipherSuiteList(!flag);
+                    }
                 }
+
                 roleIsServer = !flag;
                 connectionState = cs_START;
                 initHandshaker();
@@ -2535,6 +2469,9 @@
         params.setSNIMatchers(sniMatchers);
         params.setServerNames(serverNames);
         params.setUseCipherSuitesOrder(preferLocalCipherSuites);
+        params.setMaximumPacketSize(maximumPacketSize);
+
+        // DTLS handshake retransmissions parameter does not apply here.
 
         return params;
     }
@@ -2550,6 +2487,16 @@
         identificationProtocol = params.getEndpointIdentificationAlgorithm();
         algorithmConstraints = params.getAlgorithmConstraints();
         preferLocalCipherSuites = params.getUseCipherSuitesOrder();
+        maximumPacketSize = params.getMaximumPacketSize();
+
+        // DTLS handshake retransmissions parameter does not apply here.
+
+        if (maximumPacketSize != 0) {
+            outputRecord.changePacketSize(maximumPacketSize);
+        } else {
+            // use the implicit maximum packet size.
+            maximumPacketSize = outputRecord.getMaxPacketSize();
+        }
 
         List<SNIServerName> sniNames = params.getServerNames();
         if (sniNames != null) {
@@ -2564,6 +2511,7 @@
         if ((handshaker != null) && !handshaker.started()) {
             handshaker.setIdentificationProtocol(identificationProtocol);
             handshaker.setAlgorithmConstraints(algorithmConstraints);
+            handshaker.setMaximumPacketSize(maximumPacketSize);
             if (roleIsServer) {
                 handshaker.setSNIMatchers(sniMatchers);
                 handshaker.setUseCipherSuitesOrder(preferLocalCipherSuites);
@@ -2612,14 +2560,6 @@
     }
 
     /**
-     * Returns a boolean indicating whether the ChangeCipherSpec message
-     * has been received for this handshake.
-     */
-    boolean receivedChangeCipherSpec() {
-        return receivedCCS;
-    }
-
-    /**
      * Returns a printable representation of this end of the connection.
      */
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,441 @@
+/*
+ * Copyright (c) 1996, 2014, 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.security.ssl;
+
+import java.io.*;
+import java.nio.*;
+
+import javax.crypto.BadPaddingException;
+
+import javax.net.ssl.*;
+
+import sun.misc.HexDumpEncoder;
+
+
+/**
+ * {@code InputRecord} implementation for {@code SSLSocket}.
+ *
+ * @author David Brownell
+ */
+final class SSLSocketInputRecord extends InputRecord implements SSLRecord {
+    private OutputStream deliverStream = null;
+    private byte[] temporary = new byte[1024];
+
+    // used by handshake hash computation for handshake fragment
+    private byte prevType = -1;
+    private int hsMsgOff = 0;
+    private int hsMsgLen = 0;
+
+    private boolean formatVerified = false;     // SSLv2 ruled out?
+
+    private boolean hasHeader = false;          // Had read the record header
+
+    SSLSocketInputRecord() {
+        this.readAuthenticator = MAC.TLS_NULL;
+    }
+
+    @Override
+    int bytesInCompletePacket(InputStream is) throws IOException {
+
+        if (!hasHeader) {
+            // read exactly one record
+            int really = read(is, temporary, 0, headerSize);
+            if (really < 0) {
+                throw new EOFException("SSL peer shut down incorrectly");
+            }
+            hasHeader = true;
+        }
+
+        byte byteZero = temporary[0];
+        int len = 0;
+
+        /*
+         * If we have already verified previous packets, we can
+         * ignore the verifications steps, and jump right to the
+         * determination.  Otherwise, try one last hueristic to
+         * see if it's SSL/TLS.
+         */
+        if (formatVerified ||
+                (byteZero == ct_handshake) || (byteZero == ct_alert)) {
+            /*
+             * Last sanity check that it's not a wild record
+             */
+            ProtocolVersion recordVersion =
+                    ProtocolVersion.valueOf(temporary[1], temporary[2]);
+
+            // check the record version
+            checkRecordVersion(recordVersion, false);
+
+            /*
+             * Reasonably sure this is a V3, disable further checks.
+             * We can't do the same in the v2 check below, because
+             * read still needs to parse/handle the v2 clientHello.
+             */
+            formatVerified = true;
+
+            /*
+             * One of the SSLv3/TLS message types.
+             */
+            len = ((temporary[3] & 0xFF) << 8) +
+                   (temporary[4] & 0xFF) + headerSize;
+        } else {
+            /*
+             * Must be SSLv2 or something unknown.
+             * Check if it's short (2 bytes) or
+             * long (3) header.
+             *
+             * Internals can warn about unsupported SSLv2
+             */
+            boolean isShort = ((byteZero & 0x80) != 0);
+
+            if (isShort && ((temporary[2] == 1) || (temporary[2] == 4))) {
+                ProtocolVersion recordVersion =
+                        ProtocolVersion.valueOf(temporary[3], temporary[4]);
+
+                // check the record version
+                checkRecordVersion(recordVersion, true);
+
+                /*
+                 * Client or Server Hello
+                 */
+                //
+                // Short header is using here.  We reverse the code here
+                // in case it it used in the future.
+                //
+                // int mask = (isShort ? 0x7F : 0x3F);
+                // len = ((byteZero & mask) << 8) +
+                //        (temporary[1] & 0xFF) + (isShort ? 2 : 3);
+                //
+                len = ((byteZero & 0x7F) << 8) + (temporary[1] & 0xFF) + 2;
+            } else {
+                // Gobblygook!
+                throw new SSLException(
+                        "Unrecognized SSL message, plaintext connection?");
+            }
+        }
+
+        return len;
+    }
+
+    // destination.position() is zero.
+    @Override
+    Plaintext decode(InputStream is, ByteBuffer destination)
+            throws IOException, BadPaddingException {
+
+        if (isClosed) {
+            return null;
+        }
+
+        if (!hasHeader) {
+            // read exactly one record
+            int really = read(is, temporary, 0, headerSize);
+            if (really < 0) {
+                throw new EOFException("SSL peer shut down incorrectly");
+            }
+            hasHeader = true;
+        }
+
+        Plaintext plaintext = null;
+        if (!formatVerified) {
+            formatVerified = true;
+
+            /*
+             * The first record must either be a handshake record or an
+             * alert message. If it's not, it is either invalid or an
+             * SSLv2 message.
+             */
+            if ((temporary[0] != ct_handshake) &&
+                (temporary[0] != ct_alert)) {
+
+                plaintext = handleUnknownRecord(is, temporary, destination);
+            }
+        }
+
+        if (plaintext == null) {
+            plaintext = decodeInputRecord(is, temporary, destination);
+        }
+
+        // The record header should has comsumed.
+        hasHeader = false;
+
+        return plaintext;
+    }
+
+    @Override
+    void setDeliverStream(OutputStream outputStream) {
+        this.deliverStream = outputStream;
+    }
+
+    // Note that destination may be null
+    private Plaintext decodeInputRecord(InputStream is, byte[] header,
+            ByteBuffer destination) throws IOException, BadPaddingException {
+
+        byte contentType = header[0];
+        byte majorVersion = header[1];
+        byte minorVersion = header[2];
+        int contentLen = ((header[3] & 0xFF) << 8) + (header[4] & 0xFF);
+
+        //
+        // Check for upper bound.
+        //
+        // Note: May check packetSize limit in the future.
+        if (contentLen < 0 || contentLen > maxLargeRecordSize - headerSize) {
+            throw new SSLProtocolException(
+                "Bad input record size, TLSCiphertext.length = " + contentLen);
+        }
+
+        //
+        // Read a complete record.
+        //
+        if (destination == null) {
+            destination = ByteBuffer.allocate(headerSize + contentLen);
+        }  // Otherwise, the destination buffer should have enough room.
+
+        int dstPos = destination.position();
+        destination.put(temporary, 0, headerSize);
+        while (contentLen > 0) {
+            int howmuch = Math.min(temporary.length, contentLen);
+            int really = read(is, temporary, 0, howmuch);
+            if (really < 0) {
+                throw new EOFException("SSL peer shut down incorrectly");
+            }
+
+            destination.put(temporary, 0, howmuch);
+            contentLen -= howmuch;
+        }
+        destination.flip();
+        destination.position(dstPos + headerSize);
+
+        if (debug != null && Debug.isOn("record")) {
+             System.out.println(Thread.currentThread().getName() +
+                    ", READ: " +
+                    ProtocolVersion.valueOf(majorVersion, minorVersion) +
+                    " " + Record.contentName(contentType) + ", length = " +
+                    destination.remaining());
+        }
+
+        //
+        // Decrypt the fragment
+        //
+        ByteBuffer plaintext =
+            decrypt(readAuthenticator, readCipher, contentType, destination);
+
+        if ((contentType != ct_handshake) && (hsMsgOff != hsMsgLen)) {
+            throw new SSLProtocolException(
+                    "Expected to get a handshake fragment");
+        }
+
+        //
+        // handshake hashing
+        //
+        if (contentType == ct_handshake) {
+            int pltPos = plaintext.position();
+            int pltLim = plaintext.limit();
+            int frgPos = pltPos;
+            for (int remains = plaintext.remaining(); remains > 0;) {
+                int howmuch;
+                byte handshakeType;
+                if (hsMsgOff < hsMsgLen) {
+                    // a fragment of the handshake message
+                    howmuch = Math.min((hsMsgLen - hsMsgOff), remains);
+                    handshakeType = prevType;
+
+                    hsMsgOff += howmuch;
+                    if (hsMsgOff == hsMsgLen) {
+                        // Now is a complete handshake message.
+                        hsMsgOff = 0;
+                        hsMsgLen = 0;
+                    }
+                } else {    // hsMsgOff == hsMsgLen, a new handshake message
+                    handshakeType = plaintext.get();
+                    int handshakeLen = ((plaintext.get() & 0xFF) << 16) |
+                                       ((plaintext.get() & 0xFF) << 8) |
+                                        (plaintext.get() & 0xFF);
+                    plaintext.position(frgPos);
+                    if (remains < (handshakeLen + 1)) { // 1: handshake type
+                        // This handshake message is fragmented.
+                        prevType = handshakeType;
+                        hsMsgOff = remains - 4;         // 4: handshake header
+                        hsMsgLen = handshakeLen;
+                    }
+
+                    howmuch = Math.min(handshakeLen + 4, remains);
+                }
+
+                plaintext.limit(frgPos + howmuch);
+
+                if (handshakeType == HandshakeMessage.ht_hello_request) {
+                    // omitted from handshake hash computation
+                } else if ((handshakeType != HandshakeMessage.ht_finished) &&
+                    (handshakeType != HandshakeMessage.ht_certificate_verify)) {
+
+                    if (handshakeHash == null) {
+                        // used for cache only
+                        handshakeHash = new HandshakeHash(false);
+                    }
+                    handshakeHash.update(plaintext);
+                } else {
+                    // Reserve until this handshake message has been processed.
+                    if (handshakeHash == null) {
+                        // used for cache only
+                        handshakeHash = new HandshakeHash(false);
+                    }
+                    handshakeHash.reserve(plaintext);
+                }
+
+                plaintext.position(frgPos + howmuch);
+                plaintext.limit(pltLim);
+
+                frgPos += howmuch;
+                remains -= howmuch;
+            }
+            plaintext.position(pltPos);
+        }
+
+        return new Plaintext(contentType,
+                majorVersion, minorVersion, -1, -1L, plaintext);
+                // recordEpoch, recordSeq, plaintext);
+    }
+
+    private Plaintext handleUnknownRecord(InputStream is, byte[] header,
+            ByteBuffer destination) throws IOException, BadPaddingException {
+
+        byte firstByte = header[0];
+        byte thirdByte = header[2];
+
+        // Does it look like a Version 2 client hello (V2ClientHello)?
+        if (((firstByte & 0x80) != 0) && (thirdByte == 1)) {
+            /*
+             * If SSLv2Hello is not enabled, throw an exception.
+             */
+            if (helloVersion != ProtocolVersion.SSL20Hello) {
+                throw new SSLHandshakeException("SSLv2Hello is not enabled");
+            }
+
+            byte majorVersion = header[3];
+            byte minorVersion = header[4];
+
+            if ((majorVersion == ProtocolVersion.SSL20Hello.major) &&
+                (minorVersion == ProtocolVersion.SSL20Hello.minor)) {
+
+                /*
+                 * Looks like a V2 client hello, but not one saying
+                 * "let's talk SSLv3".  So we need to send an SSLv2
+                 * error message, one that's treated as fatal by
+                 * clients (Otherwise we'll hang.)
+                 */
+                deliverStream.write(SSLRecord.v2NoCipher);      // SSLv2Hello
+
+                if (debug != null) {
+                    if (Debug.isOn("record")) {
+                         System.out.println(Thread.currentThread().getName() +
+                                "Requested to negotiate unsupported SSLv2!");
+                    }
+
+                    if (Debug.isOn("packet")) {
+                        Debug.printHex(
+                                "[Raw write]: length = " +
+                                SSLRecord.v2NoCipher.length,
+                                SSLRecord.v2NoCipher);
+                    }
+                }
+
+                throw new SSLException("Unsupported SSL v2.0 ClientHello");
+            }
+
+            int msgLen = ((header[0] & 0x7F) << 8) | (header[1] & 0xFF);
+
+            if (destination == null) {
+                destination = ByteBuffer.allocate(headerSize + msgLen);
+            }
+            destination.put(temporary, 0, headerSize);
+            msgLen -= 3;            // had read 3 bytes of content as header
+            while (msgLen > 0) {
+                int howmuch = Math.min(temporary.length, msgLen);
+                int really = read(is, temporary, 0, howmuch);
+                if (really < 0) {
+                    throw new EOFException("SSL peer shut down incorrectly");
+                }
+
+                destination.put(temporary, 0, howmuch);
+                msgLen -= howmuch;
+            }
+            destination.flip();
+
+            /*
+             * If we can map this into a V3 ClientHello, read and
+             * hash the rest of the V2 handshake, turn it into a
+             * V3 ClientHello message, and pass it up.
+             */
+            destination.position(2);     // exclude the header
+
+            if (handshakeHash == null) {
+                // used for cache only
+                handshakeHash = new HandshakeHash(false);
+            }
+            handshakeHash.update(destination);
+            destination.position(0);
+
+            ByteBuffer converted = convertToClientHello(destination);
+
+            if (debug != null && Debug.isOn("packet")) {
+                 Debug.printHex(
+                        "[Converted] ClientHello", converted);
+            }
+
+            return new Plaintext(ct_handshake,
+                majorVersion, minorVersion, -1, -1L, converted);
+        } else {
+            if (((firstByte & 0x80) != 0) && (thirdByte == 4)) {
+                throw new SSLException("SSL V2.0 servers are not supported.");
+            }
+
+            throw new SSLException("Unsupported or unrecognized SSL message");
+        }
+    }
+
+    // Read the exact bytes of data, otherwise, return -1.
+    private static int read(InputStream is,
+            byte[] buffer, int offset, int len) throws IOException {
+        int n = 0;
+        while (n < len) {
+            int readLen = is.read(buffer, offset + n, len - n);
+            if (readLen < 0) {
+                return -1;
+            }
+
+            if (debug != null && Debug.isOn("packet")) {
+                 Debug.printHex(
+                        "[Raw read]: length = " + readLen,
+                        buffer, offset + n, readLen);
+            }
+
+            n += readLen;
+        }
+
+        return n;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,383 @@
+/*
+ * 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
+ * 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.security.ssl;
+
+import java.io.*;
+import java.nio.*;
+import java.util.Arrays;
+
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLHandshakeException;
+import sun.misc.HexDumpEncoder;
+
+
+/**
+ * {@code OutputRecord} implementation for {@code SSLSocket}.
+ */
+final class SSLSocketOutputRecord extends OutputRecord implements SSLRecord {
+    private OutputStream deliverStream = null;
+
+    SSLSocketOutputRecord() {
+        this.writeAuthenticator = MAC.TLS_NULL;
+
+        this.packetSize = SSLRecord.maxRecordSize;
+        this.protocolVersion = ProtocolVersion.DEFAULT_TLS;
+    }
+
+    @Override
+    void encodeAlert(byte level, byte description) throws IOException {
+        // use the buf of ByteArrayOutputStream
+        int position = headerSize + writeCipher.getExplicitNonceSize();
+        count = position;
+
+        write(level);
+        write(description);
+
+        if (debug != null && Debug.isOn("record")) {
+            System.out.println(Thread.currentThread().getName() +
+                    ", WRITE: " + protocolVersion +
+                    " " + Record.contentName(Record.ct_alert) +
+                    ", length = " + (count - headerSize));
+        }
+
+        // Encrypt the fragment and wrap up a record.
+        encrypt(writeAuthenticator, writeCipher,
+                Record.ct_alert, headerSize);
+
+        // deliver this message
+        deliverStream.write(buf, 0, count);    // may throw IOException
+        deliverStream.flush();                 // may throw IOException
+
+        if (debug != null && Debug.isOn("packet")) {
+             Debug.printHex(
+                    "[Raw write]: length = " + count, buf, 0, count);
+        }
+
+        // reset the internal buffer
+        count = 0;
+    }
+
+    @Override
+    void encodeHandshake(byte[] source,
+            int offset, int length) throws IOException {
+
+        if (firstMessage) {
+            firstMessage = false;
+
+            if ((helloVersion == ProtocolVersion.SSL20Hello) &&
+                (source[offset] == HandshakeMessage.ht_client_hello) &&
+                                            //  5: recode header size
+                (source[offset + 4 + 2 + 32] == 0)) {
+                                            // V3 session ID is empty
+                                            //  4: handshake header size
+                                            //  2: client_version in ClientHello
+                                            // 32: random in ClientHello
+
+                ByteBuffer v2ClientHello = encodeV2ClientHello(
+                        source, (offset + 4), (length - 4));
+
+                byte[] record = v2ClientHello.array();  // array offset is zero
+                int limit = v2ClientHello.limit();
+                handshakeHash.update(record, 2, (limit - 2));
+
+                if (debug != null && Debug.isOn("record")) {
+                     System.out.println(Thread.currentThread().getName() +
+                        ", WRITE: SSLv2 ClientHello message" +
+                        ", length = " + limit);
+                }
+
+                // deliver this message
+                //
+                // Version 2 ClientHello message should be plaintext.
+                //
+                // No max fragment length negotiation.
+                deliverStream.write(record, 0, limit);
+                deliverStream.flush();
+
+                if (debug != null && Debug.isOn("packet")) {
+                     Debug.printHex(
+                            "[Raw write]: length = " + count, record, 0, limit);
+                }
+
+                return;
+            }
+        }
+
+        byte handshakeType = source[0];
+        if (handshakeType != HandshakeMessage.ht_hello_request) {
+            handshakeHash.update(source, offset, length);
+        }
+
+        int fragLimit = getFragLimit();
+        int position = headerSize + writeCipher.getExplicitNonceSize();
+        if (count == 0) {
+            count = position;
+        }
+
+        if ((count - position) < (fragLimit - length)) {
+            write(source, offset, length);
+            return;
+        }
+
+        for (int limit = (offset + length); offset < limit;) {
+
+            int remains = (limit - offset) + (count - position);
+            int fragLen = Math.min(fragLimit, remains);
+
+            // use the buf of ByteArrayOutputStream
+            write(source, offset, fragLen);
+            if (remains < fragLimit) {
+                return;
+            }
+
+            if (debug != null && Debug.isOn("record")) {
+                System.out.println(Thread.currentThread().getName() +
+                        ", WRITE: " + protocolVersion +
+                        " " + Record.contentName(Record.ct_handshake) +
+                        ", length = " + (count - headerSize));
+            }
+
+            // Encrypt the fragment and wrap up a record.
+            encrypt(writeAuthenticator, writeCipher,
+                    Record.ct_handshake, headerSize);
+
+            // deliver this message
+            deliverStream.write(buf, 0, count);    // may throw IOException
+            deliverStream.flush();                 // may throw IOException
+
+            if (debug != null && Debug.isOn("packet")) {
+                 Debug.printHex(
+                        "[Raw write]: length = " + count, buf, 0, count);
+            }
+
+            // reset the offset
+            offset += fragLen;
+
+            // reset the internal buffer
+            count = position;
+        }
+    }
+
+    @Override
+    void encodeChangeCipherSpec() throws IOException {
+
+        // use the buf of ByteArrayOutputStream
+        int position = headerSize + writeCipher.getExplicitNonceSize();
+        count = position;
+
+        write((byte)1);         // byte 1: change_cipher_spec(
+
+        if (debug != null && Debug.isOn("record")) {
+            System.out.println(Thread.currentThread().getName() +
+                    ", WRITE: " + protocolVersion +
+                    " " + Record.contentName(Record.ct_change_cipher_spec) +
+                    ", length = " + (count - headerSize));
+        }
+
+        // Encrypt the fragment and wrap up a record.
+        encrypt(writeAuthenticator, writeCipher,
+                Record.ct_change_cipher_spec, headerSize);
+
+        // deliver this message
+        deliverStream.write(buf, 0, count);        // may throw IOException
+        // deliverStream.flush();                  // flush in Finished
+
+        if (debug != null && Debug.isOn("packet")) {
+             Debug.printHex(
+                    "[Raw write]: length = " + count, buf, 0, count);
+        }
+
+        // reset the internal buffer
+        count = 0;
+    }
+
+    @Override
+    public void flush() throws IOException {
+        int position = headerSize + writeCipher.getExplicitNonceSize();
+        if (count <= position) {
+            return;
+        }
+
+        if (debug != null && Debug.isOn("record")) {
+            System.out.println(Thread.currentThread().getName() +
+                    ", WRITE: " + protocolVersion +
+                    " " + Record.contentName(Record.ct_handshake) +
+                    ", length = " + (count - headerSize));
+        }
+
+        // Encrypt the fragment and wrap up a record.
+        encrypt(writeAuthenticator, writeCipher,
+                    Record.ct_handshake, headerSize);
+
+        // deliver this message
+        deliverStream.write(buf, 0, count);    // may throw IOException
+        deliverStream.flush();                 // may throw IOException
+
+        if (debug != null && Debug.isOn("packet")) {
+             Debug.printHex(
+                    "[Raw write]: length = " + count, buf, 0, count);
+        }
+
+        // reset the internal buffer
+        count = 0;      // DON'T use position
+    }
+
+    @Override
+    void deliver(byte[] source, int offset, int length) throws IOException {
+
+        if (writeAuthenticator.seqNumOverflow()) {
+            if (debug != null && Debug.isOn("ssl")) {
+                System.out.println(Thread.currentThread().getName() +
+                    ", sequence number extremely close to overflow " +
+                    "(2^64-1 packets). Closing connection.");
+            }
+
+            throw new SSLHandshakeException("sequence number overflow");
+        }
+
+        boolean isFirstRecordOfThePayload = true;
+        for (int limit = (offset + length); offset < limit;) {
+            int macLen = 0;
+            if (writeAuthenticator instanceof MAC) {
+                macLen = ((MAC)writeAuthenticator).MAClen();
+            }
+
+            int fragLen;
+            if (packetSize > 0) {
+                fragLen = Math.min(maxRecordSize, packetSize);
+                fragLen = writeCipher.calculateFragmentSize(
+                        fragLen, macLen, headerSize);
+
+                fragLen = Math.min(fragLen, Record.maxDataSize);
+            } else {
+                fragLen = Record.maxDataSize;
+            }
+
+            if (fragmentSize > 0) {
+                fragLen = Math.min(fragLen, fragmentSize);
+            }
+
+            if (isFirstRecordOfThePayload && needToSplitPayload()) {
+                fragLen = 1;
+                isFirstRecordOfThePayload = false;
+            } else {
+                fragLen = Math.min(fragLen, (limit - offset));
+            }
+
+            // use the buf of ByteArrayOutputStream
+            int position = headerSize + writeCipher.getExplicitNonceSize();
+            count = position;
+            write(source, offset, fragLen);
+
+            if (debug != null && Debug.isOn("record")) {
+                System.out.println(Thread.currentThread().getName() +
+                        ", WRITE: " + protocolVersion +
+                        " " + Record.contentName(Record.ct_application_data) +
+                        ", length = " + (count - headerSize));
+            }
+
+            // Encrypt the fragment and wrap up a record.
+            encrypt(writeAuthenticator, writeCipher,
+                    Record.ct_application_data, headerSize);
+
+            // deliver this message
+            deliverStream.write(buf, 0, count);    // may throw IOException
+            deliverStream.flush();                 // may throw IOException
+
+            if (debug != null && Debug.isOn("packet")) {
+                 Debug.printHex(
+                        "[Raw write]: length = " + count, buf, 0, count);
+            }
+
+            // reset the internal buffer
+            count = 0;
+
+            if (isFirstAppOutputRecord) {
+                isFirstAppOutputRecord = false;
+            }
+
+            offset += fragLen;
+        }
+    }
+
+    @Override
+    void setDeliverStream(OutputStream outputStream) {
+        this.deliverStream = outputStream;
+    }
+
+    /*
+     * Need to split the payload except the following cases:
+     *
+     * 1. protocol version is TLS 1.1 or later;
+     * 2. bulk cipher does not use CBC mode, including null bulk cipher suites.
+     * 3. the payload is the first application record of a freshly
+     *    negotiated TLS session.
+     * 4. the CBC protection is disabled;
+     *
+     * By default, we counter chosen plaintext issues on CBC mode
+     * ciphersuites in SSLv3/TLS1.0 by sending one byte of application
+     * data in the first record of every payload, and the rest in
+     * subsequent record(s). Note that the issues have been solved in
+     * TLS 1.1 or later.
+     *
+     * It is not necessary to split the very first application record of
+     * a freshly negotiated TLS session, as there is no previous
+     * application data to guess.  To improve compatibility, we will not
+     * split such records.
+     *
+     * This avoids issues in the outbound direction.  For a full fix,
+     * the peer must have similar protections.
+     */
+    boolean needToSplitPayload() {
+        return (!protocolVersion.useTLS11PlusSpec()) &&
+                writeCipher.isCBCMode() && !isFirstAppOutputRecord &&
+                Record.enableCBCProtection;
+    }
+
+    private int getFragLimit() {
+        int macLen = 0;
+        if (writeAuthenticator instanceof MAC) {
+            macLen = ((MAC)writeAuthenticator).MAClen();
+        }
+
+        int fragLimit;
+        if (packetSize > 0) {
+            fragLimit = Math.min(maxRecordSize, packetSize);
+            fragLimit = writeCipher.calculateFragmentSize(
+                    fragLimit, macLen, headerSize);
+
+            fragLimit = Math.min(fragLimit, Record.maxDataSize);
+        } else {
+            fragLimit = Record.maxDataSize;
+        }
+
+        if (fragmentSize > 0) {
+            fragLimit = Math.min(fragLimit, fragmentSize);
+        }
+
+        return fragLimit;
+    }
+}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java	Wed Jul 05 20:37:09 2017 +0200
@@ -38,8 +38,6 @@
 
 import javax.net.ssl.*;
 
-import javax.security.auth.Subject;
-
 import sun.security.util.KeyUtil;
 import sun.security.action.GetPropertyAction;
 import sun.security.ssl.HandshakeMessage.*;
@@ -58,7 +56,7 @@
 final class ServerHandshaker extends Handshaker {
 
     // is the server going to require the client to authenticate?
-    private byte                doClientAuth;
+    private ClientAuthType      doClientAuth;
 
     // our authentication info
     private X509Certificate[]   certs;
@@ -143,13 +141,13 @@
      * Constructor ... use the keys found in the auth context.
      */
     ServerHandshaker(SSLSocketImpl socket, SSLContextImpl context,
-            ProtocolList enabledProtocols, byte clientAuth,
+            ProtocolList enabledProtocols, ClientAuthType clientAuth,
             ProtocolVersion activeProtocolVersion, boolean isInitialHandshake,
             boolean secureRenegotiation,
             byte[] clientVerifyData, byte[] serverVerifyData) {
 
         super(socket, context, enabledProtocols,
-                (clientAuth != SSLEngineImpl.clauth_none), false,
+                (clientAuth != ClientAuthType.CLIENT_AUTH_NONE), false,
                 activeProtocolVersion, isInitialHandshake, secureRenegotiation,
                 clientVerifyData, serverVerifyData);
         doClientAuth = clientAuth;
@@ -159,15 +157,16 @@
      * Constructor ... use the keys found in the auth context.
      */
     ServerHandshaker(SSLEngineImpl engine, SSLContextImpl context,
-            ProtocolList enabledProtocols, byte clientAuth,
+            ProtocolList enabledProtocols, ClientAuthType clientAuth,
             ProtocolVersion activeProtocolVersion,
             boolean isInitialHandshake, boolean secureRenegotiation,
-            byte[] clientVerifyData, byte[] serverVerifyData) {
+            byte[] clientVerifyData, byte[] serverVerifyData,
+            boolean isDTLS) {
 
         super(engine, context, enabledProtocols,
-                (clientAuth != SSLEngineImpl.clauth_none), false,
+                (clientAuth != ClientAuthType.CLIENT_AUTH_NONE), false,
                 activeProtocolVersion, isInitialHandshake, secureRenegotiation,
-                clientVerifyData, serverVerifyData);
+                clientVerifyData, serverVerifyData, isDTLS);
         doClientAuth = clientAuth;
     }
 
@@ -176,7 +175,7 @@
      * whether client authentication is required.  Otherwise,
      * we will need to wait for the next handshake.
      */
-    void setClientAuth(byte clientAuth) {
+    void setClientAuth(ClientAuthType clientAuth) {
         doClientAuth = clientAuth;
     }
 
@@ -192,21 +191,15 @@
     @Override
     void processMessage(byte type, int message_len)
             throws IOException {
-        //
-        // In SSLv3 and TLS, messages follow strictly increasing
-        // numerical order _except_ for one annoying special case.
-        //
-        if ((state >= type)
-                && (state != HandshakeMessage.ht_client_key_exchange
-                    && type != HandshakeMessage.ht_certificate_verify)) {
-            throw new SSLProtocolException(
-                    "Handshake message sequence violation, state = " + state
-                    + ", type = " + type);
-        }
+
+        // check the handshake state
+        handshakeState.check(type);
 
         switch (type) {
             case HandshakeMessage.ht_client_hello:
-                ClientHello ch = new ClientHello(input, message_len);
+                ClientHello ch = new ClientHello(input, message_len, isDTLS);
+                handshakeState.update(ch, resumingSession);
+
                 /*
                  * send it off for processing.
                  */
@@ -214,12 +207,14 @@
                 break;
 
             case HandshakeMessage.ht_certificate:
-                if (doClientAuth == SSLEngineImpl.clauth_none) {
+                if (doClientAuth == ClientAuthType.CLIENT_AUTH_NONE) {
                     fatalSE(Alerts.alert_unexpected_message,
                                 "client sent unsolicited cert chain");
                     // NOTREACHED
                 }
-                this.clientCertificate(new CertificateMsg(input));
+                CertificateMsg certificateMsg = new CertificateMsg(input);
+                handshakeState.update(certificateMsg, resumingSession);
+                this.clientCertificate(certificateMsg);
                 break;
 
             case HandshakeMessage.ht_client_key_exchange:
@@ -237,18 +232,9 @@
                             protocolVersion, clientRequestedVersion,
                             sslContext.getSecureRandom(), input,
                             message_len, privateKey);
+                    handshakeState.update(pms, resumingSession);
                     preMasterSecret = this.clientKeyExchange(pms);
                     break;
-                case K_KRB5:
-                case K_KRB5_EXPORT:
-                    preMasterSecret = this.clientKeyExchange(
-                        new KerberosClientKeyExchange(protocolVersion,
-                            clientRequestedVersion,
-                            sslContext.getSecureRandom(),
-                            input,
-                            this.getAccSE(),
-                            serviceCreds));
-                    break;
                 case K_DHE_RSA:
                 case K_DHE_DSS:
                 case K_DH_ANON:
@@ -258,20 +244,39 @@
                      * protocol difference in these five flavors is in how
                      * the ServerKeyExchange message was constructed!
                      */
-                    preMasterSecret = this.clientKeyExchange(
-                            new DHClientKeyExchange(input));
+                    DHClientKeyExchange dhcke = new DHClientKeyExchange(input);
+                    handshakeState.update(dhcke, resumingSession);
+                    preMasterSecret = this.clientKeyExchange(dhcke);
                     break;
                 case K_ECDH_RSA:
                 case K_ECDH_ECDSA:
                 case K_ECDHE_RSA:
                 case K_ECDHE_ECDSA:
                 case K_ECDH_ANON:
-                    preMasterSecret = this.clientKeyExchange
-                                            (new ECDHClientKeyExchange(input));
+                    ECDHClientKeyExchange ecdhcke =
+                                    new ECDHClientKeyExchange(input);
+                    handshakeState.update(ecdhcke, resumingSession);
+                    preMasterSecret = this.clientKeyExchange(ecdhcke);
                     break;
                 default:
-                    throw new SSLProtocolException
-                        ("Unrecognized key exchange: " + keyExchange);
+                    ClientKeyExchangeService p =
+                            ClientKeyExchangeService.find(keyExchange.name);
+                    if (p == null) {
+                        throw new SSLProtocolException
+                                ("Unrecognized key exchange: " + keyExchange);
+                    }
+                    byte[] encodedTicket = input.getBytes16();
+                    input.getBytes16();
+                    byte[] secret = input.getBytes16();
+                    ClientKeyExchange cke = p.createServerExchange(protocolVersion,
+                            clientRequestedVersion,
+                            sslContext.getSecureRandom(),
+                            encodedTicket,
+                            secret,
+                            this.getAccSE(), serviceCreds);
+                    handshakeState.update(cke, resumingSession);
+                    preMasterSecret = this.clientKeyExchange(cke);
+                    break;
                 }
 
                 //
@@ -282,20 +287,20 @@
                 break;
 
             case HandshakeMessage.ht_certificate_verify:
-                this.clientCertificateVerify(new CertificateVerify(input,
-                            localSupportedSignAlgs, protocolVersion));
+                CertificateVerify cvm =
+                        new CertificateVerify(input,
+                            localSupportedSignAlgs, protocolVersion);
+                handshakeState.update(cvm, resumingSession);
+                this.clientCertificateVerify(cvm);
+
                 break;
 
             case HandshakeMessage.ht_finished:
-                // A ChangeCipherSpec record must have been received prior to
-                // reception of the Finished message (RFC 5246, 7.4.9).
-                if (!receivedChangeCipherSpec()) {
-                    fatalSE(Alerts.alert_handshake_failure,
-                        "Received Finished message before ChangeCipherSpec");
-                }
+                Finished cfm =
+                    new Finished(protocolVersion, input, cipherSuite);
+                handshakeState.update(cfm, resumingSession);
+                this.clientFinished(cfm);
 
-                this.clientFinished(
-                    new Finished(protocolVersion, input, cipherSuite));
                 break;
 
             default:
@@ -303,17 +308,6 @@
                         "Illegal server handshake msg, " + type);
         }
 
-        //
-        // Move state machine forward if the message handling
-        // code didn't already do so
-        //
-        if (state < type) {
-            if(type == HandshakeMessage.ht_certificate_verify) {
-                state = type + 2;    // an annoying special case
-            } else {
-                state = type;
-            }
-        }
     }
 
 
@@ -344,7 +338,7 @@
         //
         // This will not have any impact on server initiated renegotiation.
         if (rejectClientInitiatedRenego && !isInitialHandshake &&
-                state != HandshakeMessage.ht_hello_request) {
+                !serverHelloRequested) {
             fatalSE(Alerts.alert_handshake_failure,
                 "Client initiated renegotiation is not allowed");
         }
@@ -438,7 +432,7 @@
                 }
             } else if (!allowUnsafeRenegotiation) {
                 // abort the handshake
-                if (activeProtocolVersion.v >= ProtocolVersion.TLS10.v) {
+                if (activeProtocolVersion.useTLS10PlusSpec()) {
                     // respond with a no_renegotiation warning
                     warningSE(Alerts.alert_no_renegotiation);
 
@@ -480,11 +474,52 @@
             }
         }
 
-        /*
-         * Always make sure this entire record has been digested before we
-         * start emitting output, to ensure correct digesting order.
-         */
-        input.digestNow();
+        // check the "max_fragment_length" extension
+        MaxFragmentLengthExtension maxFragLenExt = (MaxFragmentLengthExtension)
+                    mesg.extensions.get(ExtensionType.EXT_MAX_FRAGMENT_LENGTH);
+        if ((maxFragLenExt != null) && (maximumPacketSize != 0)) {
+            // Not yet consider the impact of IV/MAC/padding.
+            int estimatedMaxFragSize = maximumPacketSize;
+            if (isDTLS) {
+                estimatedMaxFragSize -= DTLSRecord.headerSize;
+            } else {
+                estimatedMaxFragSize -= SSLRecord.headerSize;
+            }
+
+            if (maxFragLenExt.getMaxFragLen() > estimatedMaxFragSize) {
+                // For better interoperability, abort the maximum fragment
+                // length negotiation, rather than terminate the connection
+                // with a fatal alert.
+                maxFragLenExt = null;
+
+                // fatalSE(Alerts.alert_illegal_parameter,
+                //         "Not an allowed max_fragment_length value");
+            }
+        }
+
+        // cookie exchange
+        if (isDTLS) {
+             HelloCookieManager hcMgr = sslContext.getHelloCookieManager();
+             if ((mesg.cookie == null) || (mesg.cookie.length == 0) ||
+                    (!hcMgr.isValid(mesg))) {
+
+                //
+                // Perform cookie exchange for DTLS handshaking if no cookie
+                // or the cookie is invalid in the ClientHello message.
+                //
+                HelloVerifyRequest m0 = new HelloVerifyRequest(hcMgr, mesg);
+
+                if (debug != null && Debug.isOn("handshake")) {
+                    m0.print(System.out);
+                }
+
+                m0.write(output);
+                handshakeState.update(m0, resumingSession);
+                output.flush();
+
+                return;
+            }
+        }
 
         /*
          * FIRST, construct the ServerHello using the options and priorities
@@ -580,7 +615,7 @@
                 }
 
                 if (resumingSession &&
-                        (doClientAuth == SSLEngineImpl.clauth_required)) {
+                        (doClientAuth == ClientAuthType.CLIENT_AUTH_REQUIRED)) {
                     try {
                         previous.getPeerPrincipal();
                     } catch (SSLPeerUnverifiedException e) {
@@ -591,47 +626,21 @@
                 // validate subject identity
                 if (resumingSession) {
                     CipherSuite suite = previous.getSuite();
-                    if (suite.keyExchange == K_KRB5 ||
-                        suite.keyExchange == K_KRB5_EXPORT) {
+                    ClientKeyExchangeService p =
+                            ClientKeyExchangeService.find(suite.keyExchange.name);
+                    if (p != null) {
                         Principal localPrincipal = previous.getLocalPrincipal();
 
-                        Subject subject = null;
-                        try {
-                            subject = AccessController.doPrivileged(
-                                new PrivilegedExceptionAction<Subject>() {
-                                @Override
-                                public Subject run() throws Exception {
-                                    return
-                                        Krb5Helper.getServerSubject(getAccSE());
-                            }});
-                        } catch (PrivilegedActionException e) {
-                            subject = null;
-                            if (debug != null && Debug.isOn("session")) {
-                                System.out.println("Attempt to obtain" +
-                                                " subject failed!");
-                            }
-                        }
-
-                        if (subject != null) {
-                            // Eliminate dependency on KerberosPrincipal
-                            if (Krb5Helper.isRelated(subject, localPrincipal)) {
-                                if (debug != null && Debug.isOn("session"))
-                                    System.out.println("Subject can" +
-                                            " provide creds for princ");
-                            } else {
-                                resumingSession = false;
-                                if (debug != null && Debug.isOn("session"))
-                                    System.out.println("Subject cannot" +
-                                            " provide creds for princ");
-                            }
+                        if (p.isRelated(
+                                false, getAccSE(), localPrincipal)) {
+                            if (debug != null && Debug.isOn("session"))
+                                System.out.println("Subject can" +
+                                        " provide creds for princ");
                         } else {
                             resumingSession = false;
                             if (debug != null && Debug.isOn("session"))
-                                System.out.println("Kerberos credentials are" +
-                                    " not present in the current Subject;" +
-                                    " check if " +
-                                    " javax.security.auth.useSubjectAsCreds" +
-                                    " system property has been set to false");
+                                System.out.println("Subject cannot" +
+                                        " provide creds for princ");
                         }
                     }
                 }
@@ -660,7 +669,7 @@
                     }
                 }
             }
-        } // else client did not try to resume
+        }   // else client did not try to resume
 
         //
         // If client hasn't specified a session we can resume, start a
@@ -677,7 +686,7 @@
 
             // We only need to handle the "signature_algorithm" extension
             // for full handshakes and TLS 1.2 or later.
-            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (protocolVersion.useTLS12PlusSpec()) {
                 SignatureAlgorithmsExtension signAlgs =
                     (SignatureAlgorithmsExtension)mesg.extensions.get(
                                     ExtensionType.EXT_SIGNATURE_ALGORITHMS);
@@ -708,7 +717,7 @@
                         sslContext.getSecureRandom(),
                         getHostAddressSE(), getPortSE());
 
-            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (protocolVersion.useTLS12PlusSpec()) {
                 if (peerSupportedSignAlgs != null) {
                     session.setPeerSupportedSignatureAlgorithms(
                             peerSupportedSignAlgs);
@@ -734,12 +743,41 @@
             session.setLocalPrivateKey(privateKey);
 
             // chooseCompression(mesg);
+
+            // set the negotiated maximum fragment in the session
+            //
+            // The protocol version and cipher suite have been negotiated
+            // in previous processes.
+            if (maxFragLenExt != null) {
+                int maxFragLen = maxFragLenExt.getMaxFragLen();
+
+                // More check of the requested "max_fragment_length" extension.
+                if (maximumPacketSize != 0) {
+                    int estimatedMaxFragSize = cipherSuite.calculatePacketSize(
+                            maxFragLen, protocolVersion, isDTLS);
+                    if (estimatedMaxFragSize > maximumPacketSize) {
+                        // For better interoperability, abort the maximum
+                        // fragment length negotiation, rather than terminate
+                        // the connection with a fatal alert.
+                        maxFragLenExt = null;
+
+                        // fatalSE(Alerts.alert_illegal_parameter,
+                        //         "Not an allowed max_fragment_length value");
+                    }
+                }
+
+                if (maxFragLenExt != null) {
+                    session.setNegotiatedMaxFragSize(maxFragLen);
+                }
+            }
+
+            session.setMaximumPacketSize(maximumPacketSize);
         } else {
             // set the handshake session
             setHandshakeSessionSE(session);
         }
 
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             handshakeHash.setFinishedAlg(cipherSuite.prfAlg.getPRFHashAlg());
         }
 
@@ -771,11 +809,20 @@
             }
         }
 
+        if ((maxFragLenExt != null) && !resumingSession) {
+            // When resuming a session, the server MUST NOT include a
+            // max_fragment_length extension in the server hello.
+            //
+            // Otherwise, use the same value as the requested extension.
+            m1.extensions.add(maxFragLenExt);
+        }
+
         if (debug != null && Debug.isOn("handshake")) {
             m1.print(System.out);
             System.out.println("Cipher suite:  " + session.getSuite());
         }
         m1.write(output);
+        handshakeState.update(m1, resumingSession);
 
         //
         // If we are resuming a session, we finish writing handshake
@@ -784,6 +831,10 @@
         if (resumingSession) {
             calculateConnectionKeys(session.getMasterSecret());
             sendChangeCipherAndFinish(false);
+
+            // expecting the final ChangeCipherSpec and Finished messages
+            expectingFinishFlightSE();
+
             return;
         }
 
@@ -796,9 +847,8 @@
          * defined in the protocol spec are explicitly stated to require
          * using RSA certificates.
          */
-        if (keyExchange == K_KRB5 || keyExchange == K_KRB5_EXPORT) {
-            // Server certificates are omitted for Kerberos ciphers
-
+        if (ClientKeyExchangeService.find(cipherSuite.keyExchange.name) != null) {
+            // No external key exchange provider needs a cert now.
         } else if ((keyExchange != K_DH_ANON) && (keyExchange != K_ECDH_ANON)) {
             if (certs == null) {
                 throw new RuntimeException("no certificates");
@@ -815,6 +865,7 @@
                 m2.print(System.out);
             }
             m2.write(output);
+            handshakeState.update(m2, resumingSession);
 
             // XXX has some side effects with OS TCP buffering,
             // leave it out for now
@@ -839,9 +890,7 @@
         ServerKeyExchange m3;
         switch (keyExchange) {
         case K_RSA:
-        case K_KRB5:
-        case K_KRB5_EXPORT:
-            // no server key exchange for RSA or KRB5 ciphersuites
+            // no server key exchange for RSA ciphersuites
             m3 = null;
             break;
         case K_RSA_EXPORT:
@@ -853,9 +902,9 @@
                         sslContext.getSecureRandom());
                     privateKey = tempPrivateKey;
                 } catch (GeneralSecurityException e) {
-                    throwSSLException
-                        ("Error generating RSA server key exchange", e);
                     m3 = null; // make compiler happy
+                    throw new SSLException(
+                            "Error generating RSA server key exchange", e);
                 }
             } else {
                 // RSA_EXPORT with short key, don't need ServerKeyExchange
@@ -873,8 +922,9 @@
                     preferableSignatureAlgorithm,
                     protocolVersion);
             } catch (GeneralSecurityException e) {
-                throwSSLException("Error generating DH server key exchange", e);
                 m3 = null; // make compiler happy
+                throw new SSLException(
+                        "Error generating DH server key exchange", e);
             }
             break;
         case K_DH_ANON:
@@ -892,9 +942,9 @@
                     preferableSignatureAlgorithm,
                     protocolVersion);
             } catch (GeneralSecurityException e) {
-                throwSSLException(
-                    "Error generating ECDH server key exchange", e);
                 m3 = null; // make compiler happy
+                throw new SSLException(
+                        "Error generating ECDH server key exchange", e);
             }
             break;
         case K_ECDH_RSA:
@@ -903,6 +953,13 @@
             m3 = null;
             break;
         default:
+            ClientKeyExchangeService p =
+                    ClientKeyExchangeService.find(keyExchange.name);
+            if (p != null) {
+                // No external key exchange provider needs a cert now.
+                m3 = null;
+                break;
+            }
             throw new RuntimeException("internal error: " + keyExchange);
         }
         if (m3 != null) {
@@ -910,6 +967,7 @@
                 m3.print(System.out);
             }
             m3.write(output);
+            handshakeState.update(m3, resumingSession);
         }
 
         //
@@ -922,16 +980,16 @@
         // Needed only if server requires client to authenticate self.
         // Illegal for anonymous flavors, so we need to check that.
         //
-        // CertificateRequest is omitted for Kerberos ciphers
-        if (doClientAuth != SSLEngineImpl.clauth_none &&
+        // No external key exchange provider needs a cert now.
+        if (doClientAuth != ClientAuthType.CLIENT_AUTH_NONE &&
                 keyExchange != K_DH_ANON && keyExchange != K_ECDH_ANON &&
-                keyExchange != K_KRB5 && keyExchange != K_KRB5_EXPORT) {
+                ClientKeyExchangeService.find(keyExchange.name) == null) {
 
             CertificateRequest m4;
             X509Certificate caCerts[];
 
             Collection<SignatureAndHashAlgorithm> localSignAlgs = null;
-            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (protocolVersion.useTLS12PlusSpec()) {
                 // We currently use all local upported signature and hash
                 // algorithms. However, to minimize the computation cost
                 // of requested hash algorithms, we may use a restricted
@@ -959,6 +1017,7 @@
                 m4.print(System.out);
             }
             m4.write(output);
+            handshakeState.update(m4, resumingSession);
         }
 
         /*
@@ -970,6 +1029,7 @@
             m5.print(System.out);
         }
         m5.write(output);
+        handshakeState.update(m5, resumingSession);
 
         /*
          * Flush any buffered messages so the client will see them.
@@ -1000,7 +1060,7 @@
                 continue;
             }
 
-            if (doClientAuth == SSLEngineImpl.clauth_required) {
+            if (doClientAuth == ClientAuthType.CLIENT_AUTH_REQUIRED) {
                 if ((suite.keyExchange == K_DH_ANON) ||
                     (suite.keyExchange == K_ECDH_ANON)) {
                     continue;
@@ -1043,12 +1103,12 @@
         }
 
         // must not negotiate the obsoleted weak cipher suites.
-        if (protocolVersion.v >= suite.obsoleted) {
+        if (protocolVersion.obsoletes(suite)) {
             return false;
         }
 
         // must not negotiate unsupported cipher suites.
-        if (protocolVersion.v < suite.supported) {
+        if (!protocolVersion.supports(suite)) {
             return false;
         }
 
@@ -1062,7 +1122,7 @@
         tempPublicKey = null;
 
         Collection<SignatureAndHashAlgorithm> supportedSignAlgs = null;
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             if (peerSupportedSignAlgs != null) {
                 supportedSignAlgs = peerSupportedSignAlgs;
             } else {
@@ -1151,7 +1211,7 @@
             }
 
             // get preferable peer signature algorithm for server key exchange
-            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (protocolVersion.useTLS12PlusSpec()) {
                 preferableSignatureAlgorithm =
                     SignatureAndHashAlgorithm.getPreferableAlgorithm(
                                         supportedSignAlgs, "RSA", privateKey);
@@ -1169,7 +1229,7 @@
             }
 
             // get preferable peer signature algorithm for server key exchange
-            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (protocolVersion.useTLS12PlusSpec()) {
                 preferableSignatureAlgorithm =
                     SignatureAndHashAlgorithm.getPreferableAlgorithm(
                                         supportedSignAlgs, "RSA", privateKey);
@@ -1184,7 +1244,7 @@
             break;
         case K_DHE_DSS:
             // get preferable peer signature algorithm for server key exchange
-            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (protocolVersion.useTLS12PlusSpec()) {
                 preferableSignatureAlgorithm =
                     SignatureAndHashAlgorithm.getPreferableAlgorithm(
                                                 supportedSignAlgs, "DSA");
@@ -1202,7 +1262,7 @@
             break;
         case K_ECDHE_ECDSA:
             // get preferable peer signature algorithm for server key exchange
-            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (protocolVersion.useTLS12PlusSpec()) {
                 preferableSignatureAlgorithm =
                     SignatureAndHashAlgorithm.getPreferableAlgorithm(
                                             supportedSignAlgs, "ECDSA");
@@ -1233,13 +1293,6 @@
             }
             setupStaticECDHKeys();
             break;
-        case K_KRB5:
-        case K_KRB5_EXPORT:
-            // need Kerberos Key
-            if (!setupKerberosKeys()) {
-                return false;
-            }
-            break;
         case K_DH_ANON:
             // no certs needed for anonymous
             setupEphemeralDHKeys(suite.exportable, null);
@@ -1251,13 +1304,31 @@
             }
             break;
         default:
-            // internal error, unknown key exchange
-            throw new RuntimeException("Unrecognized cipherSuite: " + suite);
+            ClientKeyExchangeService p =
+                    ClientKeyExchangeService.find(keyExchange.name);
+            if (p == null) {
+                // internal error, unknown key exchange
+                throw new RuntimeException("Unrecognized cipherSuite: " + suite);
+            }
+            // need service creds
+            if (serviceCreds == null) {
+                AccessControlContext acc = getAccSE();
+                serviceCreds = p.getServiceCreds(acc);
+                if (serviceCreds != null) {
+                    if (debug != null && Debug.isOn("handshake")) {
+                        System.out.println("Using serviceCreds");
+                    }
+                }
+                if (serviceCreds == null) {
+                    return false;
+                }
+            }
+            break;
         }
         setCipherSuite(suite);
 
         // set the peer implicit supported signature algorithms
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             if (peerSupportedSignAlgs == null) {
                 setPeerSupportedSignAlgs(supportedSignAlgs);
                 // we had alreay update the session
@@ -1442,73 +1513,10 @@
         return true;
     }
 
-    /**
-     * Retrieve the Kerberos key for the specified server principal
-     * from the JAAS configuration file.
-     *
-     * @return true if successful, false if not available or invalid
+    /*
+     * Returns premaster secret for external key exchange services.
      */
-    private boolean setupKerberosKeys() {
-        if (serviceCreds != null) {
-            return true;
-        }
-        try {
-            final AccessControlContext acc = getAccSE();
-            serviceCreds = AccessController.doPrivileged(
-                // Eliminate dependency on KerberosKey
-                new PrivilegedExceptionAction<Object>() {
-                @Override
-                public Object run() throws Exception {
-                    // get kerberos key for the default principal
-                    return Krb5Helper.getServiceCreds(acc);
-                        }});
-
-            // check permission to access and use the secret key of the
-            // Kerberized "host" service
-            if (serviceCreds != null) {
-                if (debug != null && Debug.isOn("handshake")) {
-                    System.out.println("Using Kerberos creds");
-                }
-                String serverPrincipal =
-                        Krb5Helper.getServerPrincipalName(serviceCreds);
-                if (serverPrincipal != null) {
-                    // When service is bound, we check ASAP. Otherwise,
-                    // will check after client request is received
-                    // in Kerberos ClientKeyExchange
-                    SecurityManager sm = System.getSecurityManager();
-                    try {
-                        if (sm != null) {
-                            // Eliminate dependency on ServicePermission
-                            sm.checkPermission(Krb5Helper.getServicePermission(
-                                    serverPrincipal, "accept"), acc);
-                        }
-                    } catch (SecurityException se) {
-                        serviceCreds = null;
-                        // Do not destroy keys. Will affect Subject
-                        if (debug != null && Debug.isOn("handshake")) {
-                            System.out.println("Permission to access Kerberos"
-                                    + " secret key denied");
-                        }
-                        return false;
-                    }
-                }
-            }
-            return serviceCreds != null;
-        } catch (PrivilegedActionException e) {
-            // Likely exception here is LoginExceptin
-            if (debug != null && Debug.isOn("handshake")) {
-                System.out.println("Attempt to obtain Kerberos key failed: "
-                                + e.toString());
-            }
-            return false;
-        }
-    }
-
-    /*
-     * For Kerberos ciphers, the premaster secret is encrypted using
-     * the session key. See RFC 2712.
-     */
-    private SecretKey clientKeyExchange(KerberosClientKeyExchange mesg)
+    private SecretKey clientKeyExchange(ClientKeyExchange mesg)
         throws IOException {
 
         if (debug != null && Debug.isOn("handshake")) {
@@ -1519,8 +1527,7 @@
         session.setPeerPrincipal(mesg.getPeerPrincipal());
         session.setLocalPrincipal(mesg.getLocalPrincipal());
 
-        byte[] b = mesg.getUnencryptedPreMasterSecret();
-        return new SecretKeySpec(b, "TlsPremasterSecret");
+        return mesg.clientKeyExchange();
     }
 
     /*
@@ -1571,7 +1578,7 @@
             mesg.print(System.out);
         }
 
-        if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+        if (protocolVersion.useTLS12PlusSpec()) {
             SignatureAndHashAlgorithm signAlg =
                 mesg.getPreferableSignatureAlgorithm();
             if (signAlg == null) {
@@ -1623,9 +1630,9 @@
          * Verify if client did send the certificate when client
          * authentication was required, otherwise server should not proceed
          */
-        if (doClientAuth == SSLEngineImpl.clauth_required) {
+        if (doClientAuth == ClientAuthType.CLIENT_AUTH_REQUIRED) {
            // get X500Principal of the end-entity certificate for X509-based
-           // ciphersuites, or Kerberos principal for Kerberos ciphersuites
+           // ciphersuites, or Kerberos principal for Kerberos ciphersuites, etc
            session.getPeerPrincipal();
         }
 
@@ -1664,8 +1671,9 @@
          * the change_cipher_spec and Finished message.
          */
         if (!resumingSession) {
-            input.digestNow();
             sendChangeCipherAndFinish(true);
+        } else {
+            handshakeFinished = true;
         }
 
         /*
@@ -1695,7 +1703,8 @@
     private void sendChangeCipherAndFinish(boolean finishedTag)
             throws IOException {
 
-        output.flush();
+        // Reload if this message has been reserved.
+        handshakeHash.reload();
 
         Finished mesg = new Finished(protocolVersion, handshakeHash,
             Finished.SERVER, session.getMasterSecret(), cipherSuite);
@@ -1713,16 +1722,6 @@
         if (secureRenegotiation) {
             serverVerifyData = mesg.getVerifyData();
         }
-
-        /*
-         * Update state machine so client MUST send 'finished' next
-         * The update should only take place if it is not in the fast
-         * handshake mode since the server has to wait for a finished
-         * message from the client.
-         */
-        if (finishedTag) {
-            state = HandshakeMessage.ht_finished;
-        }
     }
 
 
@@ -1757,7 +1756,7 @@
          * session will get an SSLPeerUnverifiedException.
          */
         if ((description == Alerts.alert_no_certificate) &&
-                (doClientAuth == SSLEngineImpl.clauth_requested)) {
+                (doClientAuth == ClientAuthType.CLIENT_AUTH_REQUESTED)) {
             return;
         }
 
@@ -1798,7 +1797,7 @@
              * If the client authentication is only *REQUESTED* (e.g.
              * not *REQUIRED*, this is an acceptable condition.)
              */
-            if (doClientAuth == SSLEngineImpl.clauth_requested) {
+            if (doClientAuth == ClientAuthType.CLIENT_AUTH_REQUESTED) {
                 return;
             } else {
                 fatalSE(Alerts.alert_bad_certificate,
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SunJSSE.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SunJSSE.java	Wed Jul 05 20:37:09 2017 +0200
@@ -61,7 +61,7 @@
 
     private static String info = "Sun JSSE provider" +
         "(PKCS12, SunX509/PKIX key/trust factories, " +
-        "SSLv3/TLSv1/TLSv1.1/TLSv1.2)";
+        "SSLv3/TLSv1/TLSv1.1/TLSv1.2/DTLSv1.0/DTLSv1.2)";
 
     private static String fipsInfo =
         "Sun JSSE provider (FIPS mode, crypto provider ";
@@ -220,6 +220,13 @@
             put("Alg.Alias.SSLContext.SSLv3", "TLSv1");
         }
 
+        put("SSLContext.DTLSv1.0",
+            "sun.security.ssl.SSLContextImpl$DTLS10Context");
+        put("SSLContext.DTLSv1.2",
+            "sun.security.ssl.SSLContextImpl$DTLS12Context");
+        put("SSLContext.DTLS",
+            "sun.security.ssl.SSLContextImpl$DTLSContext");
+
         put("SSLContext.Default",
             "sun.security.ssl.SSLContextImpl$DefaultSSLContext");
 
--- a/jdk/src/java.base/share/classes/sun/security/ssl/X509KeyManagerImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/X509KeyManagerImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -190,7 +190,7 @@
             if (session != null) {
                 ProtocolVersion protocolVersion =
                     ProtocolVersion.valueOf(session.getProtocol());
-                if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                if (protocolVersion.useTLS12PlusSpec()) {
                     String[] peerSupportedSignAlgs = null;
 
                     if (session instanceof ExtendedSSLSession) {
@@ -218,7 +218,7 @@
             if (session != null) {
                 ProtocolVersion protocolVersion =
                     ProtocolVersion.valueOf(session.getProtocol());
-                if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+                if (protocolVersion.useTLS12PlusSpec()) {
                     String[] peerSupportedSignAlgs = null;
 
                     if (session instanceof ExtendedSSLSession) {
--- a/jdk/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -204,7 +204,7 @@
             // create the algorithm constraints
             ProtocolVersion protocolVersion =
                 ProtocolVersion.valueOf(session.getProtocol());
-            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (protocolVersion.useTLS12PlusSpec()) {
                 if (session instanceof ExtendedSSLSession) {
                     ExtendedSSLSession extSession =
                                     (ExtendedSSLSession)session;
@@ -256,7 +256,7 @@
             // create the algorithm constraints
             ProtocolVersion protocolVersion =
                 ProtocolVersion.valueOf(session.getProtocol());
-            if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+            if (protocolVersion.useTLS12PlusSpec()) {
                 if (session instanceof ExtendedSSLSession) {
                     ExtendedSSLSession extSession =
                                     (ExtendedSSLSession)session;
--- a/jdk/src/java.base/share/classes/sun/security/util/HostnameChecker.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/util/HostnameChecker.java	Wed Jul 05 20:37:09 2017 +0200
@@ -35,7 +35,7 @@
 
 import javax.security.auth.x500.X500Principal;
 
-import sun.security.ssl.Krb5Helper;
+import sun.security.ssl.ClientKeyExchangeService;
 import sun.security.x509.X500Name;
 
 import sun.net.util.IPAddressUtil;
@@ -108,7 +108,12 @@
      * Return the Server name from Kerberos principal.
      */
     public static String getServerName(Principal principal) {
-        return Krb5Helper.getPrincipalHostName(principal);
+        ClientKeyExchangeService p =
+                ClientKeyExchangeService.find("KRB5");
+        if (p == null) {
+            throw new AssertionError("Kerberos should have been available");
+        }
+        return p.getServiceHostName(principal);
     }
 
     /**
--- a/jdk/src/java.base/share/conf/security/java.security	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/share/conf/security/java.security	Wed Jul 05 20:37:09 2017 +0200
@@ -511,11 +511,11 @@
 jdk.certpath.disabledAlgorithms=MD2, MD5, RSA keySize < 1024
 
 # Algorithm restrictions for Secure Socket Layer/Transport Layer Security
-# (SSL/TLS) processing
+# (SSL/TLS/DTLS) processing
 #
 # In some environments, certain algorithms or key lengths may be undesirable
-# when using SSL/TLS.  This section describes the mechanism for disabling
-# algorithms during SSL/TLS security parameters negotiation, including
+# when using SSL/TLS/DTLS.  This section describes the mechanism for disabling
+# algorithms during SSL/TLS/DTLS security parameters negotiation, including
 # protocol version negotiation, cipher suites selection, peer authentication
 # and key exchange mechanisms.
 #
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/solaris/native/libjava/ProcessHandleImpl_solaris.c	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.
+ */
+
+#include "jni.h"
+#include "jni_util.h"
+#include "java_lang_ProcessHandleImpl.h"
+#include "java_lang_ProcessHandleImpl_Info.h"
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <procfs.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <limits.h>
+
+/**
+ * Implementations of ProcessHandleImpl functions that are
+ * NOT common to all Unix variants:
+ * - getProcessPids0(pid, pidArray)
+ *
+ * Implementations of ProcessHandleImpl_Info
+ * - totalTime, startTime
+ * - Command
+ * - Arguments
+ */
+
+/*
+ * Signatures for internal OS specific functions.
+ */
+static pid_t parentPid(JNIEnv *env, pid_t pid);
+static void getStatInfo(JNIEnv *env, jobject jinfo, pid_t pid);
+static void getCmdlineInfo(JNIEnv *env, jobject jinfo, pid_t pid);
+
+extern jstring uidToUser(JNIEnv* env, uid_t uid);
+
+/* Field id for jString 'command' in java.lang.ProcessHandle.Info */
+static jfieldID ProcessHandleImpl_Info_commandID;
+
+/* Field id for jString[] 'arguments' in java.lang.ProcessHandle.Info */
+static jfieldID ProcessHandleImpl_Info_argumentsID;
+
+/* Field id for jlong 'totalTime' in java.lang.ProcessHandle.Info */
+static jfieldID ProcessHandleImpl_Info_totalTimeID;
+
+/* Field id for jlong 'startTime' in java.lang.ProcessHandle.Info */
+static jfieldID ProcessHandleImpl_Info_startTimeID;
+
+/* Field id for jString 'user' in java.lang.ProcessHandleImpl.Info */
+static jfieldID ProcessHandleImpl_Info_userID;
+
+/* static value for clock ticks per second. */
+static long clock_ticks_per_second;
+
+/**************************************************************
+ * Static method to initialize field IDs and the ticks per second rate.
+ *
+ * Class:     java_lang_ProcessHandleImpl_Info
+ * Method:    initIDs
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_java_lang_ProcessHandleImpl_00024Info_initIDs
+  (JNIEnv *env, jclass clazz) {
+
+    CHECK_NULL(ProcessHandleImpl_Info_commandID = (*env)->GetFieldID(env,
+        clazz, "command", "Ljava/lang/String;"));
+    CHECK_NULL(ProcessHandleImpl_Info_argumentsID = (*env)->GetFieldID(env,
+        clazz, "arguments", "[Ljava/lang/String;"));
+    CHECK_NULL(ProcessHandleImpl_Info_totalTimeID = (*env)->GetFieldID(env,
+        clazz, "totalTime", "J"));
+    CHECK_NULL(ProcessHandleImpl_Info_startTimeID = (*env)->GetFieldID(env,
+        clazz, "startTime", "J"));
+    CHECK_NULL(ProcessHandleImpl_Info_userID = (*env)->GetFieldID(env,
+        clazz, "user", "Ljava/lang/String;"));
+    clock_ticks_per_second = sysconf(_SC_CLK_TCK);
+}
+
+/*
+ * Returns the parent pid of the requested pid.
+ *
+ * Class:     java_lang_ProcessHandleImpl
+ * Method:    parent0
+ * Signature: (J)J
+ */
+JNIEXPORT jlong JNICALL Java_java_lang_ProcessHandleImpl_parent0
+(JNIEnv *env, jobject obj, jlong jpid) {
+    pid_t pid = (pid_t) jpid;
+    pid_t ppid = -1;
+
+    if (pid == getpid()) {
+        ppid = getppid();
+    } else {
+        ppid = parentPid(env, pid);
+    }
+    return (jlong) ppid;
+}
+
+/*
+ * Returns the children of the requested pid and optionally each parent.
+ *
+ * Class:     java_lang_ProcessHandleImpl
+ * Method:    getChildPids
+ * Signature: (J[J)I
+ *
+ * Reads /proc and accumulates any process who parent pid matches.
+ * The resulting pids are stored into the array of longs.
+ * The number of pids is returned if they all fit.
+ * If the array is too short, the desired length is returned.
+ */
+JNIEXPORT jint JNICALL Java_java_lang_ProcessHandleImpl_getProcessPids0
+(JNIEnv *env, jclass clazz, jlong jpid,
+    jlongArray jarray, jlongArray jparentArray)
+{
+    DIR* dir;
+    struct dirent* ptr;
+    pid_t pid = (pid_t) jpid;
+    size_t count = 0;
+    jlong* pids = NULL;
+    jlong* ppids = NULL;
+    size_t parentArraySize = 0;
+    size_t arraySize = 0;
+
+    arraySize = (*env)->GetArrayLength(env, jarray);
+    JNU_CHECK_EXCEPTION_RETURN(env, 0);
+    if (jparentArray != NULL) {
+        parentArraySize = (*env)->GetArrayLength(env, jparentArray);
+        JNU_CHECK_EXCEPTION_RETURN(env, 0);
+
+        if (arraySize != parentArraySize) {
+            JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
+            return 0;
+        }
+    }
+
+    /*
+     * To locate the children we scan /proc looking for files that have a
+     * positive integer as a filename.
+     */
+    if ((dir = opendir("/proc")) == NULL) {
+        JNU_ThrowByNameWithLastError(env,
+            "java/lang/Runtime", "Unable to open /proc");
+        return 0;
+    }
+
+    do { // Block to break out of on Exception
+        pids = (*env)->GetLongArrayElements(env, jarray, NULL);
+        if (pids == NULL) {
+            break;
+        }
+        if (jparentArray != NULL) {
+            ppids  = (*env)->GetLongArrayElements(env, jparentArray, NULL);
+            if (ppids == NULL) {
+                break;
+            }
+        }
+
+        while ((ptr = readdir(dir)) != NULL) {
+            pid_t ppid;
+
+            /* skip files that aren't numbers */
+            pid_t childpid = (pid_t) atoi(ptr->d_name);
+            if ((int) childpid <= 0) {
+                continue;
+            }
+
+            ppid = 0;
+            if (pid != 0 || jparentArray != NULL) {
+                // parentPid opens and reads /proc/pid/stat
+                ppid = parentPid(env, childpid);
+            }
+            if (pid == 0 || ppid == pid) {
+                if (count < arraySize) {
+                    // Only store if it fits
+                    pids[count] = (jlong) childpid;
+
+                    if (ppids != NULL) {
+                        // Store the parentPid
+                        ppids[count] = (jlong) ppid;
+                    }
+                }
+                count++; // Count to tabulate size needed
+            }
+        }
+    } while (0);
+
+    if (pids != NULL) {
+        (*env)->ReleaseLongArrayElements(env, jarray, pids, 0);
+    }
+    if (ppids != NULL) {
+        (*env)->ReleaseLongArrayElements(env, jparentArray, ppids, 0);
+    }
+
+    closedir(dir);
+    // If more pids than array had size for; count will be greater than array size
+    return count;
+}
+
+/*
+ * Returns the parent pid of a given pid, or -1 if not found
+ */
+static pid_t parentPid(JNIEnv *env, pid_t pid) {
+    FILE* fp;
+    pstatus_t pstatus;
+    int statlen;
+    char fn[32];
+    int i, p;
+    char* s;
+
+    /*
+     * Try to open /proc/%d/status
+     */
+    snprintf(fn, sizeof fn, "/proc/%d/status", pid);
+    fp = fopen(fn, "r");
+    if (fp == NULL) {
+        return -1;
+    }
+
+    /*
+     * The format is: pid (command) state ppid ...
+     * As the command could be anything we must find the right most
+     * ")" and then skip the white spaces that follow it.
+     */
+    statlen = fread(&pstatus, 1, (sizeof pstatus), fp);
+    fclose(fp);
+    if (statlen < 0) {
+        return -1;
+    }
+    return (pid_t) pstatus.pr_ppid;
+}
+
+/**************************************************************
+ * Implementation of ProcessHandleImpl_Info native methods.
+ */
+
+/*
+ * Fill in the Info object from the OS information about the process.
+ *
+ * Class:     java_lang_ProcessHandleImpl_Info
+ * Method:    info0
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_java_lang_ProcessHandleImpl_00024Info_info0
+  (JNIEnv *env, jobject jinfo, jlong jpid) {
+    pid_t pid = (pid_t) jpid;
+    getStatInfo(env, jinfo, pid);
+    getCmdlineInfo(env, jinfo, pid);
+}
+
+/**
+ * Read /proc/<pid>/stat and fill in the fields of the Info object.
+ * Gather the user and system times.
+ */
+static void getStatInfo(JNIEnv *env, jobject jinfo, pid_t pid) {
+    FILE* fp;
+    pstatus_t pstatus;
+    struct stat stat_buf;
+    int ret;
+    char fn[32];
+    int i, p;
+    char* s;
+    jlong totalTime;
+
+    /*
+     * Try to open /proc/%d/status
+     */
+    snprintf(fn, sizeof fn, "/proc/%d/status", pid);
+
+    if (stat(fn, &stat_buf) < 0) {
+        return;
+    }
+
+    fp = fopen(fn, "r");
+    if (fp == NULL) {
+        return;
+    }
+
+    ret = fread(&pstatus, 1, (sizeof pstatus), fp);
+    fclose(fp);
+    if (ret < 0) {
+        return;
+    }
+
+    totalTime = pstatus.pr_utime.tv_sec * 1000000000L + pstatus.pr_utime.tv_nsec +
+                pstatus.pr_stime.tv_sec * 1000000000L + pstatus.pr_stime.tv_nsec;
+
+    (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_totalTimeID, totalTime);
+    JNU_CHECK_EXCEPTION(env);
+}
+
+static void getCmdlineInfo(JNIEnv *env, jobject jinfo, pid_t pid) {
+    FILE* fp;
+    psinfo_t psinfo;
+    int ret;
+    char fn[32];
+    char exePath[PATH_MAX];
+    int i, p;
+    jlong startTime;
+    jobjectArray cmdArray;
+    jstring str = NULL;
+
+    /*
+     * try to open /proc/%d/psinfo
+     */
+    snprintf(fn, sizeof fn, "/proc/%d/psinfo", pid);
+    fp = fopen(fn, "r");
+    if (fp == NULL) {
+        return;
+    }
+
+    /*
+     * The format is: pid (command) state ppid ...
+     * As the command could be anything we must find the right most
+     * ")" and then skip the white spaces that follow it.
+     */
+    ret = fread(&psinfo, 1, (sizeof psinfo), fp);
+    fclose(fp);
+    if (ret < 0) {
+        return;
+    }
+
+    CHECK_NULL((str = uidToUser(env, psinfo.pr_uid)));
+    (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_userID, str);
+    JNU_CHECK_EXCEPTION(env);
+
+    startTime = (jlong)psinfo.pr_start.tv_sec * (jlong)1000 +
+                (jlong)psinfo.pr_start.tv_nsec / 1000000;
+    (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_startTimeID, startTime);
+    JNU_CHECK_EXCEPTION(env);
+
+    /*
+     * The path to the executable command is the link in /proc/<pid>/paths/a.out.
+     */
+    snprintf(fn, sizeof fn, "/proc/%d/path/a.out", pid);
+    if ((ret = readlink(fn, exePath, PATH_MAX - 1)) < 0) {
+        return;
+    }
+
+    // null terminate and create String to store for command
+    exePath[ret] = '\0';
+    CHECK_NULL(str = JNU_NewStringPlatform(env, exePath));
+    (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_commandID, str);
+    JNU_CHECK_EXCEPTION(env);
+}
+
--- a/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -39,9 +39,7 @@
 import java.util.EnumSet;
 import java.util.Locale;
 import java.util.Set;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
 import java.security.AccessController;
 import static java.security.AccessController.doPrivileged;
@@ -50,8 +48,7 @@
 import java.security.PrivilegedExceptionAction;
 
 /**
- * This java.lang.Process subclass in the UNIX environment is for the exclusive use of
- * ProcessBuilder.start() to create new processes.
+ * java.lang.Process subclass in the UNIX environment.
  *
  * @author Mario Wolczko and Ross Knippel.
  * @author Konstantin Kladko (ported to Linux and Bsd)
@@ -63,12 +60,16 @@
     private static final sun.misc.JavaIOFileDescriptorAccess fdAccess
         = sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess();
 
+    // Linux platforms support a normal (non-forcible) kill signal.
+    static final boolean SUPPORTS_NORMAL_TERMINATION = true;
+
     private final int pid;
+    private final ProcessHandle processHandle;
     private int exitcode;
     private boolean hasExited;
 
     private /* final */ OutputStream stdin;
-    private /* final */ InputStream stdout;
+    private /* final */ InputStream  stdout;
     private /* final */ InputStream  stderr;
 
     // only used on Solaris
@@ -97,7 +98,7 @@
         Platform(LaunchMechanism ... launchMechanisms) {
             this.defaultLaunchMechanism = launchMechanisms[0];
             this.validLaunchMechanisms =
-                    EnumSet.copyOf(Arrays.asList(launchMechanisms));
+                EnumSet.copyOf(Arrays.asList(launchMechanisms));
         }
 
         @SuppressWarnings("fallthrough")
@@ -121,43 +122,43 @@
 
         String helperPath() {
             return AccessController.doPrivileged(
-                    (PrivilegedAction<String>) () ->
-                            helperPath(System.getProperty("java.home"),
-                                    System.getProperty("os.arch"))
+                (PrivilegedAction<String>) () ->
+                    helperPath(System.getProperty("java.home"),
+                               System.getProperty("os.arch"))
             );
         }
 
         LaunchMechanism launchMechanism() {
             return AccessController.doPrivileged(
-                    (PrivilegedAction<LaunchMechanism>) () -> {
-                        String s = System.getProperty(
-                                "jdk.lang.Process.launchMechanism");
-                        LaunchMechanism lm;
-                        if (s == null) {
-                            lm = defaultLaunchMechanism;
-                            s = lm.name().toLowerCase(Locale.ENGLISH);
-                        } else {
-                            try {
-                                lm = LaunchMechanism.valueOf(
-                                        s.toUpperCase(Locale.ENGLISH));
-                            } catch (IllegalArgumentException e) {
-                                lm = null;
-                            }
+                (PrivilegedAction<LaunchMechanism>) () -> {
+                    String s = System.getProperty(
+                        "jdk.lang.Process.launchMechanism");
+                    LaunchMechanism lm;
+                    if (s == null) {
+                        lm = defaultLaunchMechanism;
+                        s = lm.name().toLowerCase(Locale.ENGLISH);
+                    } else {
+                        try {
+                            lm = LaunchMechanism.valueOf(
+                                s.toUpperCase(Locale.ENGLISH));
+                        } catch (IllegalArgumentException e) {
+                            lm = null;
                         }
-                        if (lm == null || !validLaunchMechanisms.contains(lm)) {
-                            throw new Error(
-                                    s + " is not a supported " +
-                                            "process launch mechanism on this platform."
-                            );
-                        }
-                        return lm;
                     }
+                    if (lm == null || !validLaunchMechanisms.contains(lm)) {
+                        throw new Error(
+                            s + " is not a supported " +
+                            "process launch mechanism on this platform."
+                        );
+                    }
+                    return lm;
+                }
             );
         }
 
         static Platform get() {
             String osName = AccessController.doPrivileged(
-                    (PrivilegedAction<String>) () -> System.getProperty("os.name")
+                (PrivilegedAction<String>) () -> System.getProperty("os.name")
             );
 
             if (osName.equals("Linux")) { return LINUX; }
@@ -173,17 +174,14 @@
     private static final LaunchMechanism launchMechanism = platform.launchMechanism();
     private static final byte[] helperpath = toCString(platform.helperPath());
 
-    /* this is for the reaping thread */
-    private native int waitForProcessExit(int pid);
-
     private static byte[] toCString(String s) {
         if (s == null)
             return null;
         byte[] bytes = s.getBytes();
         byte[] result = new byte[bytes.length + 1];
         System.arraycopy(bytes, 0,
-                result, 0,
-                bytes.length);
+                         result, 0,
+                         bytes.length);
         result[result.length-1] = (byte)0;
         return result;
     }
@@ -304,30 +302,7 @@
                                    byte[] dir,
                                    int[] fds,
                                    boolean redirectErrorStream)
-            throws IOException;
-
-    /**
-     * The thread pool of "process reaper" daemon threads.
-     */
-    private static final Executor processReaperExecutor =
-            doPrivileged((PrivilegedAction<Executor>) () -> {
-
-                ThreadGroup tg = Thread.currentThread().getThreadGroup();
-                while (tg.getParent() != null) tg = tg.getParent();
-                ThreadGroup systemThreadGroup = tg;
-
-                ThreadFactory threadFactory = grimReaper -> {
-                    // Our thread stack requirement is quite modest.
-                    Thread t = new Thread(systemThreadGroup, grimReaper,
-                            "process reaper", 32768);
-                    t.setDaemon(true);
-                    // A small attempt (probably futile) to avoid priority inversion
-                    t.setPriority(Thread.MAX_PRIORITY);
-                    return t;
-                };
-
-                return Executors.newCachedThreadPool(threadFactory);
-            });
+        throws IOException;
 
     private ProcessImpl(final byte[] prog,
                 final byte[] argBlock, final int argc,
@@ -338,13 +313,14 @@
             throws IOException {
 
         pid = forkAndExec(launchMechanism.ordinal() + 1,
-                helperpath,
-                prog,
-                argBlock, argc,
-                envBlock, envc,
-                dir,
-                fds,
-                redirectErrorStream);
+                          helperpath,
+                          prog,
+                          argBlock, argc,
+                          envBlock, envc,
+                          dir,
+                          fds,
+                          redirectErrorStream);
+        processHandle = ProcessHandleImpl.getUnchecked(pid);
 
         try {
             doPrivileged((PrivilegedExceptionAction<Void>) () -> {
@@ -371,18 +347,16 @@
                         new ProcessPipeOutputStream(fds[0]);
 
                 stdout = (fds[1] == -1) ?
-                        ProcessBuilder.NullInputStream.INSTANCE :
-                        new ProcessPipeInputStream(fds[1]);
+                         ProcessBuilder.NullInputStream.INSTANCE :
+                         new ProcessPipeInputStream(fds[1]);
 
                 stderr = (fds[2] == -1) ?
-                        ProcessBuilder.NullInputStream.INSTANCE :
-                        new ProcessPipeInputStream(fds[2]);
+                         ProcessBuilder.NullInputStream.INSTANCE :
+                         new ProcessPipeInputStream(fds[2]);
 
-                processReaperExecutor.execute(() -> {
-                    int exitcode = waitForProcessExit(pid);
-
+                ProcessHandleImpl.completion(pid, true).handle((exitcode, throwable) -> {
                     synchronized (this) {
-                        this.exitcode = exitcode;
+                        this.exitcode = (exitcode == null) ? -1 : exitcode.intValue();
                         this.hasExited = true;
                         this.notifyAll();
                     }
@@ -395,6 +369,8 @@
 
                     if (stdin instanceof ProcessPipeOutputStream)
                         ((ProcessPipeOutputStream) stdin).processExited();
+
+                    return null;
                 });
                 break;
 
@@ -402,18 +378,18 @@
                 stdin = (fds[0] == -1) ?
                         ProcessBuilder.NullOutputStream.INSTANCE :
                         new BufferedOutputStream(
-                                new FileOutputStream(newFileDescriptor(fds[0])));
+                            new FileOutputStream(newFileDescriptor(fds[0])));
 
                 stdout = (fds[1] == -1) ?
-                        ProcessBuilder.NullInputStream.INSTANCE :
-                        new BufferedInputStream(
-                                stdout_inner_stream =
-                                        new DeferredCloseInputStream(
-                                                newFileDescriptor(fds[1])));
+                         ProcessBuilder.NullInputStream.INSTANCE :
+                         new BufferedInputStream(
+                             stdout_inner_stream =
+                                 new DeferredCloseInputStream(
+                                     newFileDescriptor(fds[1])));
 
                 stderr = (fds[2] == -1) ?
-                        ProcessBuilder.NullInputStream.INSTANCE :
-                        new DeferredCloseInputStream(newFileDescriptor(fds[2]));
+                         ProcessBuilder.NullInputStream.INSTANCE :
+                         new DeferredCloseInputStream(newFileDescriptor(fds[2]));
 
                 /*
                  * For each subprocess forked a corresponding reaper task
@@ -423,14 +399,13 @@
                  * exitStatus() to be safely executed in parallel (and they
                  * need no native code).
                  */
-                processReaperExecutor.execute(() -> {
-                    int exitcode = waitForProcessExit(pid);
-
+                ProcessHandleImpl.completion(pid, true).handle((exitcode, throwable) -> {
                     synchronized (this) {
-                        this.exitcode = exitcode;
+                        this.exitcode = (exitcode == null) ? -1 : exitcode.intValue();
                         this.hasExited = true;
                         this.notifyAll();
                     }
+                    return null;
                 });
                 break;
 
@@ -440,18 +415,16 @@
                         new ProcessPipeOutputStream(fds[0]);
 
                 stdout = (fds[1] == -1) ?
-                        ProcessBuilder.NullInputStream.INSTANCE :
-                        new DeferredCloseProcessPipeInputStream(fds[1]);
+                         ProcessBuilder.NullInputStream.INSTANCE :
+                         new DeferredCloseProcessPipeInputStream(fds[1]);
 
                 stderr = (fds[2] == -1) ?
-                        ProcessBuilder.NullInputStream.INSTANCE :
-                        new DeferredCloseProcessPipeInputStream(fds[2]);
+                         ProcessBuilder.NullInputStream.INSTANCE :
+                         new DeferredCloseProcessPipeInputStream(fds[2]);
 
-                processReaperExecutor.execute(() -> {
-                    int exitcode = waitForProcessExit(pid);
-
+                ProcessHandleImpl.completion(pid, true).handle((exitcode, throwable) -> {
                     synchronized (this) {
-                        this.exitcode = exitcode;
+                        this.exitcode = (exitcode == null) ? -1 : exitcode.intValue();
                         this.hasExited = true;
                         this.notifyAll();
                     }
@@ -464,6 +437,8 @@
 
                     if (stdin instanceof ProcessPipeOutputStream)
                         ((ProcessPipeOutputStream) stdin).processExited();
+
+                    return null;
                 });
                 break;
 
@@ -492,7 +467,7 @@
 
     @Override
     public synchronized boolean waitFor(long timeout, TimeUnit unit)
-            throws InterruptedException
+        throws InterruptedException
     {
         long remainingNanos = unit.toNanos(timeout);    // throw NPE before other conditions
         if (hasExited) return true;
@@ -517,8 +492,6 @@
         return exitcode;
     }
 
-    private static native void destroyProcess(int pid, boolean force);
-
     private void destroy(boolean force) {
         switch (platform) {
             case LINUX:
@@ -532,7 +505,7 @@
                 // soon, so this is quite safe.
                 synchronized (this) {
                     if (!hasExited)
-                        destroyProcess(pid, force);
+                        ProcessHandleImpl.destroyProcess(pid, force);
                 }
                 try { stdin.close();  } catch (IOException ignored) {}
                 try { stdout.close(); } catch (IOException ignored) {}
@@ -548,14 +521,14 @@
                 // soon, so this is quite safe.
                 synchronized (this) {
                     if (!hasExited)
-                        destroyProcess(pid, force);
+                        ProcessHandleImpl.destroyProcess(pid, force);
                     try {
                         stdin.close();
                         if (stdout_inner_stream != null)
                             stdout_inner_stream.closeDeferred(stdout);
                         if (stderr instanceof DeferredCloseInputStream)
                             ((DeferredCloseInputStream) stderr)
-                                    .closeDeferred(stderr);
+                                .closeDeferred(stderr);
                     } catch (IOException e) {
                         // ignore
                     }
@@ -566,6 +539,27 @@
         }
     }
 
+    @Override
+    public CompletableFuture<Process> onExit() {
+        return ProcessHandleImpl.completion(pid, false)
+                .handleAsync((exitStatus, unusedThrowable) -> this);
+    }
+
+    @Override
+    public ProcessHandle toHandle() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new RuntimePermission("manageProcess"));
+        }
+        return processHandle;
+    }
+
+    @Override
+    public boolean supportsNormalTermination() {
+        return ProcessImpl.SUPPORTS_NORMAL_TERMINATION;
+    }
+
+    @Override
     public void destroy() {
         destroy(false);
     }
@@ -629,8 +623,8 @@
                         byte[] stragglers = drainInputStream(in);
                         in.close();
                         this.in = (stragglers == null) ?
-                                ProcessBuilder.NullInputStream.INSTANCE :
-                                new ByteArrayInputStream(stragglers);
+                            ProcessBuilder.NullInputStream.INSTANCE :
+                            new ByteArrayInputStream(stragglers);
                     }
                 } catch (IOException ignored) {}
             }
@@ -797,7 +791,7 @@
      *
      */
     private static class DeferredCloseProcessPipeInputStream
-            extends BufferedInputStream {
+        extends BufferedInputStream {
 
         private final Object closeLock = new Object();
         private int useCount = 0;
--- a/jdk/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -80,6 +80,15 @@
         return options;
     }
 
+    protected void socketSetOption(int opt, Object val) throws SocketException {
+        try {
+            socketSetOption0(opt, val);
+        } catch (SocketException se) {
+            if (!connected)
+                throw se;
+        }
+    }
+
     protected synchronized native void bind0(int lport, InetAddress laddr)
         throws SocketException;
 
@@ -112,7 +121,7 @@
 
     protected native void datagramSocketClose();
 
-    protected native void socketSetOption(int opt, Object val)
+    protected native void socketSetOption0(int opt, Object val)
         throws SocketException;
 
     protected native Object socketGetOption(int opt) throws SocketException;
--- a/jdk/src/java.base/unix/classes/java/net/PlainSocketImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/unix/classes/java/net/PlainSocketImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -94,6 +94,15 @@
         return options;
     }
 
+    protected void socketSetOption(int opt, boolean b, Object val) throws SocketException {
+        try {
+            socketSetOption0(opt, b, val);
+        } catch (SocketException se) {
+            if (socket == null || !socket.isConnected())
+                throw se;
+        }
+    }
+
     native void socketCreate(boolean isServer) throws IOException;
 
     native void socketConnect(InetAddress address, int port, int timeout)
@@ -114,7 +123,7 @@
 
     static native void initProto();
 
-    native void socketSetOption(int cmd, boolean on, Object value)
+    native void socketSetOption0(int cmd, boolean on, Object value)
         throws SocketException;
 
     native int socketGetOption(int opt, Object iaContainerObj) throws SocketException;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,769 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.
+ */
+
+#include "jni.h"
+#include "jni_util.h"
+#include "java_lang_ProcessHandleImpl.h"
+#include "java_lang_ProcessHandleImpl_Info.h"
+
+
+#include <stdio.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <string.h>
+#include <dirent.h>
+#include <ctype.h>
+
+/**
+ * Implementations of ProcessHandleImpl functions that are common to all
+ * Unix variants:
+ * - waitForProcessExit0(pid, reap)
+ * - getCurrentPid0()
+ * - destroy0(pid, force)
+ */
+
+
+#ifndef WIFEXITED
+#define WIFEXITED(status) (((status)&0xFF) == 0)
+#endif
+
+#ifndef WEXITSTATUS
+#define WEXITSTATUS(status) (((status)>>8)&0xFF)
+#endif
+
+#ifndef WIFSIGNALED
+#define WIFSIGNALED(status) (((status)&0xFF) > 0 && ((status)&0xFF00) == 0)
+#endif
+
+#ifndef WTERMSIG
+#define WTERMSIG(status) ((status)&0x7F)
+#endif
+
+#define RESTARTABLE(_cmd, _result) do { \
+  do { \
+    _result = _cmd; \
+  } while((_result == -1) && (errno == EINTR)); \
+} while(0)
+
+#define RESTARTABLE_RETURN_PTR(_cmd, _result) do { \
+  do { \
+    _result = _cmd; \
+  } while((_result == NULL) && (errno == EINTR)); \
+} while(0)
+
+
+/* Block until a child process exits and return its exit code.
+ * Note, can only be called once for any given pid if reapStatus = true.
+ */
+JNIEXPORT jint JNICALL
+Java_java_lang_ProcessHandleImpl_waitForProcessExit0(JNIEnv* env,
+                                              jclass junk,
+                                              jlong jpid,
+                                              jboolean reapStatus)
+{
+    pid_t pid = (pid_t)jpid;
+    errno = 0;
+
+    if (reapStatus != JNI_FALSE) {
+        /* Wait for the child process to exit.
+         * waitpid() is standard, so use it on all POSIX platforms.
+         * It is known to work when blocking to wait for the pid
+         * This returns immediately if the child has already exited.
+         */
+        int status;
+        while (waitpid(pid, &status, 0) < 0) {
+            switch (errno) {
+                case ECHILD: return 0;
+                case EINTR: break;
+                default: return -1;
+            }
+        }
+
+        if (WIFEXITED(status)) {
+            return WEXITSTATUS(status);
+        } else if (WIFSIGNALED(status)) {
+            /* The child exited because of a signal.
+             * The best value to return is 0x80 + signal number,
+             * because that is what all Unix shells do, and because
+             * it allows callers to distinguish between process exit and
+             * process death by signal.
+             * Unfortunately, the historical behavior on Solaris is to return
+             * the signal number, and we preserve this for compatibility. */
+#ifdef __solaris__
+            return WTERMSIG(status);
+#else
+            return 0x80 + WTERMSIG(status);
+#endif
+        } else {
+            return status;
+        }
+     } else {
+        /*
+         * Wait for the child process to exit without reaping the exitValue.
+         * waitid() is standard on all POSIX platforms.
+         * Note: waitid on Mac OS X 10.7 seems to be broken;
+         * it does not return the exit status consistently.
+         */
+        siginfo_t siginfo;
+        int options = WEXITED |  WNOWAIT;
+        memset(&siginfo, 0, sizeof siginfo);
+        while (waitid(P_PID, pid, &siginfo, options) < 0) {
+            switch (errno) {
+            case ECHILD: return 0;
+            case EINTR: break;
+            default: return -1;
+            }
+        }
+
+        if (siginfo.si_code == CLD_EXITED) {
+             /*
+              * The child exited normally; get its exit code.
+              */
+             return siginfo.si_status;
+        } else if (siginfo.si_code == CLD_KILLED || siginfo.si_code == CLD_DUMPED) {
+             /* The child exited because of a signal.
+              * The best value to return is 0x80 + signal number,
+              * because that is what all Unix shells do, and because
+              * it allows callers to distinguish between process exit and
+              * process death by signal.
+              * Unfortunately, the historical behavior on Solaris is to return
+              * the signal number, and we preserve this for compatibility. */
+ #ifdef __solaris__
+             return WTERMSIG(siginfo.si_status);
+ #else
+             return 0x80 + WTERMSIG(siginfo.si_status);
+ #endif
+        } else {
+             /*
+              * Unknown exit code; pass it through.
+              */
+             return siginfo.si_status;
+        }
+    }
+}
+
+/*
+ * Class:     java_lang_ProcessHandleImpl
+ * Method:    getCurrentPid0
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_java_lang_ProcessHandleImpl_getCurrentPid0
+(JNIEnv *env, jclass clazz) {
+    pid_t pid = getpid();
+    return (jlong) pid;
+}
+
+/*
+ * Class:     java_lang_ProcessHandleImpl
+ * Method:    isAlive0
+ * Signature: (J)Z
+ */
+JNIEXPORT jboolean JNICALL Java_java_lang_ProcessHandleImpl_isAlive0
+(JNIEnv *env, jobject obj, jlong jpid) {
+    pid_t pid = (pid_t) jpid;
+    return (kill(pid, 0) < 0) ? JNI_FALSE : JNI_TRUE;
+}
+
+/*
+ * Class:     java_lang_ProcessHandleImpl
+ * Method:    destroy0
+ * Signature: (Z)Z
+ */
+JNIEXPORT jboolean JNICALL Java_java_lang_ProcessHandleImpl_destroy0
+(JNIEnv *env, jobject obj, jlong jpid, jboolean force) {
+    pid_t pid = (pid_t) jpid;
+    int sig = (force == JNI_TRUE) ? SIGKILL : SIGTERM;
+    return (kill(pid, sig) >= 0);
+
+}
+
+/**
+ * Size of password or group entry when not available via sysconf
+ */
+#define ENT_BUF_SIZE   1024
+
+/**
+ * Return a strong username for the uid_t or null.
+ */
+jstring uidToUser(JNIEnv* env, uid_t uid) {
+    int result = 0;
+    int buflen;
+    char* pwbuf;
+    jstring name = NULL;
+
+    /* allocate buffer for password record */
+    buflen = (int)sysconf(_SC_GETPW_R_SIZE_MAX);
+    if (buflen == -1)
+        buflen = ENT_BUF_SIZE;
+    pwbuf = (char*)malloc(buflen);
+    if (pwbuf == NULL) {
+        JNU_ThrowOutOfMemoryError(env, "Unable to open getpwent");
+    } else {
+        struct passwd pwent;
+        struct passwd* p = NULL;
+
+#ifdef __solaris__
+        RESTARTABLE_RETURN_PTR(getpwuid_r(uid, &pwent, pwbuf, (size_t)buflen), p);
+#else
+        RESTARTABLE(getpwuid_r(uid, &pwent, pwbuf, (size_t)buflen, &p), result);
+#endif
+
+        // Return the Java String if a name was found
+        if (result == 0 && p != NULL &&
+            p->pw_name != NULL && *(p->pw_name) != '\0') {
+            name = JNU_NewStringPlatform(env, p->pw_name);
+        }
+        free(pwbuf);
+    }
+    return name;
+}
+
+/**
+ * Implementations of ProcessHandleImpl functions that are common to
+ * (some) Unix variants:
+ * - getProcessPids0(pid, pidArray, parentArray)
+ */
+
+#if defined(__linux__) || defined(__AIX__)
+
+/*
+ * Signatures for internal OS specific functions.
+ */
+static pid_t parentPid(JNIEnv *env, pid_t pid);
+static jint getChildren(JNIEnv *env, jlong jpid,
+                        jlongArray array, jlongArray jparentArray);
+
+static void getStatInfo(JNIEnv *env, jobject jinfo, pid_t pid);
+static void getCmdlineInfo(JNIEnv *env, pid_t pid, jobject jinfo);
+static long long getBoottime(JNIEnv *env);
+
+jstring uidToUser(JNIEnv* env, uid_t uid);
+
+/* Field id for jString 'command' in java.lang.ProcessHandleImpl.Info */
+static jfieldID ProcessHandleImpl_Info_commandID;
+
+/* Field id for jString[] 'arguments' in java.lang.ProcessHandleImpl.Info */
+static jfieldID ProcessHandleImpl_Info_argumentsID;
+
+/* Field id for jlong 'totalTime' in java.lang.ProcessHandleImpl.Info */
+static jfieldID ProcessHandleImpl_Info_totalTimeID;
+
+/* Field id for jlong 'startTime' in java.lang.ProcessHandleImpl.Info */
+static jfieldID ProcessHandleImpl_Info_startTimeID;
+
+/* Field id for jString 'user' in java.lang.ProcessHandleImpl.Info */
+static jfieldID ProcessHandleImpl_Info_userID;
+
+/* static value for clock ticks per second. */
+static long clock_ticks_per_second;
+
+/* A static offset in milliseconds since boot. */
+static long long bootTime_ms;
+
+/**************************************************************
+ * Static method to initialize field IDs and the ticks per second rate.
+ *
+ * Class:     java_lang_ProcessHandleImpl_Info
+ * Method:    initIDs
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_java_lang_ProcessHandleImpl_00024Info_initIDs
+  (JNIEnv *env, jclass clazz) {
+
+    CHECK_NULL(ProcessHandleImpl_Info_commandID = (*env)->GetFieldID(env,
+        clazz, "command", "Ljava/lang/String;"));
+    CHECK_NULL(ProcessHandleImpl_Info_argumentsID = (*env)->GetFieldID(env,
+        clazz, "arguments", "[Ljava/lang/String;"));
+    CHECK_NULL(ProcessHandleImpl_Info_totalTimeID = (*env)->GetFieldID(env,
+        clazz, "totalTime", "J"));
+    CHECK_NULL(ProcessHandleImpl_Info_startTimeID = (*env)->GetFieldID(env,
+        clazz, "startTime", "J"));
+    CHECK_NULL(ProcessHandleImpl_Info_userID = (*env)->GetFieldID(env,
+        clazz, "user", "Ljava/lang/String;"));
+    clock_ticks_per_second = sysconf(_SC_CLK_TCK);
+    bootTime_ms = getBoottime(env);
+}
+
+/*
+ * Returns the parent pid of the requested pid.
+ *
+ * Class:     java_lang_ProcessHandleImpl
+ * Method:    parent0
+ * Signature: (J)J
+ */
+JNIEXPORT jlong JNICALL Java_java_lang_ProcessHandleImpl_parent0
+(JNIEnv *env, jobject obj, jlong jpid) {
+    pid_t pid = (pid_t) jpid;
+    pid_t ppid = -1;
+
+    pid_t mypid = getpid();
+    if (pid == mypid) {
+        ppid = getppid();
+    } else {
+        ppid = parentPid(env, pid);
+    }
+    return (jlong) ppid;
+}
+
+/*
+ * Returns the children of the requested pid and optionally each parent.
+ *
+ * Class:     java_lang_ProcessHandleImpl
+ * Method:    getChildPids
+ * Signature: (J[J[J)I
+ */
+JNIEXPORT jint JNICALL Java_java_lang_ProcessHandleImpl_getProcessPids0
+(JNIEnv *env, jclass clazz, jlong jpid,
+    jlongArray jarray, jlongArray jparentArray) {
+    return getChildren(env, jpid, jarray, jparentArray);
+}
+
+/*
+ * Reads /proc and accumulates any process who parent pid matches.
+ * The resulting pids are stored into the array of longs.
+ * The number of pids is returned if they all fit.
+ * If the array is too short, the negative of the desired length is returned.
+ */
+static jint getChildren(JNIEnv *env, jlong jpid,
+    jlongArray jarray, jlongArray jparentArray) {
+    DIR* dir;
+    struct dirent* ptr;
+    pid_t pid = (pid_t) jpid;
+    pid_t ppid = 0;
+    size_t count = 0;
+    jlong* pids = NULL;
+    jlong* ppids = NULL;
+    size_t parentArraySize = 0;
+    size_t arraySize = 0;
+
+    arraySize = (*env)->GetArrayLength(env, jarray);
+    JNU_CHECK_EXCEPTION_RETURN(env, -1);
+    if (jparentArray != NULL) {
+        parentArraySize = (*env)->GetArrayLength(env, jparentArray);
+        JNU_CHECK_EXCEPTION_RETURN(env, -1);
+
+        if (arraySize != parentArraySize) {
+            JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
+            return 0;
+        }
+    }
+
+    /*
+     * To locate the children we scan /proc looking for files that have a
+     * position integer as a filename.
+     */
+    if ((dir = opendir("/proc")) == NULL) {
+        JNU_ThrowByNameWithLastError(env,
+            "java/lang/Runtime", "Unable to open /proc");
+        return -1;
+    }
+
+    do { // Block to break out of on Exception
+        pids = (*env)->GetLongArrayElements(env, jarray, NULL);
+        if (pids == NULL) {
+            break;
+        }
+        if (jparentArray != NULL) {
+            ppids  = (*env)->GetLongArrayElements(env, jparentArray, NULL);
+            if (ppids == NULL) {
+                break;
+            }
+        }
+
+        while ((ptr = readdir(dir)) != NULL) {
+            /* skip files that aren't numbers */
+            pid_t childpid = (pid_t) atoi(ptr->d_name);
+            if ((int) childpid <= 0) {
+                continue;
+            }
+
+            ppid = 0;
+            if (pid != 0 || jparentArray != NULL) {
+                // parentPid opens and reads /proc/pid/stat
+                ppid = parentPid(env, childpid);
+            }
+            if (pid == 0 || ppid == pid) {
+                if (count < arraySize) {
+                    // Only store if it fits
+                    pids[count] = (jlong) childpid;
+
+                    if (ppids != NULL) {
+                        // Store the parentPid
+                        ppids[count] = (jlong) ppid;
+                    }
+                }
+                count++; // Count to tabulate size needed
+            }
+        }
+    } while (0);
+
+    if (pids != NULL) {
+        (*env)->ReleaseLongArrayElements(env, jarray, pids, 0);
+    }
+    if (ppids != NULL) {
+        (*env)->ReleaseLongArrayElements(env, jparentArray, ppids, 0);
+    }
+
+    closedir(dir);
+    // If more pids than array had size for; count will be greater than array size
+    return count;
+}
+
+/*
+ * Returns the parent pid of a given pid, or -1 if not found
+ */
+static pid_t parentPid(JNIEnv *env, pid_t pid) {
+    char state;
+    FILE* fp;
+    char stat[2048];
+    int statlen;
+    char fn[32];
+    int i, p;
+    char* s;
+
+    /*
+     * try to open /proc/%d/stat
+     */
+    snprintf(fn, sizeof fn, "/proc/%d/stat", pid);
+    fp = fopen(fn, "r");
+    if (fp == NULL) {
+        return -1;
+    }
+
+    /*
+     * The format is: pid (command) state ppid ...
+     * As the command could be anything we must find the right most
+     * ")" and then skip the white spaces that follow it.
+     */
+    statlen = fread(stat, 1, (sizeof stat - 1), fp);
+    fclose(fp);
+    if (statlen < 0) {
+        return -1;
+    }
+
+    stat[statlen] = '\0';
+    s = strrchr(stat, ')');
+    if (s == NULL) {
+        return -1;
+    }
+    do s++; while (isspace(*s));
+    i = sscanf(s, "%c %d", &state, &p);
+    if (i != 2) {
+        return (pid_t)-1;
+    }
+    return (pid_t) p;
+}
+
+/**************************************************************
+ * Implementation of ProcessHandleImpl_Info native methods.
+ */
+
+/*
+ * Fill in the Info object from the OS information about the process.
+ *
+ * Class:     java_lang_ProcessHandleImpl_Info
+ * Method:    info0
+ * Signature: (JLjava/lang/ProcessHandle/Info;)I
+ */
+JNIEXPORT void JNICALL Java_java_lang_ProcessHandleImpl_00024Info_info0
+  (JNIEnv *env, jobject jinfo, jlong jpid) {
+    pid_t pid = (pid_t) jpid;
+    getStatInfo(env, jinfo, (pid_t)pid);
+    getCmdlineInfo(env, pid, jinfo);
+}
+
+/**
+ * Read /proc/<pid>/stat and fill in the fields of the Info object.
+ * The executable name, plus the user, system, and start times are gathered.
+ */
+static void getStatInfo(JNIEnv *env, jobject jinfo, pid_t pid) {
+    char state;
+    FILE* fp;
+    char buffer[2048];
+    struct stat stat_buf;
+    int statlen;
+    char fn[32];
+    int i, ppid = -2;
+    char* s;
+    char *cmd;
+    jstring name = NULL;
+    unsigned long userTime = 0;             // clock tics
+    unsigned long totalTime = 0;            // clock tics
+    jlong total = 0;                        // nano seconds
+    unsigned long long startTime = 0;       // microseconds
+
+    /*
+     * Try to stat and then open /proc/%d/stat
+     */
+    snprintf(fn, sizeof fn, "/proc/%d/stat", pid);
+
+    if (stat(fn, &stat_buf) < 0) {
+        return;
+    }
+
+    CHECK_NULL((name = uidToUser(env, stat_buf.st_uid)));
+    (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_userID, name);
+    JNU_CHECK_EXCEPTION(env);
+
+    fp = fopen(fn, "r");
+    if (fp == NULL) {
+        return;
+    }
+
+    /*
+     * The format is: pid (command) state ppid ...
+     * As the command could be anything we must find the right most
+     * ")" and then skip the white spaces that follow it.
+     */
+    statlen = fread(buffer, 1, (sizeof buffer - 1), fp);
+    fclose(fp);
+    if (statlen < 0) {
+        return;
+    }
+
+    buffer[statlen] = '\0';
+    s = strchr(buffer, '(');
+    if (s == NULL) {
+        return;
+    }
+    // Found start of command, skip to end
+    s++;
+    s = strrchr(s, ')');
+    if (s == NULL) {
+        return;
+    }
+    s++;
+
+    // Scan the needed fields from status, retaining only ppid(4),
+    // utime (14), stime(15), starttime(22)
+    i = sscanf(s, " %c %d %*d %*d %*d %*d %*d %*u %*u %*u %*u %lu %lu %*d %*d %*d %*d %*d %*d %llu",
+            &state, &ppid, &userTime, &totalTime, &startTime);
+    if (i != 5) {
+        return;              // not all values parsed; return error
+    }
+
+    total = (userTime + totalTime) * (jlong)(1000000000 / clock_ticks_per_second);
+
+    startTime = bootTime_ms + ((startTime * 1000) / clock_ticks_per_second);
+
+    (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_totalTimeID, total);
+    JNU_CHECK_EXCEPTION(env);
+    (*env)->SetLongField(env, jinfo, ProcessHandleImpl_Info_startTimeID, startTime);
+    JNU_CHECK_EXCEPTION(env);
+}
+
+/**
+ * Construct the argument array by parsing the arguments from the sequence
+ * of arguments. The zero'th arg is the command executable
+ */
+static int fillArgArray(JNIEnv *env, jobject jinfo,
+                        int nargs, char *cp, char *argsEnd, jstring cmdexe) {
+    jobject argsArray;
+    int i;
+
+    if (nargs < 1) {
+        return 0;
+    }
+
+    if (cmdexe == NULL) {
+        // Create a string from arg[0]
+        CHECK_NULL_RETURN((cmdexe = JNU_NewStringPlatform(env, cp)), -1);
+    }
+    (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_commandID, cmdexe);
+    JNU_CHECK_EXCEPTION_RETURN(env, -3);
+
+    // Create a String array for nargs-1 elements
+    argsArray = (*env)->NewObjectArray(env, nargs - 1, JNU_ClassString(env), NULL);
+    CHECK_NULL_RETURN(argsArray, -1);
+
+    for (i = 0; i < nargs - 1; i++) {
+        jstring str = NULL;
+
+        cp += strnlen(cp, (argsEnd - cp)) + 1;
+        if (cp > argsEnd || *cp == '\0') {
+            return -2;  // Off the end pointer or an empty argument is an error
+        }
+
+        CHECK_NULL_RETURN((str = JNU_NewStringPlatform(env, cp)), -1);
+
+        (*env)->SetObjectArrayElement(env, argsArray, i, str);
+        JNU_CHECK_EXCEPTION_RETURN(env, -3);
+    }
+    (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_argumentsID, argsArray);
+    JNU_CHECK_EXCEPTION_RETURN(env, -4);
+    return 0;
+}
+
+
+static void getCmdlineInfo(JNIEnv *env, pid_t pid, jobject jinfo) {
+    int fd;
+    int cmdlen = 0;
+    char *cmdline = NULL, *cmdEnd;  // used for command line args and exe
+    jstring cmdexe = NULL;
+    char fn[32];
+
+    /*
+     * Try to open /proc/%d/cmdline
+     */
+    snprintf(fn, sizeof fn, "/proc/%d/cmdline", pid);
+    if ((fd = open(fn, O_RDONLY)) < 0) {
+        return;
+    }
+
+    do {                // Block to break out of on errors
+        int i;
+        char *s;
+
+        cmdline = (char*)malloc(PATH_MAX);
+        if (cmdline == NULL) {
+            break;
+        }
+
+        /*
+         * The path to the executable command is the link in /proc/<pid>/exe.
+         */
+        snprintf(fn, sizeof fn, "/proc/%d/exe", pid);
+        if ((cmdlen = readlink(fn, cmdline, PATH_MAX - 1)) > 0) {
+            // null terminate and create String to store for command
+            cmdline[cmdlen] = '\0';
+            cmdexe = JNU_NewStringPlatform(env, cmdline);
+            (*env)->ExceptionClear(env);        // unconditionally clear any exception
+        }
+
+        /*
+         * The buffer format is the arguments nul terminated with an extra nul.
+         */
+        cmdlen = read(fd, cmdline, PATH_MAX-1);
+        if (cmdlen < 0) {
+            break;
+        }
+
+        // Terminate the buffer and count the arguments
+        cmdline[cmdlen] = '\0';
+        cmdEnd = &cmdline[cmdlen + 1];
+        for (s = cmdline,i = 0; *s != '\0' && (s < cmdEnd); i++) {
+            s += strnlen(s, (cmdEnd - s)) + 1;
+        }
+
+        if (fillArgArray(env, jinfo, i, cmdline, cmdEnd, cmdexe) < 0) {
+            break;
+        }
+    } while (0);
+
+    if (cmdline != NULL) {
+        free(cmdline);
+    }
+    if (fd >= 0) {
+        close(fd);
+    }
+}
+
+/**
+ * Read the boottime from /proc/stat.
+ */
+static long long getBoottime(JNIEnv *env) {
+    FILE *fp;
+    char *line = NULL;
+    size_t len = 0;
+    long long bootTime = 0;
+
+    fp = fopen("/proc/stat", "r");
+    if (fp == NULL) {
+        return -1;
+    }
+
+    while (getline(&line, &len, fp) != -1) {
+        if (sscanf(line, "btime %llu", &bootTime) == 1) {
+            break;
+        }
+    }
+    free(line);
+
+    if (fp != 0) {
+        fclose(fp);
+    }
+
+    return bootTime * 1000;
+}
+
+#endif  //  defined(__linux__) || defined(__AIX__)
+
+
+/* Block until a child process exits and return its exit code.
+   Note, can only be called once for any given pid. */
+JNIEXPORT jint JNICALL
+Java_java_lang_ProcessImpl_waitForProcessExit(JNIEnv* env,
+                                              jobject junk,
+                                              jint pid)
+{
+    /* We used to use waitid() on Solaris, waitpid() on Linux, but
+     * waitpid() is more standard, so use it on all POSIX platforms. */
+    int status;
+    /* Wait for the child process to exit.  This returns immediately if
+       the child has already exited. */
+    while (waitpid(pid, &status, 0) < 0) {
+        switch (errno) {
+        case ECHILD: return 0;
+        case EINTR: break;
+        default: return -1;
+        }
+    }
+
+    if (WIFEXITED(status)) {
+        /*
+         * The child exited normally; get its exit code.
+         */
+        return WEXITSTATUS(status);
+    } else if (WIFSIGNALED(status)) {
+        /* The child exited because of a signal.
+         * The best value to return is 0x80 + signal number,
+         * because that is what all Unix shells do, and because
+         * it allows callers to distinguish between process exit and
+         * process death by signal.
+         * Unfortunately, the historical behavior on Solaris is to return
+         * the signal number, and we preserve this for compatibility. */
+#ifdef __solaris__
+        return WTERMSIG(status);
+#else
+        return 0x80 + WTERMSIG(status);
+#endif
+    } else {
+        /*
+         * Unknown exit code; pass it through.
+         */
+        return status;
+    }
+}
+
+
--- a/jdk/src/java.base/unix/native/libjava/ProcessImpl_md.c	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/unix/native/libjava/ProcessImpl_md.c	Wed Jul 05 20:37:09 2017 +0200
@@ -226,52 +226,6 @@
 #define WTERMSIG(status) ((status)&0x7F)
 #endif
 
-/* Block until a child process exits and return its exit code.
-   Note, can only be called once for any given pid. */
-JNIEXPORT jint JNICALL
-Java_java_lang_ProcessImpl_waitForProcessExit(JNIEnv* env,
-                                              jobject junk,
-                                              jint pid)
-{
-    /* We used to use waitid() on Solaris, waitpid() on Linux, but
-     * waitpid() is more standard, so use it on all POSIX platforms. */
-    int status;
-    /* Wait for the child process to exit.  This returns immediately if
-       the child has already exited. */
-    while (waitpid(pid, &status, 0) < 0) {
-        switch (errno) {
-        case ECHILD: return 0;
-        case EINTR: break;
-        default: return -1;
-        }
-    }
-
-    if (WIFEXITED(status)) {
-        /*
-         * The child exited normally; get its exit code.
-         */
-        return WEXITSTATUS(status);
-    } else if (WIFSIGNALED(status)) {
-        /* The child exited because of a signal.
-         * The best value to return is 0x80 + signal number,
-         * because that is what all Unix shells do, and because
-         * it allows callers to distinguish between process exit and
-         * process death by signal.
-         * Unfortunately, the historical behavior on Solaris is to return
-         * the signal number, and we preserve this for compatibility. */
-#ifdef __solaris__
-        return WTERMSIG(status);
-#else
-        return 0x80 + WTERMSIG(status);
-#endif
-    } else {
-        /*
-         * Unknown exit code; pass it through.
-         */
-        return status;
-    }
-}
-
 static const char *
 getBytes(JNIEnv *env, jbyteArray arr)
 {
@@ -686,12 +640,3 @@
     goto Finally;
 }
 
-JNIEXPORT void JNICALL
-Java_java_lang_ProcessImpl_destroyProcess(JNIEnv *env,
-                                          jobject junk,
-                                          jint pid,
-                                          jboolean force)
-{
-    int sig = (force == JNI_TRUE) ? SIGKILL : SIGTERM;
-    kill(pid, sig);
-}
--- a/jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c	Wed Jul 05 20:37:09 2017 +0200
@@ -1294,11 +1294,11 @@
 
 /*
  * Class:     java_net_PlainDatagramSocketImpl
- * Method:    socketSetOption
+ * Method:    socketSetOption0
  * Signature: (ILjava/lang/Object;)V
  */
 JNIEXPORT void JNICALL
-Java_java_net_PlainDatagramSocketImpl_socketSetOption(JNIEnv *env,
+Java_java_net_PlainDatagramSocketImpl_socketSetOption0(JNIEnv *env,
                                                       jobject this,
                                                       jint opt,
                                                       jobject value) {
--- a/jdk/src/java.base/unix/native/libnet/PlainSocketImpl.c	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/unix/native/libnet/PlainSocketImpl.c	Wed Jul 05 20:37:09 2017 +0200
@@ -847,11 +847,11 @@
 
 /*
  * Class:     java_net_PlainSocketImpl
- * Method:    socketSetOption
+ * Method:    socketSetOption0
  * Signature: (IZLjava/lang/Object;)V
  */
 JNIEXPORT void JNICALL
-Java_java_net_PlainSocketImpl_socketSetOption(JNIEnv *env, jobject this,
+Java_java_net_PlainSocketImpl_socketSetOption0(JNIEnv *env, jobject this,
                                               jint cmd, jboolean on,
                                               jobject value) {
     int fd;
--- a/jdk/src/java.base/unix/native/libnet/net_util_md.c	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/unix/native/libnet/net_util_md.c	Wed Jul 05 20:37:09 2017 +0200
@@ -1023,12 +1023,10 @@
 
     int i;
 
-    /*
-     * Different multicast options if IPv6 is enabled
-     */
 #ifdef AF_INET6
     if (ipv6_available()) {
         switch (cmd) {
+            // Different multicast options if IPv6 is enabled
             case java_net_SocketOptions_IP_MULTICAST_IF:
             case java_net_SocketOptions_IP_MULTICAST_IF2:
                 *level = IPPROTO_IPV6;
@@ -1039,6 +1037,13 @@
                 *level = IPPROTO_IPV6;
                 *optname = IPV6_MULTICAST_LOOP;
                 return 0;
+#if (defined(__solaris__) || defined(MACOSX))
+            // Map IP_TOS request to IPV6_TCLASS
+            case java_net_SocketOptions_IP_TOS:
+                *level = IPPROTO_IPV6;
+                *optname = IPV6_TCLASS;
+                return 0;
+#endif
         }
     }
 #endif
@@ -1214,9 +1219,6 @@
  * Wrapper for getsockopt system routine - does any necessary
  * pre/post processing to deal with OS specific oddities :-
  *
- * IP_TOS is a no-op with IPv6 sockets as it's setup when
- * the connection is established.
- *
  * On Linux the SO_SNDBUF/SO_RCVBUF values must be post-processed
  * to compensate for an incorrect value returned by the kernel.
  */
@@ -1227,21 +1229,6 @@
     int rv;
     socklen_t socklen = *len;
 
-#ifdef AF_INET6
-    if ((level == IPPROTO_IP) && (opt == IP_TOS)) {
-        if (ipv6_available()) {
-
-            /*
-             * For IPv6 socket option implemented at Java-level
-             * so return -1.
-             */
-            int *tc = (int *)result;
-            *tc = -1;
-            return 0;
-        }
-    }
-#endif
-
     rv = getsockopt(fd, level, opt, result, &socklen);
     *len = socklen;
 
@@ -1285,8 +1272,7 @@
  *
  * For IP_TOS socket option need to mask off bits as this
  * aren't automatically masked by the kernel and results in
- * an error. In addition IP_TOS is a NOOP with IPv6 as it
- * should be setup as connection time.
+ * an error.
  */
 int
 NET_SetSockOpt(int fd, int level, int  opt, const void *arg,
@@ -1317,9 +1303,9 @@
 
     /*
      * IPPROTO/IP_TOS :-
-     * 1. IPv6 on Solaris/Mac OS: NOOP and will be set
-     *    in flowinfo field when connecting TCP socket,
-     *    or sending UDP packet.
+     * 1. IPv6 on Solaris/Mac OS:
+     *    Set the TOS OR Traffic Class value to cater for
+     *    IPv6 and IPv4 scenarios.
      * 2. IPv6 on Linux: By default Linux ignores flowinfo
      *    field so enable IPV6_FLOWINFO_SEND so that flowinfo
      *    will be examined. We also set the IPv4 TOS option in this case.
@@ -1329,12 +1315,6 @@
     if (level == IPPROTO_IP && opt == IP_TOS) {
         int *iptos;
 
-#if defined(AF_INET6) && (defined(__solaris__) || defined(MACOSX))
-        if (ipv6_available()) {
-            return 0;
-        }
-#endif
-
 #if defined(AF_INET6) && defined(__linux__)
         if (ipv6_available()) {
             int optval = 1;
@@ -1342,6 +1322,16 @@
                            (void *)&optval, sizeof(optval)) < 0) {
                 return -1;
             }
+           /*
+            * Let's also set the IPV6_TCLASS flag.
+            * Linux appears to allow both IP_TOS and IPV6_TCLASS to be set
+            * This helps in mixed environments where IPv4 and IPv6 sockets
+            * are connecting.
+            */
+           if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS,
+                           arg, len) < 0) {
+                return -1;
+            }
         }
 #endif
 
@@ -1435,7 +1425,7 @@
      * On Linux the receive buffer is used for both socket
      * structures and the packet payload. The implication
      * is that if SO_RCVBUF is too small then small packets
-     * must be discard.
+     * must be discarded.
      */
 #ifdef __linux__
     if (level == SOL_SOCKET && opt == SO_RCVBUF) {
@@ -1619,7 +1609,7 @@
  * NET_WAIT_READ, NET_WAIT_WRITE & NET_WAIT_CONNECT.
  *
  * The function will return when either the socket is ready for one
- * of the specified operation or the timeout expired.
+ * of the specified operations or the timeout expired.
  *
  * It returns the time left from the timeout (possibly 0), or -1 if it expired.
  */
--- a/jdk/src/java.base/windows/classes/java/lang/ProcessImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/windows/classes/java/lang/ProcessImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,10 +34,12 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.lang.Override;
 import java.lang.ProcessBuilder.Redirect;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.ArrayList;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -53,6 +55,9 @@
     private static final sun.misc.JavaIOFileDescriptorAccess fdAccess
         = sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess();
 
+    // Windows platforms support a forcible kill signal.
+    static final boolean SUPPORTS_NORMAL_TERMINATION = false;
+
     /**
      * Open a file for writing. If {@code append} is {@code true} then the file
      * is opened for atomic append directly and a FileOutputStream constructed
@@ -306,7 +311,8 @@
     }
 
 
-    private long handle = 0;
+    private final long handle;
+    private final ProcessHandle processHandle;
     private OutputStream stdin_stream;
     private InputStream stdout_stream;
     private InputStream stderr_stream;
@@ -385,6 +391,7 @@
 
         handle = create(cmdstr, envblock, path,
                         stdHandles, redirectErrorStream);
+        processHandle = ProcessHandleImpl.getUnchecked(getProcessId0(handle));
 
         java.security.AccessController.doPrivileged(
         new java.security.PrivilegedAction<Void>() {
@@ -481,7 +488,30 @@
     private static native void waitForTimeoutInterruptibly(
         long handle, long timeout);
 
-    public void destroy() { terminateProcess(handle); }
+    @Override
+    public void destroy() {
+        terminateProcess(handle);
+    }
+
+    @Override
+    public CompletableFuture<Process> onExit() {
+        return ProcessHandleImpl.completion(getPid(), false)
+                .handleAsync((exitStatus, unusedThrowable) -> this);
+    }
+
+    @Override
+    public ProcessHandle toHandle() {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(new RuntimePermission("manageProcess"));
+        }
+        return processHandle;
+    }
+
+    @Override
+    public boolean supportsNormalTermination() {
+        return ProcessImpl.SUPPORTS_NORMAL_TERMINATION;
+    }
 
     @Override
     public Process destroyForcibly() {
@@ -493,8 +523,7 @@
 
     @Override
     public long getPid() {
-        int pid = getProcessId0(handle);
-        return pid;
+        return processHandle.getPid();
     }
 
     private static native int getProcessId0(long handle);
@@ -538,7 +567,7 @@
      * Opens a file for atomic append. The file is created if it doesn't
      * already exist.
      *
-     * @param file the file to open or create
+     * @param path the file to open or create
      * @return the native HANDLE
      */
     private static native long openForAtomicAppend(String path)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/windows/native/libjava/ProcessHandleImpl_win.c	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,434 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.
+ */
+
+
+#include "jni.h"
+#include "jvm.h"
+#include "jni_util.h"
+#include "java_lang_ProcessHandleImpl.h"
+#include "java_lang_ProcessHandleImpl_Info.h"
+
+#include <windows.h>
+#include <tlhelp32.h>
+#include <sddl.h>
+
+static void getStatInfo(JNIEnv *env, HANDLE handle, jobject jinfo);
+static void getCmdlineInfo(JNIEnv *env, HANDLE handle, jobject jinfo);
+static void procToUser(JNIEnv *env, HANDLE handle, jobject jinfo);
+
+/**************************************************************
+ * Implementation of ProcessHandleImpl_Info native methods.
+ */
+
+/* Field id for jString 'command' in java.lang.ProcessHandle.Info */
+static jfieldID ProcessHandleImpl_Info_commandID;
+
+/* Field id for jString[] 'arguments' in java.lang.ProcessHandle.Info */
+static jfieldID ProcessHandleImpl_Info_argumentsID;
+
+/* Field id for jlong 'totalTime' in java.lang.ProcessHandle.Info */
+static jfieldID ProcessHandleImpl_Info_totalTimeID;
+
+/* Field id for jlong 'startTime' in java.lang.ProcessHandle.Info */
+static jfieldID ProcessHandleImpl_Info_startTimeID;
+
+/* Field id for jString 'accountName' in java.lang.ProcessHandleImpl.UserPrincipal */
+static jfieldID ProcessHandleImpl_Info_userID;
+
+/**************************************************************
+ * Static method to initialize field IDs.
+ *
+ * Class:     java_lang_ProcessHandleImpl_Info
+ * Method:    initIDs
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_java_lang_ProcessHandleImpl_00024Info_initIDs
+  (JNIEnv *env, jclass clazz) {
+
+    CHECK_NULL(ProcessHandleImpl_Info_commandID = (*env)->GetFieldID(env,
+        clazz, "command", "Ljava/lang/String;"));
+    CHECK_NULL(ProcessHandleImpl_Info_argumentsID = (*env)->GetFieldID(env,
+        clazz, "arguments", "[Ljava/lang/String;"));
+    CHECK_NULL(ProcessHandleImpl_Info_totalTimeID = (*env)->GetFieldID(env,
+        clazz, "totalTime", "J"));
+    CHECK_NULL(ProcessHandleImpl_Info_startTimeID = (*env)->GetFieldID(env,
+        clazz, "startTime", "J"));
+    CHECK_NULL(ProcessHandleImpl_Info_userID = (*env)->GetFieldID(env,
+        clazz, "user", "Ljava/lang/String;"));
+}
+
+/*
+ * Block until a child process exits and return its exit code.
+ */
+JNIEXPORT jint JNICALL
+Java_java_lang_ProcessHandleImpl_waitForProcessExit0(JNIEnv* env,
+                                              jclass junk,
+                                              jlong jpid,
+                                              jboolean reapStatus) {
+    DWORD pid = (DWORD)jpid;
+    DWORD exitValue = -1;
+    HANDLE handle = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_LIMITED_INFORMATION,
+                                FALSE, pid);
+    if (handle == NULL) {
+        return exitValue;          // No process with that pid is alive
+    }
+    do {
+        if (!GetExitCodeProcess(handle, &exitValue)) {
+            JNU_ThrowByNameWithLastError(env,
+                "java/lang/Runtime", "GetExitCodeProcess");
+            break;
+        }
+        if (exitValue == STILL_ACTIVE) {
+            HANDLE events[2];
+            events[0] = handle;
+            events[1] = JVM_GetThreadInterruptEvent();
+
+            if (WaitForMultipleObjects(sizeof(events)/sizeof(events[0]), events,
+                                       FALSE,    /* Wait for ANY event */
+                                       INFINITE) /* Wait forever */
+                == WAIT_FAILED) {
+                JNU_ThrowByNameWithLastError(env,
+                    "java/lang/Runtime", "WaitForMultipleObjects");
+                break;
+            }
+        }
+    } while (exitValue == STILL_ACTIVE);
+    CloseHandle(handle);         // Ignore return code
+    return exitValue;
+}
+
+/*
+ * Returns the pid of the caller.
+ *
+ * Class:     java_lang_ProcessHandleImpl
+ * Method:    getCurrentPid0
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_java_lang_ProcessHandleImpl_getCurrentPid0
+(JNIEnv *env, jclass clazz) {
+    DWORD  pid = GetCurrentProcessId();
+    return (jlong)pid;
+}
+
+/*
+ * Returns the parent pid of the requested pid.
+ *
+ * Class:     java_lang_ProcessHandleImpl
+ * Method:    parent0
+ * Signature: (J)J
+ */
+JNIEXPORT jlong JNICALL Java_java_lang_ProcessHandleImpl_parent0
+(JNIEnv *env, jclass clazz, jlong jpid) {
+
+    DWORD ppid = -1;
+    DWORD wpid = (DWORD)jpid;
+    PROCESSENTRY32 pe32;
+    HANDLE hProcessSnap;
+
+    // Take a snapshot of all processes in the system.
+    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+    if (hProcessSnap == INVALID_HANDLE_VALUE) {
+        JNU_ThrowByName(env,
+            "java/lang/RuntimeException", "snapshot not available");
+        return -1;
+    }
+
+    // Retrieve information about the first process,
+    pe32.dwSize = sizeof (PROCESSENTRY32);
+    if (Process32First(hProcessSnap, &pe32)) {
+        // Now walk the snapshot of processes, and
+        do {
+            if (wpid == pe32.th32ProcessID) {
+                ppid = pe32.th32ParentProcessID;
+                break;
+            }
+        } while (Process32Next(hProcessSnap, &pe32));
+    } else {
+        JNU_ThrowByName(env,
+            "java/lang/RuntimeException", "snapshot not available");
+        return -1;
+    }
+    CloseHandle(hProcessSnap); // Ignore return code
+    return (jlong)ppid;
+}
+
+/*
+ * Returns the children of the requested pid and optionally each parent.
+ *
+ * Class:     java_lang_ProcessHandleImpl
+ * Method:    getChildPids
+ * Signature: (J[J[J)I
+ */
+JNIEXPORT jint JNICALL Java_java_lang_ProcessHandleImpl_getProcessPids0
+(JNIEnv *env, jclass clazz, jlong jpid,
+    jlongArray jarray, jlongArray jparentArray) {
+
+    HANDLE hProcessSnap;
+    PROCESSENTRY32 pe32;
+    DWORD ppid = (DWORD)jpid;
+    size_t count = 0;
+    jlong* pids = NULL;
+    jlong* ppids = NULL;
+    size_t parentArraySize = 0;
+    size_t arraySize = 0;
+
+    arraySize = (*env)->GetArrayLength(env, jarray);
+    JNU_CHECK_EXCEPTION_RETURN(env, -1);
+    if (jparentArray != NULL) {
+        parentArraySize = (*env)->GetArrayLength(env, jparentArray);
+        JNU_CHECK_EXCEPTION_RETURN(env, -1);
+
+        if (arraySize != parentArraySize) {
+            JNU_ThrowIllegalArgumentException(env, "array sizes not equal");
+            return 0;
+        }
+    }
+
+    // Take a snapshot of all processes in the system.
+    hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+    if (hProcessSnap == INVALID_HANDLE_VALUE) {
+        JNU_ThrowByName(env,
+            "java/lang/RuntimeException", "snapshot not available");
+        return 0;
+    }
+
+    // Retrieve information about the first process,
+    pe32.dwSize = sizeof (PROCESSENTRY32);
+    if (Process32First(hProcessSnap, &pe32)) {
+        do { // Block to break out of on Exception
+            pids = (*env)->GetLongArrayElements(env, jarray, NULL);
+            if (pids == NULL) {
+                break;
+            }
+            if (jparentArray != NULL) {
+                ppids  = (*env)->GetLongArrayElements(env, jparentArray, NULL);
+                if (ppids == NULL) {
+                    break;
+                }
+            }
+            // Now walk the snapshot of processes, and
+            // save information about each process in turn
+            do {
+                if (ppid == 0 ||
+                    (pe32.th32ParentProcessID > 0
+                    && (pe32.th32ParentProcessID == ppid))) {
+                    if (count < arraySize) {
+                        // Only store if it fits
+                        pids[count] = (jlong)pe32.th32ProcessID;
+                        if (ppids != NULL) {
+                            // Store the parentPid
+                            ppids[count] = (jlong) pe32.th32ParentProcessID;
+                        }
+                    }
+                    count++;    // Count to tabulate size needed
+                }
+            } while (Process32Next(hProcessSnap, &pe32));
+        } while (0);
+
+        if (pids != NULL) {
+            (*env)->ReleaseLongArrayElements(env, jarray, pids, 0);
+        }
+        if (ppids != NULL) {
+            (*env)->ReleaseLongArrayElements(env, jparentArray, ppids, 0);
+        }
+    } else {
+        JNU_ThrowByName(env,
+            "java/lang/RuntimeException", "snapshot not available");
+        return 0;
+    }
+    CloseHandle(hProcessSnap);
+    // If more pids than array had size for;  count will be greater than array size
+    return (jint)count;
+}
+
+/*
+ * Destroy the process.
+ *
+ * Class:     java_lang_ProcessHandleImpl
+ * Method:    destroy0
+ * Signature: (Z)V
+ */
+JNIEXPORT jboolean JNICALL Java_java_lang_ProcessHandleImpl_destroy0
+(JNIEnv *env, jclass clazz, jlong jpid, jboolean force) {
+    DWORD pid = (DWORD)jpid;
+    HANDLE handle = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
+    if (handle != NULL) {
+        TerminateProcess(handle, 1);
+        CloseHandle(handle);         // Ignore return code
+        return JNI_TRUE;
+    }
+    return JNI_FALSE;
+}
+
+/*
+ * Class:     java_lang_ProcessHandleImpl
+ * Method:    isAlive0
+ * Signature: (J)Z
+ */
+JNIEXPORT jboolean JNICALL Java_java_lang_ProcessHandleImpl_isAlive0
+(JNIEnv *env, jclass clazz, jlong jpid) {
+    DWORD pid = (DWORD)jpid;
+
+    jboolean ret = JNI_FALSE;
+    HANDLE handle =
+        OpenProcess(THREAD_QUERY_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION,
+                    FALSE, pid);
+    if (handle != NULL) {
+        DWORD dwExitStatus;
+
+        GetExitCodeProcess(handle, &dwExitStatus);
+        CloseHandle(handle); // Ignore return code
+        ret = (dwExitStatus == STILL_ACTIVE);
+    }
+    return ret;
+}
+
+/**
+ * Assemble a 64 bit value from two 32 bit values.
+ */
+static jlong jlong_from(jint high, jint low) {
+    jlong result = 0;
+    result = ((jlong)high << 32) | ((0x000000000ffffffff) & (jlong)low);
+    return result;
+}
+
+/*
+ * Fill in the Info object from the OS information about the process.
+ *
+ * Class:     java_lang_ProcessHandleImpl
+ * Method:    info0
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_java_lang_ProcessHandleImpl_00024Info_info0
+  (JNIEnv *env, jobject jinfo, jlong jpid) {
+    DWORD pid = (DWORD)jpid;
+    int ret = 0;
+    HANDLE handle =
+        OpenProcess(THREAD_QUERY_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION,
+                    FALSE, pid);
+    if (handle == NULL) {
+        return;
+    }
+    getStatInfo(env, handle, jinfo);
+    getCmdlineInfo(env, handle, jinfo);
+    procToUser(env, handle, jinfo);
+
+    CloseHandle(handle);                // Ignore return code
+}
+
+/**
+ * Read /proc/<pid>/stat and fill in the fields of the Info object.
+ * The executable name, plus the user, system, and start times are gathered.
+ */
+static void getStatInfo(JNIEnv *env, HANDLE handle, jobject jinfo) {
+    FILETIME CreationTime;
+    FILETIME ExitTime;
+    FILETIME KernelTime;
+    FILETIME UserTime;
+    jlong userTime;             // nanoseconds
+    jlong totalTime;            // nanoseconds
+    jlong startTime;            // nanoseconds
+    UserTime.dwHighDateTime = 0;
+    UserTime.dwLowDateTime = 0;
+    KernelTime.dwHighDateTime = 0;
+    KernelTime.dwLowDateTime = 0;
+    CreationTime.dwHighDateTime = 0;
+    CreationTime.dwLowDateTime = 0;
+
+    if (GetProcessTimes(handle, &CreationTime, &ExitTime, &KernelTime, &UserTime)) {
+        userTime = jlong_from(UserTime.dwHighDateTime, UserTime.dwLowDateTime);
+        totalTime = jlong_from( KernelTime.dwHighDateTime, KernelTime.dwLowDateTime);
+        totalTime = (totalTime + userTime) * 100;  // convert sum to nano-seconds
+
+        startTime = jlong_from(CreationTime.dwHighDateTime,
+                               CreationTime.dwLowDateTime) / 10000;
+        startTime -= 11644473600000L; // Rebase Epoch from 1601 to 1970
+
+        (*env)->SetLongField(env, jinfo,
+                             ProcessHandleImpl_Info_totalTimeID, totalTime);
+        JNU_CHECK_EXCEPTION(env);
+        (*env)->SetLongField(env, jinfo,
+                             ProcessHandleImpl_Info_startTimeID, startTime);
+        JNU_CHECK_EXCEPTION(env);
+    }
+}
+
+static void getCmdlineInfo(JNIEnv *env, HANDLE handle, jobject jinfo) {
+    char exeName[1024];
+    int bufsize = sizeof exeName;
+    jstring commandObj;
+
+    if (QueryFullProcessImageName(handle, 0,  exeName, &bufsize)) {
+        commandObj = (*env)->NewStringUTF(env, exeName);
+        CHECK_NULL(commandObj);
+        (*env)->SetObjectField(env, jinfo,
+                               ProcessHandleImpl_Info_commandID, commandObj);
+    }
+}
+
+static void procToUser(JNIEnv *env, HANDLE handle, jobject jinfo) {
+#define TOKEN_LEN 256
+    DWORD token_len = TOKEN_LEN;
+    char token_buf[TOKEN_LEN];
+    TOKEN_USER *token_user = (TOKEN_USER*)token_buf;
+    HANDLE tokenHandle;
+    WCHAR domain[255 + 1 + 255 + 1];    // large enough to concat with '/' and name
+    WCHAR name[255 + 1];
+    DWORD domainLen = sizeof(domain) - sizeof(name);
+    DWORD nameLen = sizeof(name);
+    SID_NAME_USE use;
+    jstring s;
+    int ret;
+
+    if (!OpenProcessToken(handle, TOKEN_READ, &tokenHandle)) {
+        return;
+    }
+
+    ret = GetTokenInformation(tokenHandle, TokenUser, token_user,
+                              token_len, &token_len);
+    CloseHandle(tokenHandle);           // always close handle
+    if (!ret) {
+        JNU_ThrowByNameWithLastError(env,
+            "java/lang/RuntimeException", "GetTokenInformation");
+        return;
+    }
+
+    if (LookupAccountSidW(NULL, token_user->User.Sid, &name[0], &nameLen,
+                          &domain[0], &domainLen, &use) == 0) {
+        // Name not available, convert to a String
+        LPWSTR str;
+        if (ConvertSidToStringSidW(token_user->User.Sid, &str) == 0) {
+            return;
+        }
+        s = (*env)->NewString(env, (const jchar *)str, (jsize)wcslen(str));
+        LocalFree(str);
+    } else {
+        wcscat(domain, L"\\");
+        wcscat(domain, name);
+        s = (*env)->NewString(env, (const jchar *)domain, (jsize)wcslen(domain));
+    }
+    CHECK_NULL(s);
+    (*env)->SetObjectField(env, jinfo, ProcessHandleImpl_Info_userID, s);
+}
--- a/jdk/src/java.base/windows/native/libjli/java_md.c	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.base/windows/native/libjli/java_md.c	Wed Jul 05 20:37:09 2017 +0200
@@ -44,7 +44,6 @@
 /*
  * Prototypes.
  */
-static jboolean GetPublicJREHome(char *path, jint pathsize);
 static jboolean GetJVMPath(const char *jrepath, const char *jvmtype,
                            char *jvmpath, jint jvmpathsize);
 static jboolean GetJREPath(char *path, jint pathsize);
@@ -334,12 +333,6 @@
         }
     }
 
-    /* Look for a public JRE on this machine. */
-    if (GetPublicJREHome(path, pathsize)) {
-        JLI_TraceLauncher("JRE path is %s\n", path);
-        return JNI_TRUE;
-    }
-
     JLI_ReportErrorMessage(JRE_ERROR8 JAVA_DLL);
     return JNI_FALSE;
 
@@ -426,89 +419,6 @@
 }
 
 /*
- * Helpers to look in the registry for a public JRE.
- */
-                    /* Same for 1.5.0, 1.5.1, 1.5.2 etc. */
-#define JRE_KEY     "Software\\JavaSoft\\Java Runtime Environment"
-
-static jboolean
-GetStringFromRegistry(HKEY key, const char *name, char *buf, jint bufsize)
-{
-    DWORD type, size;
-
-    if (RegQueryValueEx(key, name, 0, &type, 0, &size) == 0
-        && type == REG_SZ
-        && (size < (unsigned int)bufsize)) {
-        if (RegQueryValueEx(key, name, 0, 0, buf, &size) == 0) {
-            return JNI_TRUE;
-        }
-    }
-    return JNI_FALSE;
-}
-
-static jboolean
-GetPublicJREHome(char *buf, jint bufsize)
-{
-    HKEY key, subkey;
-    char version[MAXPATHLEN];
-
-    /*
-     * Note: There is a very similar implementation of the following
-     * registry reading code in the Windows java control panel (javacp.cpl).
-     * If there are bugs here, a similar bug probably exists there.  Hence,
-     * changes here require inspection there.
-     */
-
-    /* Find the current version of the JRE */
-    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, JRE_KEY, 0, KEY_READ, &key) != 0) {
-        JLI_ReportErrorMessage(REG_ERROR1, JRE_KEY);
-        return JNI_FALSE;
-    }
-
-    if (!GetStringFromRegistry(key, "CurrentVersion",
-                               version, sizeof(version))) {
-        JLI_ReportErrorMessage(REG_ERROR2, JRE_KEY);
-        RegCloseKey(key);
-        return JNI_FALSE;
-    }
-
-    if (JLI_StrCmp(version, GetDotVersion()) != 0) {
-        JLI_ReportErrorMessage(REG_ERROR3, JRE_KEY, version, GetDotVersion()
-        );
-        RegCloseKey(key);
-        return JNI_FALSE;
-    }
-
-    /* Find directory where the current version is installed. */
-    if (RegOpenKeyEx(key, version, 0, KEY_READ, &subkey) != 0) {
-        JLI_ReportErrorMessage(REG_ERROR1, JRE_KEY, version);
-        RegCloseKey(key);
-        return JNI_FALSE;
-    }
-
-    if (!GetStringFromRegistry(subkey, "JavaHome", buf, bufsize)) {
-        JLI_ReportErrorMessage(REG_ERROR4, JRE_KEY, version);
-        RegCloseKey(key);
-        RegCloseKey(subkey);
-        return JNI_FALSE;
-    }
-
-    if (JLI_IsTraceLauncher()) {
-        char micro[MAXPATHLEN];
-        if (!GetStringFromRegistry(subkey, "MicroVersion", micro,
-                                   sizeof(micro))) {
-            printf("Warning: Can't read MicroVersion\n");
-            micro[0] = '\0';
-        }
-        printf("Version major.minor.micro = %s.%s\n", version, micro);
-    }
-
-    RegCloseKey(key);
-    RegCloseKey(subkey);
-    return JNI_TRUE;
-}
-
-/*
  * Support for doing cheap, accurate interval timing.
  */
 static jboolean counterAvailable = JNI_FALSE;
--- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaComboBoxPopup.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaComboBoxPopup.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -204,7 +204,8 @@
             if ((p.x + comboBoxBounds.width < 0) || (p.y + comboBoxBounds.height < 0) || (p.x > scrSize.width) || (p.y > scrSize.height)) {
                 return null;
             }
-            return new Rectangle(0, 22, scrSize.width, scrSize.height - 22);
+            Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(comboBox.getGraphicsConfiguration());
+            return new Rectangle(0, insets.top, scrSize.width, scrSize.height - insets.top - insets.bottom);
         }
 
         for (final GraphicsDevice gd : gs) {
@@ -314,10 +315,17 @@
         }
 
         final Rectangle r = new Rectangle(px, py, pw, ph);
-        // Check whether it goes below the bottom of the screen, if so flip it
-        if (r.y + r.height < top.y + scrBounds.y + scrBounds.height) return r;
-
-        return new Rectangle(px, -r.height + comboBoxInsets.top, r.width, r.height);
+        if (py + ph > scrBounds.y + scrBounds.height) {
+            if (ph <= -scrBounds.y ) {
+                // popup goes above
+                r.y = -ph ;
+            } else {
+                // a full screen height popup
+                r.y = scrBounds.y + Math.max(0, (scrBounds.height - ph) / 2 );
+                r.height = Math.min(scrBounds.height, ph);
+            }
+        }
+        return r;
     }
 
     // The one to use when itemCount <= maxRowCount.  Size never adjusts for arrows
--- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaSpinnerUI.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaSpinnerUI.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -232,12 +232,12 @@
         editor.setInheritsPopupMenu(true);
 
         if (editor.getFont() instanceof UIResource) {
-            editor.setFont(spinner.getFont());
+            editor.setFont(new FontUIResource(spinner.getFont()));
         }
 
         final JFormattedTextField editorTextField = ((DefaultEditor)editor).getTextField();
         if (editorTextField.getFont() instanceof UIResource) {
-            editorTextField.setFont(spinner.getFont());
+            editorTextField.setFont(new FontUIResource(spinner.getFont()));
         }
         final InputMap spinnerInputMap = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
         final InputMap editorInputMap = editorTextField.getInputMap();
@@ -648,12 +648,12 @@
                     ui.updateToolTipTextForChildren(spinner);
                 } else if ("font".equals(propertyName)) {
                     JComponent editor = spinner.getEditor();
-                    if (editor != null && editor instanceof JSpinner.DefaultEditor) {
+                    if (editor instanceof JSpinner.DefaultEditor) {
                         JTextField tf =
                                 ((JSpinner.DefaultEditor) editor).getTextField();
                         if (tf != null) {
                             if (tf.getFont() instanceof UIResource) {
-                                tf.setFont(spinner.getFont());
+                                tf.setFont(new FontUIResource(spinner.getFont()));
                             }
                         }
                     }
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWMouseInfoPeer.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWMouseInfoPeer.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -51,8 +51,12 @@
             return false;
         }
 
-        final Object windowPeer = AWTAccessor.getComponentAccessor().getPeer(w);
-        return LWWindowPeer.getWindowUnderCursor() == windowPeer;
+        LWWindowPeer windowPeer = AWTAccessor.getComponentAccessor().getPeer(w);
+        if (windowPeer == null) {
+            return false;
+        }
+
+        return LWToolkit.getLWToolkit().getPlatformWindowUnderMouse() == windowPeer.getPlatformWindow();
     }
 
 }
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWTextAreaPeer.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWTextAreaPeer.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,6 @@
  * questions.
  */
 
-
 package sun.lwawt;
 
 import java.awt.Component;
@@ -40,7 +39,6 @@
 import javax.swing.JTextArea;
 import javax.swing.ScrollPaneConstants;
 import javax.swing.text.Document;
-import javax.swing.text.JTextComponent;
 
 /**
  * Lightweight implementation of {@link TextAreaPeer}. Delegates most of the
@@ -75,12 +73,13 @@
         super.initializeImpl();
         final int visibility = getTarget().getScrollbarVisibility();
         synchronized (getDelegateLock()) {
+            getTextComponent().setWrapStyleWord(true);
             setScrollBarVisibility(visibility);
         }
     }
 
     @Override
-    JTextComponent getTextComponent() {
+    JTextArea getTextComponent() {
         return getDelegate().getView();
     }
 
@@ -165,7 +164,7 @@
             // JTextArea.replaceRange() is called.
             final Document document = getTextComponent().getDocument();
             document.removeDocumentListener(this);
-            getDelegate().getView().replaceRange(text, start, end);
+            getTextComponent().replaceRange(text, start, end);
             revalidate();
             postEvent(new TextEvent(getTarget(), TextEvent.TEXT_VALUE_CHANGED));
             document.addDocumentListener(this);
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWToolkit.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWToolkit.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -396,6 +396,8 @@
         return new LWMouseInfoPeer();
     }
 
+    protected abstract PlatformWindow getPlatformWindowUnderMouse();
+
     @Override
     public final PrintJob getPrintJob(Frame frame, String doctitle,
                                       Properties props) {
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -61,6 +61,7 @@
     private static final int MINIMUM_HEIGHT = 1;
 
     private Insets insets = new Insets(0, 0, 0, 0);
+    private Rectangle maximizedBounds;
 
     private GraphicsDevice graphicsDevice;
     private GraphicsConfiguration graphicsConfig;
@@ -176,8 +177,10 @@
 
 
         if (getTarget() instanceof Frame) {
-            setTitle(((Frame) getTarget()).getTitle());
-            setState(((Frame) getTarget()).getExtendedState());
+            Frame frame = (Frame) getTarget();
+            setTitle(frame.getTitle());
+            setState(frame.getExtendedState());
+            setMaximizedBounds(frame.getMaximizedBounds());
         } else if (getTarget() instanceof Dialog) {
             setTitle(((Dialog) getTarget()).getTitle());
         }
@@ -543,9 +546,40 @@
         return windowState;
     }
 
+    private boolean isMaximizedBoundsSet() {
+        synchronized (getStateLock()) {
+            return maximizedBounds != null;
+        }
+    }
+
+    private Rectangle getDefaultMaximizedBounds() {
+        GraphicsConfiguration config = getGraphicsConfiguration();
+        Insets screenInsets = ((CGraphicsDevice) config.getDevice())
+                .getScreenInsets();
+        Rectangle gcBounds = config.getBounds();
+        return new Rectangle(
+                gcBounds.x + screenInsets.left,
+                gcBounds.y + screenInsets.top,
+                gcBounds.width - screenInsets.left - screenInsets.right,
+                gcBounds.height - screenInsets.top - screenInsets.bottom);
+    }
+
     @Override
     public void setMaximizedBounds(Rectangle bounds) {
-        // TODO: not implemented
+        boolean isMaximizedBoundsSet;
+        synchronized (getStateLock()) {
+            this.maximizedBounds = (isMaximizedBoundsSet = (bounds != null))
+                    ? constrainBounds(bounds) : null;
+        }
+
+        setPlatformMaximizedBounds(isMaximizedBoundsSet ? maximizedBounds
+                : getDefaultMaximizedBounds());
+    }
+
+    private void setPlatformMaximizedBounds(Rectangle bounds) {
+        platformWindow.setMaximizedBounds(
+                bounds.x, bounds.y,
+                bounds.width, bounds.height);
     }
 
     @Override
@@ -635,6 +669,10 @@
 
         // Second, update the graphics config and surface data
         final boolean isNewDevice = updateGraphicsDevice();
+        if (isNewDevice && !isMaximizedBoundsSet()) {
+            setPlatformMaximizedBounds(getDefaultMaximizedBounds());
+        }
+
         if (resized || isNewDevice) {
             replaceSurfaceData();
             updateMinimumSize();
@@ -749,11 +787,10 @@
                 lastMouseEventPeer = targetPeer;
             }
         } else {
-            PlatformWindow topmostPlatforWindow =
-                    platformWindow.getTopmostPlatformWindowUnderMouse();
+            PlatformWindow topmostPlatformWindow = LWToolkit.getLWToolkit().getPlatformWindowUnderMouse();
 
             LWWindowPeer topmostWindowPeer =
-                    topmostPlatforWindow != null ? topmostPlatforWindow.getPeer() : null;
+                    topmostPlatformWindow != null ? topmostPlatformWindow.getPeer() : null;
 
             // topmostWindowPeer == null condition is added for the backward
             // compatibility with applets. It can be removed when the
@@ -764,8 +801,7 @@
                         screenX, screenY, modifiers, clickCount, popupTrigger,
                         targetPeer);
             } else {
-                LWComponentPeer<?, ?> topmostTargetPeer =
-                        topmostWindowPeer != null ? topmostWindowPeer.findPeerAt(r.x + x, r.y + y) : null;
+                LWComponentPeer<?, ?> topmostTargetPeer = topmostWindowPeer.findPeerAt(r.x + x, r.y + y);
                 topmostWindowPeer.generateMouseEnterExitEventsForComponents(when, button, x, y,
                         screenX, screenY, modifiers, clickCount, popupTrigger,
                         topmostTargetPeer);
@@ -1057,6 +1093,9 @@
     public final void displayChanged() {
         if (updateGraphicsDevice()) {
             updateMinimumSize();
+            if (!isMaximizedBoundsSet()) {
+                setPlatformMaximizedBounds(getDefaultMaximizedBounds());
+            }
         }
         // Replace surface unconditionally, because internal state of the
         // GraphicsDevice could be changed.
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/PlatformWindow.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/PlatformWindow.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -67,6 +67,11 @@
     public void setBounds(int x, int y, int w, int h);
 
     /*
+     * Sets the maximized bounds.
+     */
+    public default void setMaximizedBounds(int x, int y, int w, int h){}
+
+    /*
      * Returns the graphics device where the window is.
      */
     public GraphicsDevice getGraphicsDevice();
@@ -107,8 +112,6 @@
 
     public void setAlwaysOnTop(boolean value);
 
-    public PlatformWindow getTopmostPlatformWindowUnderMouse();
-
     public void updateFocusableWindowState();
 
     public boolean rejectFocusRequest(CausedFocusEvent.Cause cause);
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -630,7 +630,7 @@
 
             if (!allowIgnored) {
                 final AccessibleRole role = context.getAccessibleRole();
-                if (role != null && ignoredRoles.contains(roleKey(role))) {
+                if (role != null && ignoredRoles != null && ignoredRoles.contains(roleKey(role))) {
                     // Get the child's unignored children.
                     _addChildren(child, whichChildren, false, childrenAndRoles);
                 } else {
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformEmbeddedFrame.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformEmbeddedFrame.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -129,11 +129,6 @@
     @Override
     public void setAlwaysOnTop(boolean value) {}
 
-    // This method should be properly implemented for applets.
-    // It returns null just as a stub.
-    @Override
-    public PlatformWindow getTopmostPlatformWindowUnderMouse() { return null; }
-
     @Override
     public void updateFocusableWindowState() {}
 
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformLWWindow.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformLWWindow.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -162,11 +162,6 @@
     }
 
     @Override
-    public PlatformWindow getTopmostPlatformWindowUnderMouse(){
-        return null;
-    }
-
-    @Override
     public void setOpacity(float opacity) {
     }
 
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java	Wed Jul 05 20:37:09 2017 +0200
@@ -51,6 +51,8 @@
     private static native void nativeSetNSWindowMenuBar(long nsWindowPtr, long menuBarPtr);
     private static native Insets nativeGetNSWindowInsets(long nsWindowPtr);
     private static native void nativeSetNSWindowBounds(long nsWindowPtr, double x, double y, double w, double h);
+    private static native void nativeSetNSWindowStandardFrame(long nsWindowPtr,
+            double x, double y, double w, double h);
     private static native void nativeSetNSWindowMinMax(long nsWindowPtr, double minW, double minH, double maxW, double maxH);
     private static native void nativePushNSWindowToBack(long nsWindowPtr);
     private static native void nativePushNSWindowToFront(long nsWindowPtr);
@@ -61,9 +63,9 @@
     private static native void nativeSetEnabled(long nsWindowPtr, boolean isEnabled);
     private static native void nativeSynthesizeMouseEnteredExitedEvents();
     private static native void nativeDispose(long nsWindowPtr);
-    private static native CPlatformWindow nativeGetTopmostPlatformWindowUnderMouse();
     private static native void nativeEnterFullScreenMode(long nsWindowPtr);
     private static native void nativeExitFullScreenMode(long nsWindowPtr);
+    static native CPlatformWindow nativeGetTopmostPlatformWindowUnderMouse();
 
     // Loger to report issues happened during execution but that do not affect functionality
     private static final PlatformLogger logger = PlatformLogger.getLogger("sun.lwawt.macosx.CPlatformWindow");
@@ -474,6 +476,10 @@
         nativeSetNSWindowBounds(getNSWindowPtr(), x, y, w, h);
     }
 
+    public void setMaximizedBounds(int x, int y, int w, int h) {
+        nativeSetNSWindowStandardFrame(getNSWindowPtr(), x, y, w, h);
+    }
+
     private boolean isMaximized() {
         return undecorated ? this.normalBounds != null
                 : CWrapper.NSWindow.isZoomed(getNSWindowPtr());
@@ -750,10 +756,6 @@
         setStyleBits(ALWAYS_ON_TOP, isAlwaysOnTop);
     }
 
-    public PlatformWindow getTopmostPlatformWindowUnderMouse(){
-        return CPlatformWindow.nativeGetTopmostPlatformWindowUnderMouse();
-    }
-
     @Override
     public void setOpacity(float opacity) {
         CWrapper.NSWindow.setAlphaValue(getNSWindowPtr(), opacity);
@@ -983,13 +985,11 @@
     }
 
     private void checkZoom() {
-        if (target instanceof Frame && isVisible()) {
-            Frame targetFrame = (Frame)target;
-            if (targetFrame.getExtendedState() != Frame.MAXIMIZED_BOTH && isMaximized()) {
-                deliverZoom(true);
-            } else if (targetFrame.getExtendedState() == Frame.MAXIMIZED_BOTH && !isMaximized()) {
-                deliverZoom(false);
-            }
+        int state = peer.getState();
+        if (state != Frame.MAXIMIZED_BOTH && isMaximized()) {
+            deliverZoom(true);
+        } else if (state == Frame.MAXIMIZED_BOTH && !isMaximized()) {
+            deliverZoom(false);
         }
     }
 
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CRobot.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CRobot.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -78,7 +78,7 @@
     @Override
     public void mousePress(int buttons) {
         mouseButtonsState |= buttons;
-
+        checkMousePos();
         mouseEvent(fDevice.getCGDisplayID(), mouseLastX, mouseLastY,
                    buttons, true, false);
     }
@@ -92,11 +92,40 @@
     @Override
     public void mouseRelease(int buttons) {
         mouseButtonsState &= ~buttons;
-
+        checkMousePos();
         mouseEvent(fDevice.getCGDisplayID(), mouseLastX, mouseLastY,
                    buttons, false, false);
     }
 
+    /**
+     * Set unknown mouse location, if needed.
+     */
+    private void checkMousePos() {
+        if (mouseLastX == MOUSE_LOCATION_UNKNOWN ||
+                mouseLastY == MOUSE_LOCATION_UNKNOWN) {
+
+            Rectangle deviceBounds = fDevice.getDefaultConfiguration().getBounds();
+            Point mousePos = CCursorManager.getInstance().getCursorPosition();
+
+            if (mousePos.x < deviceBounds.x) {
+                mousePos.x = deviceBounds.x;
+            }
+            else if (mousePos.x > deviceBounds.x + deviceBounds.width) {
+                mousePos.x = deviceBounds.x + deviceBounds.width;
+            }
+
+            if (mousePos.y < deviceBounds.y) {
+                mousePos.y = deviceBounds.y;
+            }
+            else if (mousePos.y > deviceBounds.y + deviceBounds.height) {
+                mousePos.y = deviceBounds.y + deviceBounds.height;
+            }
+
+            mouseLastX = mousePos.x;
+            mouseLastY = mousePos.y;
+        }
+    }
+
     @Override
     public native void mouseWheel(int wheelAmt);
 
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CViewPlatformEmbeddedFrame.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CViewPlatformEmbeddedFrame.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -144,11 +144,6 @@
     }
 
     @Override
-    public PlatformWindow getTopmostPlatformWindowUnderMouse() {
-        return null;
-    }
-
-    @Override
     public void updateFocusableWindowState() {
     }
 
--- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java	Wed Jul 05 20:37:09 2017 +0200
@@ -929,4 +929,9 @@
                 !path.endsWith("/") &&
                 !path.endsWith(".");
     }
+
+    @Override
+    protected PlatformWindow getPlatformWindowUnderMouse() {
+        return CPlatformWindow.nativeGetTopmostPlatformWindowUnderMouse();
+    }
 }
--- a/jdk/src/java.desktop/macosx/native/include/jawt_md.h	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/macosx/native/include/jawt_md.h	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.h	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.h	Wed Jul 05 20:37:09 2017 +0200
@@ -46,6 +46,7 @@
     NSWindow *nsWindow;
     AWTWindow *ownerWindow;
     jint preFullScreenLevel;
+    NSRect standardFrame;
 }
 
 // An instance of either AWTWindow_Normal or AWTWindow_Panel
@@ -59,7 +60,7 @@
 @property (nonatomic) jint styleBits;
 @property (nonatomic) BOOL isEnabled;
 @property (nonatomic) jint preFullScreenLevel;
-
+@property (nonatomic) NSRect standardFrame;
 
 - (id) initWithPlatformWindow:(JNFWeakJObjectWrapper *)javaPlatformWindow
                   ownerWindow:owner
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -184,6 +184,7 @@
 @synthesize isEnabled;
 @synthesize ownerWindow;
 @synthesize preFullScreenLevel;
+@synthesize standardFrame;
 
 - (void) updateMinMaxSize:(BOOL)resizable {
     if (resizable) {
@@ -509,6 +510,12 @@
     // window exposing in _setVisible:(BOOL)
 }
 
+- (NSRect)windowWillUseStandardFrame:(NSWindow *)window
+                        defaultFrame:(NSRect)newFrame {
+
+    return [self standardFrame];
+}
+
 - (void) _deliverIconify:(BOOL)iconify {
 AWT_ASSERT_APPKIT_THREAD;
 
@@ -953,6 +960,30 @@
 
 /*
  * Class:     sun_lwawt_macosx_CPlatformWindow
+ * Method:    nativeSetNSWindowStandardFrame
+ * Signature: (JDDDD)V
+ */
+JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeSetNSWindowStandardFrame
+(JNIEnv *env, jclass clazz, jlong windowPtr, jdouble originX, jdouble originY,
+     jdouble width, jdouble height)
+{
+    JNF_COCOA_ENTER(env);
+    
+    NSRect jrect = NSMakeRect(originX, originY, width, height);
+    
+    NSWindow *nsWindow = OBJC(windowPtr);
+    [ThreadUtilities performOnMainThreadWaiting:NO block:^(){
+        
+        NSRect rect = ConvertNSScreenRect(NULL, jrect);
+        AWTWindow *window = (AWTWindow*)[nsWindow delegate];
+        window.standardFrame = rect;
+    }];
+    
+    JNF_COCOA_EXIT(env);
+}
+
+/*
+ * Class:     sun_lwawt_macosx_CPlatformWindow
  * Method:    nativeSetNSWindowMinMax
  * Signature: (JDDDD)V
  */
@@ -1131,15 +1162,16 @@
 JNICALL Java_sun_lwawt_macosx_CPlatformWindow_nativeGetTopmostPlatformWindowUnderMouse
 (JNIEnv *env, jclass clazz)
 {
-    jobject topmostWindowUnderMouse = nil;
+    __block jobject topmostWindowUnderMouse = nil;
 
     JNF_COCOA_ENTER(env);
-    AWT_ASSERT_APPKIT_THREAD;
 
-    AWTWindow *awtWindow = [AWTWindow getTopmostWindowUnderMouse];
-    if (awtWindow != nil) {
-        topmostWindowUnderMouse = [awtWindow.javaPlatformWindow jObject];
-    }
+    [ThreadUtilities performOnMainThreadWaiting:YES block:^{
+        AWTWindow *awtWindow = [AWTWindow getTopmostWindowUnderMouse];
+        if (awtWindow != nil) {
+            topmostWindowUnderMouse = [awtWindow.javaPlatformWindow jObject];
+        }
+    }];
 
     JNF_COCOA_EXIT(env);
 
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CCursorManager.m	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CCursorManager.m	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -118,13 +118,11 @@
 
 JNF_COCOA_ENTER(env);
 
-    __block NSPoint pt = NSZeroPoint;
-    
-    [ThreadUtilities performOnMainThreadWaiting:YES block:^(){
-            pt = ConvertNSScreenPoint(env, [NSEvent mouseLocation]);
-    }];
-    
-    jpt = NSToJavaPoint(env, pt);
+    CGEventRef event = CGEventCreate(NULL);
+    CGPoint globalPos = CGEventGetLocation(event);
+    CFRelease(event);
+
+    jpt = NSToJavaPoint(env, globalPos);
 
 JNF_COCOA_EXIT(env);
 
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobot.m	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobot.m	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -146,47 +146,10 @@
 
     // This is the native method called when Robot mouse events occur.
     // The CRobot tracks the mouse position, and which button was
-    // pressed. If the mouse position is unknown it is obtained from
-    // CGEvents. The peer also tracks the mouse button desired state,
+    // pressed. The peer also tracks the mouse button desired state,
     // the appropriate key modifier state, and whether the mouse action
     // is simply a mouse move with no mouse button state changes.
 
-    CGError err = kCGErrorSuccess;
-
-    CGRect globalDeviceBounds = CGDisplayBounds(displayID);
-
-    // Set unknown mouse location, if needed.
-    if ((mouseLastX == sun_lwawt_macosx_CRobot_MOUSE_LOCATION_UNKNOWN) ||
-        (mouseLastY == sun_lwawt_macosx_CRobot_MOUSE_LOCATION_UNKNOWN))
-    {
-        CGEventRef event = CGEventCreate(NULL);
-        if (event == NULL) {
-            return;
-        }
-
-        CGPoint globalPos = CGEventGetLocation(event);
-        CFRelease(event);
-
-        // Normalize the coords within this display device, as
-        // per Robot rules.
-        if (globalPos.x < CGRectGetMinX(globalDeviceBounds)) {
-            globalPos.x = CGRectGetMinX(globalDeviceBounds);
-        }
-        else if (globalPos.x > CGRectGetMaxX(globalDeviceBounds)) {
-            globalPos.x = CGRectGetMaxX(globalDeviceBounds);
-        }
-
-        if (globalPos.y < CGRectGetMinY(globalDeviceBounds)) {
-            globalPos.y = CGRectGetMinY(globalDeviceBounds);
-        }
-        else if (globalPos.y > CGRectGetMaxY(globalDeviceBounds)) {
-            globalPos.y = CGRectGetMaxY(globalDeviceBounds);
-        }
-
-        mouseLastX = (jint)globalPos.x;
-        mouseLastY = (jint)globalPos.y;
-    }
-
     // volatile, otherwise it warns that it might be clobbered by 'longjmp'
     volatile CGPoint point;
 
--- a/jdk/src/java.desktop/share/classes/com/sun/beans/decoder/ArrayElementHandler.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/beans/decoder/ArrayElementHandler.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 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
--- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKEngine.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKEngine.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -93,7 +93,9 @@
      */
     static enum Settings {
         GTK_FONT_NAME,
-        GTK_ICON_SIZES
+        GTK_ICON_SIZES,
+        GTK_CURSOR_BLINK,
+        GTK_CURSOR_BLINK_TIME
     }
 
     /* Custom regions are needed for representing regions that don't exist
--- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -371,7 +371,17 @@
         int vProgWidth  =  22 - (progXThickness * 2);
         int vProgHeight =  80 - (progYThickness * 2);
 
-        Integer caretBlinkRate = Integer.valueOf(500);
+        Integer caretBlinkRate;
+        if (Boolean.FALSE.equals(GTKEngine.INSTANCE.getSetting(
+                GTKEngine.Settings.GTK_CURSOR_BLINK))) {
+            caretBlinkRate = Integer.valueOf(0);
+        } else {
+            caretBlinkRate = (Integer) GTKEngine.INSTANCE.getSetting(
+                    GTKEngine.Settings.GTK_CURSOR_BLINK_TIME);
+            if (caretBlinkRate == null) {
+                caretBlinkRate = Integer.valueOf(500);
+            }
+        }
         Insets zeroInsets = new InsetsUIResource(0, 0, 0, 0);
 
         Double defaultCaretAspectRatio = new Double(0.025);
--- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -34,9 +34,9 @@
 FileChooser.newFolderNoDirectoryError.textAndMnemonic=Error creating directory "{0}": No such file or directory
 FileChooser.deleteFileButton.textAndMnemonic=De&lete File
 FileChooser.renameFileButton.textAndMnemonic=&Rename File
-FileChooser.cancelButton.textAndMnemonic=&Cancel
-FileChooser.saveButton.textAndMnemonic=&OK
-FileChooser.openButton.textAndMnemonic=&OK
+FileChooser.cancelButton.textAndMnemonic=Cancel
+FileChooser.saveButton.textAndMnemonic=OK
+FileChooser.openButton.textAndMnemonic=OK
 FileChooser.saveDialogTitle.textAndMnemonic=Save
 FileChooser.openDialogTitle.textAndMnemonic=Open
 FileChooser.pathLabel.textAndMnemonic=&Selection:
--- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_de.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_de.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -34,9 +34,9 @@
 FileChooser.newFolderNoDirectoryError.textAndMnemonic=Fehler beim Erstellen von Verzeichnis "{0}": Datei oder Verzeichnis nicht vorhanden
 FileChooser.deleteFileButton.textAndMnemonic=Datei &l\u00F6schen
 FileChooser.renameFileButton.textAndMnemonic=Datei &umbenennen
-FileChooser.cancelButton.textAndMnemonic=&Abbrechen
-FileChooser.saveButton.textAndMnemonic=&OK
-FileChooser.openButton.textAndMnemonic=&OK
+FileChooser.cancelButton.textAndMnemonic=Abbrechen
+FileChooser.saveButton.textAndMnemonic=OK
+FileChooser.openButton.textAndMnemonic=OK
 FileChooser.saveDialogTitle.textAndMnemonic=Speichern
 FileChooser.openDialogTitle.textAndMnemonic=\u00D6ffnen
 FileChooser.pathLabel.textAndMnemonic=Aus&wahl:
--- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_es.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_es.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -34,9 +34,9 @@
 FileChooser.newFolderNoDirectoryError.textAndMnemonic=Error al crear el directorio "{0}": no existe dicho archivo o directorio
 FileChooser.deleteFileButton.textAndMnemonic=Su&primir Archivo
 FileChooser.renameFileButton.textAndMnemonic=Cambiar Nomb&re de Archivo
-FileChooser.cancelButton.textAndMnemonic=&Cancelar
-FileChooser.saveButton.textAndMnemonic=&Aceptar
-FileChooser.openButton.textAndMnemonic=&Aceptar
+FileChooser.cancelButton.textAndMnemonic=Cancelar
+FileChooser.saveButton.textAndMnemonic=Aceptar
+FileChooser.openButton.textAndMnemonic=Aceptar
 FileChooser.saveDialogTitle.textAndMnemonic=Guardar
 FileChooser.openDialogTitle.textAndMnemonic=Abrir
 FileChooser.pathLabel.textAndMnemonic=&Selecci\u00F3n:
--- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_fr.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_fr.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -34,9 +34,9 @@
 FileChooser.newFolderNoDirectoryError.textAndMnemonic=Erreur lors de la cr\u00E9ation du r\u00E9pertoire "{0}" : ce fichier ou r\u00E9pertoire n''existe pas
 FileChooser.deleteFileButton.textAndMnemonic=Supprimer &le fichier
 FileChooser.renameFileButton.textAndMnemonic=&Renommer le fichier
-FileChooser.cancelButton.textAndMnemonic=&Annuler
-FileChooser.saveButton.textAndMnemonic=&OK
-FileChooser.openButton.textAndMnemonic=&OK
+FileChooser.cancelButton.textAndMnemonic=Annuler
+FileChooser.saveButton.textAndMnemonic=OK
+FileChooser.openButton.textAndMnemonic=OK
 FileChooser.saveDialogTitle.textAndMnemonic=Enregistrer
 FileChooser.openDialogTitle.textAndMnemonic=Ouvrir
 FileChooser.pathLabel.textAndMnemonic=&S\u00E9lection :
--- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_it.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_it.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -34,9 +34,9 @@
 FileChooser.newFolderNoDirectoryError.textAndMnemonic=Errore durante la creazione della directory "{0}": file o directory inesistente
 FileChooser.deleteFileButton.textAndMnemonic=E&limina file
 FileChooser.renameFileButton.textAndMnemonic=&Rinomina file
-FileChooser.cancelButton.textAndMnemonic=&Annulla
-FileChooser.saveButton.textAndMnemonic=&OK
-FileChooser.openButton.textAndMnemonic=&OK
+FileChooser.cancelButton.textAndMnemonic=Annulla
+FileChooser.saveButton.textAndMnemonic=OK
+FileChooser.openButton.textAndMnemonic=OK
 FileChooser.saveDialogTitle.textAndMnemonic=Salva
 FileChooser.openDialogTitle.textAndMnemonic=Apri
 FileChooser.pathLabel.textAndMnemonic=&Selezione:
--- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_ja.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_ja.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -34,9 +34,9 @@
 FileChooser.newFolderNoDirectoryError.textAndMnemonic=\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA"{0}"\u306E\u4F5C\u6210\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F: \u3053\u306E\u30D5\u30A1\u30A4\u30EB\u307E\u305F\u306F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306F\u5B58\u5728\u3057\u307E\u305B\u3093
 FileChooser.deleteFileButton.textAndMnemonic=\u30D5\u30A1\u30A4\u30EB\u306E\u524A\u9664(&L)
 FileChooser.renameFileButton.textAndMnemonic=\u30D5\u30A1\u30A4\u30EB\u306E\u540D\u524D\u5909\u66F4(&R)
-FileChooser.cancelButton.textAndMnemonic=\u53D6\u6D88(&C)
-FileChooser.saveButton.textAndMnemonic=OK(&O)
-FileChooser.openButton.textAndMnemonic=OK(&O)
+FileChooser.cancelButton.textAndMnemonic=\u53D6\u6D88
+FileChooser.saveButton.textAndMnemonic=OK
+FileChooser.openButton.textAndMnemonic=OK
 FileChooser.saveDialogTitle.textAndMnemonic=\u4FDD\u5B58
 FileChooser.openDialogTitle.textAndMnemonic=\u958B\u304F
 FileChooser.pathLabel.textAndMnemonic=\u9078\u629E(&S):
--- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_ko.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_ko.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -34,9 +34,9 @@
 FileChooser.newFolderNoDirectoryError.textAndMnemonic="{0}" \uB514\uB809\uD1A0\uB9AC\uB97C \uC0DD\uC131\uD558\uB294 \uC911 \uC624\uB958 \uBC1C\uC0DD: \uD574\uB2F9 \uD30C\uC77C \uB610\uB294 \uB514\uB809\uD1A0\uB9AC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.
 FileChooser.deleteFileButton.textAndMnemonic=\uD30C\uC77C \uC0AD\uC81C(&L)
 FileChooser.renameFileButton.textAndMnemonic=\uD30C\uC77C \uC774\uB984 \uBC14\uAFB8\uAE30(&R)
-FileChooser.cancelButton.textAndMnemonic=\uCDE8\uC18C(&C)
-FileChooser.saveButton.textAndMnemonic=\uD655\uC778(&O)
-FileChooser.openButton.textAndMnemonic=\uD655\uC778(&O)
+FileChooser.cancelButton.textAndMnemonic=\uCDE8\uC18C
+FileChooser.saveButton.textAndMnemonic=\uD655\uC778
+FileChooser.openButton.textAndMnemonic=\uD655\uC778
 FileChooser.saveDialogTitle.textAndMnemonic=\uC800\uC7A5
 FileChooser.openDialogTitle.textAndMnemonic=\uC5F4\uAE30
 FileChooser.pathLabel.textAndMnemonic=\uC120\uD0DD \uC0AC\uD56D(&S):
--- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_pt_BR.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_pt_BR.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -34,9 +34,9 @@
 FileChooser.newFolderNoDirectoryError.textAndMnemonic=Erro ao criar o diret\u00F3rio "{0}": N\u00E3o h\u00E1 arquivo ou diret\u00F3rio
 FileChooser.deleteFileButton.textAndMnemonic=De&letar Arquivo
 FileChooser.renameFileButton.textAndMnemonic=&Renomear Arquivo
-FileChooser.cancelButton.textAndMnemonic=&Cancelar
-FileChooser.saveButton.textAndMnemonic=&OK
-FileChooser.openButton.textAndMnemonic=&OK
+FileChooser.cancelButton.textAndMnemonic=Cancelar
+FileChooser.saveButton.textAndMnemonic=OK
+FileChooser.openButton.textAndMnemonic=OK
 FileChooser.saveDialogTitle.textAndMnemonic=Salvar
 FileChooser.openDialogTitle.textAndMnemonic=Abrir
 FileChooser.pathLabel.textAndMnemonic=&Sele\u00E7\u00E3o:
--- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_sv.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_sv.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -34,9 +34,9 @@
 FileChooser.newFolderNoDirectoryError.textAndMnemonic=Ett fel intr\u00E4ffade vid f\u00F6rs\u00F6k att skapa katalogen "{0}": Filen eller katalogen finns inte
 FileChooser.deleteFileButton.textAndMnemonic=Ta &bort fil
 FileChooser.renameFileButton.textAndMnemonic=&\u00C4ndra namn p\u00E5 filen
-FileChooser.cancelButton.textAndMnemonic=&Avbryt
-FileChooser.saveButton.textAndMnemonic=&OK
-FileChooser.openButton.textAndMnemonic=&OK
+FileChooser.cancelButton.textAndMnemonic=Avbryt
+FileChooser.saveButton.textAndMnemonic=OK
+FileChooser.openButton.textAndMnemonic=OK
 FileChooser.saveDialogTitle.textAndMnemonic=Spara
 FileChooser.openDialogTitle.textAndMnemonic=\u00D6ppna
 FileChooser.pathLabel.textAndMnemonic=&Urval:
--- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_zh_CN.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_zh_CN.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -34,9 +34,9 @@
 FileChooser.newFolderNoDirectoryError.textAndMnemonic=\u521B\u5EFA\u76EE\u5F55 "{0}" \u65F6\u51FA\u9519: \u6CA1\u6709\u6B64\u7C7B\u6587\u4EF6\u6216\u76EE\u5F55
 FileChooser.deleteFileButton.textAndMnemonic=\u5220\u9664\u6587\u4EF6(&L)
 FileChooser.renameFileButton.textAndMnemonic=\u91CD\u547D\u540D\u6587\u4EF6(&R)
-FileChooser.cancelButton.textAndMnemonic=\u53D6\u6D88(&C)
-FileChooser.saveButton.textAndMnemonic=\u786E\u5B9A(&O)
-FileChooser.openButton.textAndMnemonic=\u786E\u5B9A(&O)
+FileChooser.cancelButton.textAndMnemonic=\u53D6\u6D88
+FileChooser.saveButton.textAndMnemonic=\u786E\u5B9A
+FileChooser.openButton.textAndMnemonic=\u786E\u5B9A
 FileChooser.saveDialogTitle.textAndMnemonic=\u4FDD\u5B58
 FileChooser.openDialogTitle.textAndMnemonic=\u6253\u5F00
 FileChooser.pathLabel.textAndMnemonic=\u9009\u5B9A\u5185\u5BB9(&S):
--- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_zh_TW.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_zh_TW.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -34,9 +34,9 @@
 FileChooser.newFolderNoDirectoryError.textAndMnemonic=\u5EFA\u7ACB\u76EE\u9304 "{0}" \u6642\u767C\u751F\u932F\u8AA4: \u6C92\u6709\u6B64\u6A94\u6848\u6216\u76EE\u9304
 FileChooser.deleteFileButton.textAndMnemonic=\u522A\u9664\u6A94\u6848(&L)
 FileChooser.renameFileButton.textAndMnemonic=\u91CD\u65B0\u547D\u540D\u6A94\u6848(&R)
-FileChooser.cancelButton.textAndMnemonic=\u53D6\u6D88(&C)
-FileChooser.saveButton.textAndMnemonic=\u78BA\u5B9A(&O)
-FileChooser.openButton.textAndMnemonic=\u78BA\u5B9A(&O)
+FileChooser.cancelButton.textAndMnemonic=\u53D6\u6D88
+FileChooser.saveButton.textAndMnemonic=\u78BA\u5B9A
+FileChooser.openButton.textAndMnemonic=\u78BA\u5B9A
 FileChooser.saveDialogTitle.textAndMnemonic=\u5132\u5B58
 FileChooser.openDialogTitle.textAndMnemonic=\u958B\u555F
 FileChooser.pathLabel.textAndMnemonic=\u9078\u53D6(&S):
--- a/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -43,13 +43,13 @@
   Specify a different file name.
 FileChooser.acceptAllFileFilter.textAndMnemonic=All Files
 FileChooser.cancelButton.textAndMnemonic=Cancel
-FileChooser.saveButton.textAndMnemonic=&Save
-FileChooser.openButton.textAndMnemonic=&Open
+FileChooser.saveButton.textAndMnemonic=Save
+FileChooser.openButton.textAndMnemonic=Open
 FileChooser.saveDialogTitle.textAndMnemonic=Save
 FileChooser.openDialogTitle.textAndMnemonic=Open
 FileChooser.updateButton.textAndMnemonic=&Update
 FileChooser.helpButton.textAndMnemonic=&Help
-FileChooser.directoryOpenButton.textAndMnemonic=&Open
+FileChooser.directoryOpenButton.textAndMnemonic=Open
 
 # File Size Units
 FileChooser.fileSizeKiloBytes={0} KB
--- a/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_de.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_de.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -42,13 +42,13 @@
 FileChooser.renameErrorFileExists.textAndMnemonic={0} kann nicht umbenannt werden: Es ist bereits eine Datei mit dem angegebenen Namen vorhanden. Geben Sie einen anderen Dateinamen an. 
 FileChooser.acceptAllFileFilter.textAndMnemonic=Alle Dateien
 FileChooser.cancelButton.textAndMnemonic=Abbrechen
-FileChooser.saveButton.textAndMnemonic=&Speichern
-FileChooser.openButton.textAndMnemonic=\u00D6&ffnen
+FileChooser.saveButton.textAndMnemonic=Speichern
+FileChooser.openButton.textAndMnemonic=\u00D6ffnen
 FileChooser.saveDialogTitle.textAndMnemonic=Speichern
 FileChooser.openDialogTitle.textAndMnemonic=\u00D6ffnen
 FileChooser.updateButton.textAndMnemonic=A&ktualisieren
 FileChooser.helpButton.textAndMnemonic=&Hilfe
-FileChooser.directoryOpenButton.textAndMnemonic=\u00D6&ffnen
+FileChooser.directoryOpenButton.textAndMnemonic=\u00D6ffnen
 
 # File Size Units
 FileChooser.fileSizeKiloBytes={0} KB
--- a/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_es.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_es.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -42,13 +42,13 @@
 FileChooser.renameErrorFileExists.textAndMnemonic=No se puede cambiar el nombre de {0}: ya existe un archivo con el nombre especificado. Especifique otro nombre de archivo. 
 FileChooser.acceptAllFileFilter.textAndMnemonic=Todos los Archivos
 FileChooser.cancelButton.textAndMnemonic=Cancelar
-FileChooser.saveButton.textAndMnemonic=&Guardar
-FileChooser.openButton.textAndMnemonic=&Abrir
+FileChooser.saveButton.textAndMnemonic=Guardar
+FileChooser.openButton.textAndMnemonic=Abrir
 FileChooser.saveDialogTitle.textAndMnemonic=Guardar
 FileChooser.openDialogTitle.textAndMnemonic=Abrir
 FileChooser.updateButton.textAndMnemonic=Act&ualizar
 FileChooser.helpButton.textAndMnemonic=A&yuda
-FileChooser.directoryOpenButton.textAndMnemonic=&Abrir
+FileChooser.directoryOpenButton.textAndMnemonic=Abrir
 
 # File Size Units
 FileChooser.fileSizeKiloBytes={0} KB
--- a/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_fr.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_fr.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -42,13 +42,13 @@
 FileChooser.renameErrorFileExists.textAndMnemonic=Impossible de renommer {0} : il existe d\u00E9j\u00E0 un fichier portant le nom indiqu\u00E9. Indiquez-en un autre. 
 FileChooser.acceptAllFileFilter.textAndMnemonic=Tous les fichiers
 FileChooser.cancelButton.textAndMnemonic=Annuler
-FileChooser.saveButton.textAndMnemonic=Enregi&strer
-FileChooser.openButton.textAndMnemonic=&Ouvrir
+FileChooser.saveButton.textAndMnemonic=Enregistrer
+FileChooser.openButton.textAndMnemonic=Ouvrir
 FileChooser.saveDialogTitle.textAndMnemonic=Enregistrer
 FileChooser.openDialogTitle.textAndMnemonic=Ouvrir
 FileChooser.updateButton.textAndMnemonic=Mettre \u00E0 jo&ur
 FileChooser.helpButton.textAndMnemonic=&Aide
-FileChooser.directoryOpenButton.textAndMnemonic=&Ouvrir
+FileChooser.directoryOpenButton.textAndMnemonic=Ouvrir
 
 # File Size Units
 FileChooser.fileSizeKiloBytes={0} KB
--- a/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_it.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_it.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -42,13 +42,13 @@
 FileChooser.renameErrorFileExists.textAndMnemonic=Impossibile rinominare {0}: esiste gi\u00E0 un file con il nome specificato. Specificare un altro nome. 
 FileChooser.acceptAllFileFilter.textAndMnemonic=Tutti i file
 FileChooser.cancelButton.textAndMnemonic=Annulla
-FileChooser.saveButton.textAndMnemonic=Sal&va
-FileChooser.openButton.textAndMnemonic=&Apri
+FileChooser.saveButton.textAndMnemonic=Salva
+FileChooser.openButton.textAndMnemonic=Apri
 FileChooser.saveDialogTitle.textAndMnemonic=Salva
 FileChooser.openDialogTitle.textAndMnemonic=Apri
 FileChooser.updateButton.textAndMnemonic=Ag&giorna
 FileChooser.helpButton.textAndMnemonic=&?
-FileChooser.directoryOpenButton.textAndMnemonic=&Apri
+FileChooser.directoryOpenButton.textAndMnemonic=Apri
 
 # File Size Units
 FileChooser.fileSizeKiloBytes={0} KB
--- a/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_pt_BR.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_pt_BR.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -42,13 +42,13 @@
 FileChooser.renameErrorFileExists.textAndMnemonic=N\u00E3o \u00E9 poss\u00EDvel renomear {0}: Um arquivo com o nome especificado j\u00E1 existe. Especifique outro nome de arquivo.
 FileChooser.acceptAllFileFilter.textAndMnemonic=Todos os Arquivos
 FileChooser.cancelButton.textAndMnemonic=Cancelar
-FileChooser.saveButton.textAndMnemonic=&Salvar
-FileChooser.openButton.textAndMnemonic=A&brir
+FileChooser.saveButton.textAndMnemonic=Salvar
+FileChooser.openButton.textAndMnemonic=Abrir
 FileChooser.saveDialogTitle.textAndMnemonic=Salvar
 FileChooser.openDialogTitle.textAndMnemonic=Abrir
 FileChooser.updateButton.textAndMnemonic=At&ualizar
 FileChooser.helpButton.textAndMnemonic=Aj&uda
-FileChooser.directoryOpenButton.textAndMnemonic=A&brir
+FileChooser.directoryOpenButton.textAndMnemonic=Abrir
 
 # File Size Units
 FileChooser.fileSizeKiloBytes={0} KB
--- a/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_sv.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_sv.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -42,13 +42,13 @@
 FileChooser.renameErrorFileExists.textAndMnemonic=Kan inte namn\u00E4ndra {0}: En fil med angivet namn finns redan. Ange ett annat filnamn. 
 FileChooser.acceptAllFileFilter.textAndMnemonic=Alla filer
 FileChooser.cancelButton.textAndMnemonic=Avbryt
-FileChooser.saveButton.textAndMnemonic=&Spara
-FileChooser.openButton.textAndMnemonic=&\u00D6ppna
+FileChooser.saveButton.textAndMnemonic=Spara
+FileChooser.openButton.textAndMnemonic=\u00D6ppna
 FileChooser.saveDialogTitle.textAndMnemonic=Spara
 FileChooser.openDialogTitle.textAndMnemonic=\u00D6ppna
 FileChooser.updateButton.textAndMnemonic=Upp&datera
 FileChooser.helpButton.textAndMnemonic=&Hj\u00E4lp
-FileChooser.directoryOpenButton.textAndMnemonic=&\u00D6ppna
+FileChooser.directoryOpenButton.textAndMnemonic=\u00D6ppna
 
 # File Size Units
 FileChooser.fileSizeKiloBytes={0} KB
--- a/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -43,8 +43,6 @@
 FileChooser.fileTypeHeader.textAndMnemonic=Type
 FileChooser.fileDateHeader.textAndMnemonic=Modified
 FileChooser.fileAttrHeader.textAndMnemonic=Attributes
-FileChooser.saveButton.textAndMnemonic=Save
-FileChooser.openButton.textAndMnemonic=Open
 
 ############ Used by MetalTitlePane if rendering window decorations############
 MetalTitlePane.restore.titleAndMnemonic=&Restore
--- a/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_de.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_de.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -43,8 +43,6 @@
 FileChooser.fileTypeHeader.textAndMnemonic=Typ
 FileChooser.fileDateHeader.textAndMnemonic=Ge\u00E4ndert
 FileChooser.fileAttrHeader.textAndMnemonic=Attribute
-FileChooser.saveButton.textAndMnemonic=Speichern
-FileChooser.openButton.textAndMnemonic=\u00D6ffnen
 
 ############ Used by MetalTitlePane if rendering window decorations############
 MetalTitlePane.restore.titleAndMnemonic=&Wiederherstellen
--- a/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_es.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_es.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -43,8 +43,6 @@
 FileChooser.fileTypeHeader.textAndMnemonic=Tipo
 FileChooser.fileDateHeader.textAndMnemonic=Modificado
 FileChooser.fileAttrHeader.textAndMnemonic=Atributos
-FileChooser.saveButton.textAndMnemonic=Guardar
-FileChooser.openButton.textAndMnemonic=Abrir
 
 ############ Used by MetalTitlePane if rendering window decorations############
 MetalTitlePane.restore.titleAndMnemonic=&Restaurar
--- a/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_fr.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_fr.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -43,8 +43,6 @@
 FileChooser.fileTypeHeader.textAndMnemonic=Type
 FileChooser.fileDateHeader.textAndMnemonic=Modifi\u00E9
 FileChooser.fileAttrHeader.textAndMnemonic=Attributs
-FileChooser.saveButton.textAndMnemonic=Enregistrer
-FileChooser.openButton.textAndMnemonic=Ouvrir
 
 ############ Used by MetalTitlePane if rendering window decorations############
 MetalTitlePane.restore.titleAndMnemonic=&Restaurer
--- a/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_it.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_it.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -43,8 +43,6 @@
 FileChooser.fileTypeHeader.textAndMnemonic=Tipo
 FileChooser.fileDateHeader.textAndMnemonic=Modificato
 FileChooser.fileAttrHeader.textAndMnemonic=Attributi
-FileChooser.saveButton.textAndMnemonic=Salva
-FileChooser.openButton.textAndMnemonic=Apri
 
 ############ Used by MetalTitlePane if rendering window decorations############
 MetalTitlePane.restore.titleAndMnemonic=&Ripristina
--- a/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_ja.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_ja.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -43,8 +43,6 @@
 FileChooser.fileTypeHeader.textAndMnemonic=\u30BF\u30A4\u30D7
 FileChooser.fileDateHeader.textAndMnemonic=\u4FEE\u6B63\u65E5
 FileChooser.fileAttrHeader.textAndMnemonic=\u5C5E\u6027
-FileChooser.saveButton.textAndMnemonic=\u4FDD\u5B58
-FileChooser.openButton.textAndMnemonic=\u958B\u304F
 
 ############ Used by MetalTitlePane if rendering window decorations############
 MetalTitlePane.restore.titleAndMnemonic=\u5FA9\u5143(&R)
--- a/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_ko.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_ko.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -43,8 +43,6 @@
 FileChooser.fileTypeHeader.textAndMnemonic=\uC720\uD615
 FileChooser.fileDateHeader.textAndMnemonic=\uC218\uC815 \uB0A0\uC9DC
 FileChooser.fileAttrHeader.textAndMnemonic=\uC18D\uC131
-FileChooser.saveButton.textAndMnemonic=\uC800\uC7A5
-FileChooser.openButton.textAndMnemonic=\uC5F4\uAE30
 
 ############ Used by MetalTitlePane if rendering window decorations############
 MetalTitlePane.restore.titleAndMnemonic=\uBCF5\uC6D0(&R)
--- a/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_pt_BR.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_pt_BR.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -43,8 +43,6 @@
 FileChooser.fileTypeHeader.textAndMnemonic=Tipo
 FileChooser.fileDateHeader.textAndMnemonic=Modificado
 FileChooser.fileAttrHeader.textAndMnemonic=Atributos
-FileChooser.saveButton.textAndMnemonic=Salvar
-FileChooser.openButton.textAndMnemonic=Abrir
 
 ############ Used by MetalTitlePane if rendering window decorations############
 MetalTitlePane.restore.titleAndMnemonic=&Restaurar
--- a/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_sv.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_sv.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -43,8 +43,6 @@
 FileChooser.fileTypeHeader.textAndMnemonic=Typ
 FileChooser.fileDateHeader.textAndMnemonic=\u00C4ndrad
 FileChooser.fileAttrHeader.textAndMnemonic=Attribut
-FileChooser.saveButton.textAndMnemonic=Spara
-FileChooser.openButton.textAndMnemonic=\u00D6ppna
 
 ############ Used by MetalTitlePane if rendering window decorations############
 MetalTitlePane.restore.titleAndMnemonic=&\u00C5terst\u00E4ll
--- a/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_zh_CN.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_zh_CN.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -43,8 +43,6 @@
 FileChooser.fileTypeHeader.textAndMnemonic=\u7C7B\u578B
 FileChooser.fileDateHeader.textAndMnemonic=\u4FEE\u6539\u65E5\u671F
 FileChooser.fileAttrHeader.textAndMnemonic=\u5C5E\u6027
-FileChooser.saveButton.textAndMnemonic=\u4FDD\u5B58
-FileChooser.openButton.textAndMnemonic=\u6253\u5F00
 
 ############ Used by MetalTitlePane if rendering window decorations############
 MetalTitlePane.restore.titleAndMnemonic=\u8FD8\u539F(&R)
--- a/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_zh_TW.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_zh_TW.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -43,8 +43,6 @@
 FileChooser.fileTypeHeader.textAndMnemonic=\u985E\u578B
 FileChooser.fileDateHeader.textAndMnemonic=\u4FEE\u6539\u65E5\u671F
 FileChooser.fileAttrHeader.textAndMnemonic=\u5C6C\u6027
-FileChooser.saveButton.textAndMnemonic=\u5132\u5B58
-FileChooser.openButton.textAndMnemonic=\u958B\u555F
 
 ############ Used by MetalTitlePane if rendering window decorations############
 MetalTitlePane.restore.titleAndMnemonic=\u56DE\u5FA9(&R)
--- a/jdk/src/java.desktop/share/classes/java/awt/Component.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/java/awt/Component.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1312,6 +1312,25 @@
     }
 
     /**
+     * Determines the bounds of a visible part of the component relative to its
+     * parent.
+     *
+     * @return the visible part of bounds
+     */
+    private Rectangle getRecursivelyVisibleBounds() {
+        final Component container = getContainer();
+        final Rectangle bounds = getBounds();
+        if (container == null) {
+            // we are top level window or haven't a container, return our bounds
+            return bounds;
+        }
+        // translate the container's bounds to our coordinate space
+        final Rectangle parentsBounds = container.getRecursivelyVisibleBounds();
+        parentsBounds.setLocation(0, 0);
+        return parentsBounds.intersection(bounds);
+    }
+
+    /**
      * Translates absolute coordinates into coordinates in the coordinate
      * space of this component.
      */
@@ -1487,7 +1506,7 @@
                 ComponentPeer peer = this.peer;
                 if (peer != null) {
                     peer.setEnabled(true);
-                    if (visible) {
+                    if (visible && !getRecursivelyVisibleBounds().isEmpty()) {
                         updateCursorImmediately();
                     }
                 }
@@ -1541,7 +1560,7 @@
                 ComponentPeer peer = this.peer;
                 if (peer != null) {
                     peer.setEnabled(false);
-                    if (visible) {
+                    if (visible && !getRecursivelyVisibleBounds().isEmpty()) {
                         updateCursorImmediately();
                     }
                 }
--- a/jdk/src/java.desktop/share/classes/java/awt/Container.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/java/awt/Container.java	Wed Jul 05 20:37:09 2017 +0200
@@ -44,6 +44,7 @@
 import java.lang.ref.WeakReference;
 import java.security.AccessController;
 
+import java.util.ArrayList;
 import java.util.EventListener;
 import java.util.HashSet;
 import java.util.Set;
@@ -100,7 +101,7 @@
      * @see #add
      * @see #getComponents
      */
-    private java.util.List<Component> component = new java.util.ArrayList<Component>();
+    private java.util.List<Component> component = new ArrayList<>();
 
     /**
      * Layout manager for this container.
@@ -2568,28 +2569,24 @@
         if (!contains(x, y)) {
             return null;
         }
+        Component lightweight = null;
         synchronized (getTreeLock()) {
-            // Two passes: see comment in sun.awt.SunGraphicsCallback
-            for (int i = 0; i < component.size(); i++) {
-                Component comp = component.get(i);
-                if (comp != null &&
-                    !(comp.peer instanceof LightweightPeer)) {
-                    if (comp.contains(x - comp.x, y - comp.y)) {
+            // Optimized version of two passes:
+            // see comment in sun.awt.SunGraphicsCallback
+            for (final Component comp : component) {
+                if (comp.contains(x - comp.x, y - comp.y)) {
+                    if (!comp.isLightweight()) {
+                        // return heavyweight component as soon as possible
                         return comp;
                     }
-                }
-            }
-            for (int i = 0; i < component.size(); i++) {
-                Component comp = component.get(i);
-                if (comp != null &&
-                    comp.peer instanceof LightweightPeer) {
-                    if (comp.contains(x - comp.x, y - comp.y)) {
-                        return comp;
+                    if (lightweight == null) {
+                        // save and return later the first lightweight component
+                        lightweight = comp;
                     }
                 }
             }
         }
-        return this;
+        return lightweight != null ? lightweight : this;
     }
 
     /**
@@ -2693,52 +2690,54 @@
         return null;
     }
 
-    final Component findComponentAtImpl(int x, int y, boolean ignoreEnabled){
-        checkTreeLock();
+    final Component findComponentAtImpl(int x, int y, boolean ignoreEnabled) {
+        // checkTreeLock(); commented for a performance reason
 
         if (!(contains(x, y) && visible && (ignoreEnabled || enabled))) {
             return null;
         }
-
-        // Two passes: see comment in sun.awt.SunGraphicsCallback
-        for (int i = 0; i < component.size(); i++) {
-            Component comp = component.get(i);
-            if (comp != null &&
-                !(comp.peer instanceof LightweightPeer)) {
-                if (comp instanceof Container) {
-                    comp = ((Container)comp).findComponentAtImpl(x - comp.x,
-                                                                 y - comp.y,
-                                                                 ignoreEnabled);
-                } else {
-                    comp = comp.getComponentAt(x - comp.x, y - comp.y);
+        Component lightweight = null;
+        // Optimized version of two passes:
+        // see comment in sun.awt.SunGraphicsCallback
+        for (final Component comp : component) {
+            final int x1 = x - comp.x;
+            final int y1 = y - comp.y;
+            if (!comp.contains(x1, y1)) {
+                continue; // fast path
+            }
+            if (!comp.isLightweight()) {
+                final Component child = getChildAt(comp, x1, y1, ignoreEnabled);
+                if (child != null) {
+                    // return heavyweight component as soon as possible
+                    return child;
                 }
-                if (comp != null && comp.visible &&
-                    (ignoreEnabled || comp.enabled))
-                {
-                    return comp;
+            } else {
+                if (lightweight == null) {
+                    // save and return later the first lightweight component
+                    lightweight = getChildAt(comp, x1, y1, ignoreEnabled);
                 }
             }
         }
-        for (int i = 0; i < component.size(); i++) {
-            Component comp = component.get(i);
-            if (comp != null &&
-                comp.peer instanceof LightweightPeer) {
-                if (comp instanceof Container) {
-                    comp = ((Container)comp).findComponentAtImpl(x - comp.x,
-                                                                 y - comp.y,
-                                                                 ignoreEnabled);
-                } else {
-                    comp = comp.getComponentAt(x - comp.x, y - comp.y);
-                }
-                if (comp != null && comp.visible &&
-                    (ignoreEnabled || comp.enabled))
-                {
-                    return comp;
-                }
-            }
+        return lightweight != null ? lightweight : this;
+    }
+
+    /**
+     * Helper method for findComponentAtImpl. Finds a child component using
+     * findComponentAtImpl for Container and getComponentAt for Component.
+     */
+    private static Component getChildAt(Component comp, int x, int y,
+                                        boolean ignoreEnabled) {
+        if (comp instanceof Container) {
+            comp = ((Container) comp).findComponentAtImpl(x, y,
+                                                          ignoreEnabled);
+        } else {
+            comp = comp.getComponentAt(x, y);
         }
-
-        return this;
+        if (comp != null && comp.visible &&
+                (ignoreEnabled || comp.enabled)) {
+            return comp;
+        }
+        return null;
     }
 
     /**
@@ -4420,6 +4419,18 @@
 
     private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.LightweightDispatcher");
 
+    private static final int BUTTONS_DOWN_MASK;
+
+    static {
+        int[] buttonsDownMask = AWTAccessor.getInputEventAccessor().
+                getButtonDownMasks();
+        int mask = 0;
+        for (int buttonDownMask : buttonsDownMask) {
+            mask |= buttonDownMask;
+        }
+        BUTTONS_DOWN_MASK = mask;
+    }
+
     LightweightDispatcher(Container nativeContainer) {
         this.nativeContainer = nativeContainer;
         mouseEventTarget = new WeakReference<>(null);
@@ -4488,25 +4499,12 @@
     private boolean isMouseGrab(MouseEvent e) {
         int modifiers = e.getModifiersEx();
 
-        if(e.getID() == MouseEvent.MOUSE_PRESSED
-            || e.getID() == MouseEvent.MOUSE_RELEASED)
-        {
-            switch (e.getButton()) {
-            case MouseEvent.BUTTON1:
-                modifiers ^= InputEvent.BUTTON1_DOWN_MASK;
-                break;
-            case MouseEvent.BUTTON2:
-                modifiers ^= InputEvent.BUTTON2_DOWN_MASK;
-                break;
-            case MouseEvent.BUTTON3:
-                modifiers ^= InputEvent.BUTTON3_DOWN_MASK;
-                break;
-            }
+        if (e.getID() == MouseEvent.MOUSE_PRESSED
+                || e.getID() == MouseEvent.MOUSE_RELEASED) {
+            modifiers ^= InputEvent.getMaskForButton(e.getButton());
         }
         /* modifiers now as just before event */
-        return ((modifiers & (InputEvent.BUTTON1_DOWN_MASK
-                              | InputEvent.BUTTON2_DOWN_MASK
-                              | InputEvent.BUTTON3_DOWN_MASK)) != 0);
+        return ((modifiers & BUTTONS_DOWN_MASK) != 0);
     }
 
     /**
--- a/jdk/src/java.desktop/share/classes/java/awt/Menu.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/java/awt/Menu.java	Wed Jul 05 20:37:09 2017 +0200
@@ -413,9 +413,9 @@
             items.removeElementAt(index);
             MenuPeer peer = (MenuPeer)this.peer;
             if (peer != null) {
+                peer.delItem(index);
                 mi.removeNotify();
                 mi.parent = null;
-                peer.delItem(index);
             }
         }
     }
--- a/jdk/src/java.desktop/share/classes/java/awt/MenuBar.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/java/awt/MenuBar.java	Wed Jul 05 20:37:09 2017 +0200
@@ -222,7 +222,6 @@
             if (m.parent != null) {
                 m.parent.remove(m);
             }
-            menus.addElement(m);
             m.parent = this;
 
             MenuBarPeer peer = (MenuBarPeer)this.peer;
@@ -232,6 +231,7 @@
                 }
                 peer.addMenu(m);
             }
+            menus.addElement(m);
             return m;
         }
     }
@@ -248,9 +248,9 @@
             menus.removeElementAt(index);
             MenuBarPeer peer = (MenuBarPeer)this.peer;
             if (peer != null) {
+                peer.delMenu(index);
                 m.removeNotify();
                 m.parent = null;
-                peer.delMenu(index);
             }
             if (helpMenu == m) {
                 helpMenu = null;
--- a/jdk/src/java.desktop/share/classes/java/awt/MenuComponent.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/java/awt/MenuComponent.java	Wed Jul 05 20:37:09 2017 +0200
@@ -77,7 +77,7 @@
      * @see #setFont(Font)
      * @see #getFont()
      */
-    Font font;
+    volatile Font font;
 
     /**
      * The menu component's name, which defaults to <code>null</code>.
@@ -302,11 +302,13 @@
      * @see       java.awt.font.TextAttribute
      */
     public void setFont(Font f) {
-        font = f;
-        //Fixed 6312943: NullPointerException in method MenuComponent.setFont(Font)
-        MenuComponentPeer peer = this.peer;
-        if (peer != null) {
-            peer.setFont(f);
+        synchronized (getTreeLock()) {
+            font = f;
+            //Fixed 6312943: NullPointerException in method MenuComponent.setFont(Font)
+            MenuComponentPeer peer = this.peer;
+            if (peer != null) {
+                peer.setFont(f);
+            }
         }
     }
 
--- a/jdk/src/java.desktop/share/classes/java/awt/WaitDispatchSupport.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/java/awt/WaitDispatchSupport.java	Wed Jul 05 20:37:09 2017 +0200
@@ -65,6 +65,7 @@
 
     private AtomicBoolean keepBlockingEDT = new AtomicBoolean(false);
     private AtomicBoolean keepBlockingCT = new AtomicBoolean(false);
+    private AtomicBoolean afterExit = new AtomicBoolean(false);
 
     private static synchronized void initializeTimer() {
         if (timer == null) {
@@ -114,7 +115,7 @@
                 }
                 boolean extEvaluate =
                     (extCondition != null) ? extCondition.evaluate() : true;
-                if (!keepBlockingEDT.get() || !extEvaluate) {
+                if (!keepBlockingEDT.get() || !extEvaluate || afterExit.get()) {
                     if (timerTask != null) {
                         timerTask.cancel();
                         timerTask = null;
@@ -174,110 +175,116 @@
             log.fine("The secondary loop is already running, aborting");
             return false;
         }
+        try {
+            if (afterExit.get()) {
+                log.fine("Exit was called already, aborting");
+                return false;
+            }
 
-        final Runnable run = new Runnable() {
-            public void run() {
-                log.fine("Starting a new event pump");
-                if (filter == null) {
-                    dispatchThread.pumpEvents(condition);
-                } else {
-                    dispatchThread.pumpEventsForFilter(condition, filter);
+            final Runnable run = new Runnable() {
+                public void run() {
+                    log.fine("Starting a new event pump");
+                    if (filter == null) {
+                        dispatchThread.pumpEvents(condition);
+                    } else {
+                        dispatchThread.pumpEventsForFilter(condition, filter);
+                    }
                 }
-            }
-        };
+            };
+
+            // We have two mechanisms for blocking: if we're on the
+            // dispatch thread, start a new event pump; if we're
+            // on any other thread, call wait() on the treelock
 
-        // We have two mechanisms for blocking: if we're on the
-        // dispatch thread, start a new event pump; if we're
-        // on any other thread, call wait() on the treelock
-
-        Thread currentThread = Thread.currentThread();
-        if (currentThread == dispatchThread) {
-            if (log.isLoggable(PlatformLogger.Level.FINEST)) {
-                log.finest("On dispatch thread: " + dispatchThread);
-            }
-            if (interval != 0) {
+            Thread currentThread = Thread.currentThread();
+            if (currentThread == dispatchThread) {
                 if (log.isLoggable(PlatformLogger.Level.FINEST)) {
-                    log.finest("scheduling the timer for " + interval + " ms");
+                    log.finest("On dispatch thread: " + dispatchThread);
+                }
+                if (interval != 0) {
+                    if (log.isLoggable(PlatformLogger.Level.FINEST)) {
+                        log.finest("scheduling the timer for " + interval + " ms");
+                    }
+                    timer.schedule(timerTask = new TimerTask() {
+                        @Override
+                        public void run() {
+                            if (keepBlockingEDT.compareAndSet(true, false)) {
+                                wakeupEDT();
+                            }
+                        }
+                    }, interval);
+                }
+                // Dispose SequencedEvent we are dispatching on the current
+                // AppContext, to prevent us from hang - see 4531693 for details
+                SequencedEvent currentSE = KeyboardFocusManager.
+                        getCurrentKeyboardFocusManager().getCurrentSequencedEvent();
+                if (currentSE != null) {
+                    if (log.isLoggable(PlatformLogger.Level.FINE)) {
+                        log.fine("Dispose current SequencedEvent: " + currentSE);
+                    }
+                    currentSE.dispose();
                 }
-                timer.schedule(timerTask = new TimerTask() {
-                    @Override
-                    public void run() {
-                        if (keepBlockingEDT.compareAndSet(true, false)) {
-                            wakeupEDT();
+                // In case the exit() method is called before starting
+                // new event pump it will post the waking event to EDT.
+                // The event will be handled after the new event pump
+                // starts. Thus, the enter() method will not hang.
+                //
+                // Event pump should be privileged. See 6300270.
+                AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                    public Void run() {
+                        run.run();
+                        return null;
+                    }
+                });
+            } else {
+                if (log.isLoggable(PlatformLogger.Level.FINEST)) {
+                    log.finest("On non-dispatch thread: " + currentThread);
+                }
+                keepBlockingCT.set(true);
+                synchronized (getTreeLock()) {
+                    if (afterExit.get()) return false;
+                    if (filter != null) {
+                        dispatchThread.addEventFilter(filter);
+                    }
+                    try {
+                        EventQueue eq = dispatchThread.getEventQueue();
+                        eq.postEvent(new PeerEvent(this, run, PeerEvent.PRIORITY_EVENT));
+                        if (interval > 0) {
+                            long currTime = System.currentTimeMillis();
+                            while (keepBlockingCT.get() &&
+                                    ((extCondition != null) ? extCondition.evaluate() : true) &&
+                                    (currTime + interval > System.currentTimeMillis()))
+                            {
+                                getTreeLock().wait(interval);
+                            }
+                        } else {
+                            while (keepBlockingCT.get() &&
+                                    ((extCondition != null) ? extCondition.evaluate() : true))
+                            {
+                                getTreeLock().wait();
+                            }
+                        }
+                        if (log.isLoggable(PlatformLogger.Level.FINE)) {
+                            log.fine("waitDone " + keepBlockingEDT.get() + " " + keepBlockingCT.get());
+                        }
+                    } catch (InterruptedException e) {
+                        if (log.isLoggable(PlatformLogger.Level.FINE)) {
+                            log.fine("Exception caught while waiting: " + e);
+                        }
+                    } finally {
+                        if (filter != null) {
+                            dispatchThread.removeEventFilter(filter);
                         }
                     }
-                }, interval);
-            }
-            // Dispose SequencedEvent we are dispatching on the current
-            // AppContext, to prevent us from hang - see 4531693 for details
-            SequencedEvent currentSE = KeyboardFocusManager.
-                getCurrentKeyboardFocusManager().getCurrentSequencedEvent();
-            if (currentSE != null) {
-                if (log.isLoggable(PlatformLogger.Level.FINE)) {
-                    log.fine("Dispose current SequencedEvent: " + currentSE);
                 }
-                currentSE.dispose();
-            }
-            // In case the exit() method is called before starting
-            // new event pump it will post the waking event to EDT.
-            // The event will be handled after the new event pump
-            // starts. Thus, the enter() method will not hang.
-            //
-            // Event pump should be privileged. See 6300270.
-            AccessController.doPrivileged(new PrivilegedAction<Void>() {
-                public Void run() {
-                    run.run();
-                    return null;
-                }
-            });
-        } else {
-            if (log.isLoggable(PlatformLogger.Level.FINEST)) {
-                log.finest("On non-dispatch thread: " + currentThread);
             }
-            synchronized (getTreeLock()) {
-                if (filter != null) {
-                    dispatchThread.addEventFilter(filter);
-                }
-                try {
-                    EventQueue eq = dispatchThread.getEventQueue();
-                    eq.postEvent(new PeerEvent(this, run, PeerEvent.PRIORITY_EVENT));
-                    keepBlockingCT.set(true);
-                    if (interval > 0) {
-                        long currTime = System.currentTimeMillis();
-                        while (keepBlockingCT.get() &&
-                               ((extCondition != null) ? extCondition.evaluate() : true) &&
-                               (currTime + interval > System.currentTimeMillis()))
-                        {
-                            getTreeLock().wait(interval);
-                        }
-                    } else {
-                        while (keepBlockingCT.get() &&
-                               ((extCondition != null) ? extCondition.evaluate() : true))
-                        {
-                            getTreeLock().wait();
-                        }
-                    }
-                    if (log.isLoggable(PlatformLogger.Level.FINE)) {
-                        log.fine("waitDone " + keepBlockingEDT.get() + " " + keepBlockingCT.get());
-                    }
-                } catch (InterruptedException e) {
-                    if (log.isLoggable(PlatformLogger.Level.FINE)) {
-                        log.fine("Exception caught while waiting: " + e);
-                    }
-                } finally {
-                    if (filter != null) {
-                        dispatchThread.removeEventFilter(filter);
-                    }
-                }
-                // If the waiting process has been stopped because of the
-                // time interval passed or an exception occurred, the state
-                // should be changed
-                keepBlockingEDT.set(false);
-                keepBlockingCT.set(false);
-            }
+            return true;
         }
-
-        return true;
+        finally {
+            keepBlockingEDT.set(false);
+            keepBlockingCT.set(false);
+            afterExit.set(false);
+        }
     }
 
     /**
@@ -288,7 +295,8 @@
             log.fine("exit(): blockingEDT=" + keepBlockingEDT.get() +
                      ", blockingCT=" + keepBlockingCT.get());
         }
-        if (keepBlockingEDT.compareAndSet(true, false)) {
+        afterExit.set(true);
+        if (keepBlockingEDT.getAndSet(false)) {
             wakeupEDT();
             return true;
         }
--- a/jdk/src/java.desktop/share/classes/java/awt/font/OpenType.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/java/awt/font/OpenType.java	Wed Jul 05 20:37:09 2017 +0200
@@ -331,7 +331,7 @@
    * Optical bounds.  Table tag "opbd" in the Open
    * Type Specification.
    */
-  public final static int       TAG_OPBD        = 0x6d6f7274;
+  public final static int       TAG_OPBD        = 0x6F706264;
 
   /**
    * Glyph properties.  Table tag "prop" in the Open
--- a/jdk/src/java.desktop/share/classes/java/beans/Introspector.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/java/beans/Introspector.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,16 +35,19 @@
 
 import java.lang.ref.Reference;
 import java.lang.ref.SoftReference;
+import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
 import java.lang.reflect.Type;
 
 import java.util.Map;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.EventObject;
 import java.util.List;
 import java.util.TreeMap;
+import sun.misc.JavaBeansAccess;
 
 import sun.misc.SharedSecrets;
 import sun.reflect.misc.ReflectUtil;
@@ -146,15 +149,25 @@
 
     // register with SharedSecrets for JMX usage
     static {
-        SharedSecrets.setJavaBeansIntrospectorAccess((clazz, property) -> {
-            BeanInfo bi = Introspector.getBeanInfo(clazz);
-            PropertyDescriptor[] pds = bi.getPropertyDescriptors();
-            for (PropertyDescriptor pd: pds) {
-                if (pd.getName().equals(property)) {
-                    return pd.getReadMethod();
+        SharedSecrets.setJavaBeansAccess(new JavaBeansAccess() {
+            @Override
+            public Method getReadMethod(Class<?> clazz, String property) throws Exception {
+                BeanInfo bi = Introspector.getBeanInfo(clazz);
+                PropertyDescriptor[] pds = bi.getPropertyDescriptors();
+                for (PropertyDescriptor pd: pds) {
+                    if (pd.getName().equals(property)) {
+                        return pd.getReadMethod();
+                    }
                 }
+                return null;
             }
-            return null;
+
+            @Override
+            public String[] getConstructorPropertiesValue(Constructor<?> ctr) {
+                ConstructorProperties cp = ctr.getAnnotation(ConstructorProperties.class);
+                String [] ret = cp != null ? cp.value() : null;
+                return ret;
+            }
         });
     }
 
--- a/jdk/src/java.desktop/share/classes/javax/sound/sampled/spi/AudioFileWriter.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/sound/sampled/spi/AudioFileWriter.java	Wed Jul 05 20:37:09 2017 +0200
@@ -121,7 +121,7 @@
      * @throws IOException if an I/O exception occurs
      * @throws IllegalArgumentException if the file type is not supported by the
      *         system
-     * @see #isFileTypeSupported(Type, AudioInputStream)
+     * @see #isFileTypeSupported(AudioFileFormat.Type, AudioInputStream)
      * @see #getAudioFileTypes
      */
     public abstract int write(AudioInputStream stream, Type fileType,
--- a/jdk/src/java.desktop/share/classes/javax/swing/GroupLayout.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/GroupLayout.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -218,6 +218,9 @@
 
     private static final int UNSET = Integer.MIN_VALUE;
 
+    // Maximum spring size constrain to avoid integer overflow
+    private static final int INFINITE = Integer.MAX_VALUE >> 1;
+
     /**
      * Indicates the size from the component or gap should be used for a
      * particular range value.
@@ -1389,7 +1392,7 @@
         }
 
         int constrain(int value) {
-            return Math.min(value, Short.MAX_VALUE);
+            return Math.min(value, INFINITE);
         }
 
         int getBaseline() {
--- a/jdk/src/java.desktop/share/classes/javax/swing/JApplet.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/JApplet.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,14 +24,18 @@
  */
 package javax.swing;
 
-import java.awt.*;
-import java.awt.event.*;
 import java.applet.Applet;
-import java.beans.PropertyChangeListener;
-import java.util.Locale;
-import java.util.Vector;
-import java.io.Serializable;
-import javax.accessibility.*;
+import java.awt.AWTEvent;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Graphics;
+import java.awt.HeadlessException;
+import java.awt.LayoutManager;
+
+import javax.accessibility.Accessible;
+import javax.accessibility.AccessibleContext;
 
 /**
  * An extended version of <code>java.applet.Applet</code> that adds support for
@@ -243,9 +247,8 @@
     *      hidden: true
     * description: The menubar for accessing pulldown menus from this applet.
     */
-    @SuppressWarnings("deprecation")
-    public void setJMenuBar(JMenuBar menuBar) {
-        getRootPane().setMenuBar(menuBar);
+    public void setJMenuBar(final JMenuBar menuBar) {
+        getRootPane().setJMenuBar(menuBar);
     }
 
    /**
@@ -254,9 +257,8 @@
     * @return the menubar set on this applet
     * @see #setJMenuBar
     */
-    @SuppressWarnings("deprecation")
     public JMenuBar getJMenuBar() {
-        return getRootPane().getMenuBar();
+        return getRootPane().getJMenuBar();
     }
 
 
--- a/jdk/src/java.desktop/share/classes/javax/swing/JDialog.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/JDialog.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -849,9 +849,8 @@
     *      hidden: true
     * description: The menubar for accessing pulldown menus from this dialog.
     */
-    @SuppressWarnings("deprecation")
-    public void setJMenuBar(JMenuBar menu) {
-        getRootPane().setMenuBar(menu);
+    public void setJMenuBar(final JMenuBar menu) {
+        getRootPane().setJMenuBar(menu);
     }
 
    /**
@@ -860,12 +859,10 @@
     * @return the menubar set on this dialog
     * @see #setJMenuBar
     */
-    @SuppressWarnings("deprecation")
     public JMenuBar getJMenuBar() {
-        return getRootPane().getMenuBar();
+        return getRootPane().getJMenuBar();
     }
 
-
     /**
      * Returns whether calls to {@code add} and
      * {@code setLayout} are forwarded to the {@code contentPane}.
--- a/jdk/src/java.desktop/share/classes/javax/swing/JFrame.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/JFrame.java	Wed Jul 05 20:37:09 2017 +0200
@@ -486,9 +486,8 @@
     *      hidden: true
     * description: The menubar for accessing pulldown menus from this frame.
     */
-    @SuppressWarnings("deprecation")
-    public void setJMenuBar(JMenuBar menubar) {
-        getRootPane().setMenuBar(menubar);
+    public void setJMenuBar(final JMenuBar menubar) {
+        getRootPane().setJMenuBar(menubar);
     }
 
    /**
@@ -497,9 +496,8 @@
     *
     * @see #setJMenuBar
     */
-    @SuppressWarnings("deprecation")
     public JMenuBar getJMenuBar() {
-        return getRootPane().getMenuBar();
+        return getRootPane().getJMenuBar();
     }
 
     /**
--- a/jdk/src/java.desktop/share/classes/javax/swing/JSpinner.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/JSpinner.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -42,8 +42,6 @@
 import javax.accessibility.*;
 import sun.util.locale.provider.LocaleProviderAdapter;
 import sun.util.locale.provider.LocaleResources;
-import sun.util.locale.provider.LocaleServiceProviderPool;
-
 
 /**
  * A single line input field that lets the user select a
@@ -77,12 +75,12 @@
  *   try {
  *       spinner.commitEdit();
  *   }
- *   catch (ParseException pe) {{
+ *   catch (ParseException pe) {
  *       // Edited value is invalid, spinner.getValue() will return
  *       // the last valid value, you could revert the spinner to show that:
- *       JComponent editor = spinner.getEditor()
+ *       JComponent editor = spinner.getEditor();
  *       if (editor instanceof DefaultEditor) {
- *           ((DefaultEditor)editor).getTextField().setValue(spinner.getValue();
+ *           ((DefaultEditor)editor).getTextField().setValue(spinner.getValue());
  *       }
  *       // reset the value to some known value:
  *       spinner.setValue(fallbackValue);
@@ -972,7 +970,7 @@
          * and editing the value of a <code>SpinnerDateModel</code>
          * with a <code>JFormattedTextField</code>.  <code>This</code>
          * <code>DateEditor</code> becomes both a <code>ChangeListener</code>
-         * on the spinners model and a <code>PropertyChangeListener</code>
+         * on the spinner and a <code>PropertyChangeListener</code>
          * on the new <code>JFormattedTextField</code>.
          *
          * @param spinner the spinner whose model <code>this</code> editor will monitor
--- a/jdk/src/java.desktop/share/classes/javax/swing/RepaintManager.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/RepaintManager.java	Wed Jul 05 20:37:09 2017 +0200
@@ -182,9 +182,16 @@
      */
     private final ProcessingRunnable processingRunnable;
 
-    private final static JavaSecurityAccess javaSecurityAccess =
-        SharedSecrets.getJavaSecurityAccess();
+    private static final JavaSecurityAccess javaSecurityAccess =
+            SharedSecrets.getJavaSecurityAccess();
 
+    /**
+     * Listener installed to detect display changes. When display changes,
+     * schedules a callback to notify all RepaintManagers of the display
+     * changes.
+     */
+    private static final DisplayChangedListener displayChangedHandler =
+            new DisplayChangedHandler();
 
     static {
         SwingAccessor.setRepaintManagerAccessor(new SwingAccessor.RepaintManagerAccessor() {
@@ -226,8 +233,8 @@
         GraphicsEnvironment ge = GraphicsEnvironment.
                 getLocalGraphicsEnvironment();
         if (ge instanceof SunGraphicsEnvironment) {
-            ((SunGraphicsEnvironment)ge).addDisplayChangedListener(
-                    new DisplayChangedHandler());
+            ((SunGraphicsEnvironment) ge).addDisplayChangedListener(
+                    displayChangedHandler);
         }
         Toolkit tk = Toolkit.getDefaultToolkit();
         if ((tk instanceof SunToolkit)
@@ -1679,6 +1686,12 @@
      */
     private static final class DisplayChangedHandler implements
                                              DisplayChangedListener {
+        // Empty non private constructor was added because access to this
+        // class shouldn't be generated by the compiler using synthetic
+        // accessor method
+        DisplayChangedHandler() {
+        }
+
         public void displayChanged() {
             scheduleDisplayChanges();
         }
@@ -1686,11 +1699,10 @@
         public void paletteChanged() {
         }
 
-        private void scheduleDisplayChanges() {
+        private static void scheduleDisplayChanges() {
             // To avoid threading problems, we notify each RepaintManager
             // on the thread it was created on.
-            for (Object c : AppContext.getAppContexts()) {
-                AppContext context = (AppContext) c;
+            for (AppContext context : AppContext.getAppContexts()) {
                 synchronized(context) {
                     if (!context.isDisposed()) {
                         EventQueue eventQueue = (EventQueue)context.get(
--- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicComboBoxUI.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicComboBoxUI.java	Wed Jul 05 20:37:09 2017 +0200
@@ -150,6 +150,8 @@
      */
     protected KeyListener popupKeyListener;
 
+    private MouseWheelListener mouseWheelListener;
+
     // This is used for knowing when to cache the minimum preferred size.
     // If the data in the list changes, the cached value get marked for recalc.
     // Added to the current JComboBox model
@@ -413,6 +415,10 @@
                 comboBox.getModel().addListDataListener( listDataListener );
             }
         }
+
+        if ((mouseWheelListener = createMouseWheelListener()) != null) {
+            comboBox.addMouseWheelListener(mouseWheelListener);
+        }
     }
 
     /**
@@ -459,6 +465,9 @@
                 comboBox.getModel().removeListDataListener( listDataListener );
             }
         }
+        if (mouseWheelListener != null) {
+            comboBox.removeMouseWheelListener(mouseWheelListener);
+        }
     }
 
     /**
@@ -572,6 +581,10 @@
         return handler;
     }
 
+    private MouseWheelListener createMouseWheelListener() {
+        return getHandler();
+    }
+
     //
     // end UI Initialization
     //======================
@@ -1723,7 +1736,8 @@
     //
     private class Handler implements ActionListener, FocusListener,
                                      KeyListener, LayoutManager,
-                                     ListDataListener, PropertyChangeListener {
+                                     ListDataListener, PropertyChangeListener,
+                                     MouseWheelListener {
         //
         // PropertyChangeListener
         //
@@ -1997,21 +2011,25 @@
         public void actionPerformed(ActionEvent evt) {
             Object item = comboBox.getEditor().getItem();
             if (item != null) {
-             if(!comboBox.isPopupVisible() && !item.equals(comboBox.getSelectedItem())) {
-              comboBox.setSelectedItem(comboBox.getEditor().getItem());
-             }
-             ActionMap am = comboBox.getActionMap();
-             if (am != null) {
-                Action action = am.get("enterPressed");
-                if (action != null) {
-                    action.actionPerformed(new ActionEvent(comboBox, evt.getID(),
-                                           evt.getActionCommand(),
-                                           evt.getModifiers()));
+                if (!comboBox.isPopupVisible() && !item.equals(comboBox.getSelectedItem())) {
+                    comboBox.setSelectedItem(comboBox.getEditor().getItem());
+                }
+                ActionMap am = comboBox.getActionMap();
+                if (am != null) {
+                    Action action = am.get("enterPressed");
+                    if (action != null) {
+                        action.actionPerformed(new ActionEvent(comboBox, evt.getID(),
+                                evt.getActionCommand(),
+                                evt.getModifiers()));
+                    }
                 }
             }
-       }
+        }
+
+        public void mouseWheelMoved(MouseWheelEvent e) {
+            e.consume();
+        }
    }
-  }
 
     class DefaultKeySelectionManager implements JComboBox.KeySelectionManager, UIResource {
         private String prefix = "";
--- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicComboPopup.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicComboPopup.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -184,6 +184,8 @@
      */
     protected ItemListener             itemListener;
 
+    private MouseWheelListener         scrollerMouseWheelListener;
+
     /**
      * This protected field is implementation specific. Do not access directly
      * or override.
@@ -311,6 +313,7 @@
         uninstallComboBoxModelListeners(comboBox.getModel());
         uninstallKeyboardActions();
         uninstallListListeners();
+        uninstallScrollerListeners();
         // We do this, otherwise the listener the ui installs on
         // the model (the combobox model in this case) will keep a
         // reference to the list, causing the list (and us) to never get gced.
@@ -608,6 +611,7 @@
         scroller.setFocusable( false );
         scroller.getVerticalScrollBar().setFocusable( false );
         scroller.setBorder( null );
+        installScrollerListeners();
     }
 
     /**
@@ -624,6 +628,20 @@
         setFocusable( false );
     }
 
+    private void installScrollerListeners() {
+        scrollerMouseWheelListener = getHandler();
+        if (scrollerMouseWheelListener != null) {
+            scroller.addMouseWheelListener(scrollerMouseWheelListener);
+        }
+    }
+
+    private void uninstallScrollerListeners() {
+        if (scrollerMouseWheelListener != null) {
+            scroller.removeMouseWheelListener(scrollerMouseWheelListener);
+            scrollerMouseWheelListener = null;
+        }
+    }
+
     /**
      * This method adds the necessary listeners to the JComboBox.
      */
@@ -835,8 +853,8 @@
 
 
     private class Handler implements ItemListener, MouseListener,
-                          MouseMotionListener, PropertyChangeListener,
-                          Serializable {
+                          MouseMotionListener, MouseWheelListener,
+                          PropertyChangeListener, Serializable {
         //
         // MouseListener
         // NOTE: this is added to both the JList and JComboBox
@@ -1024,6 +1042,13 @@
                 setListSelection(comboBox.getSelectedIndex());
             }
         }
+
+        //
+        // MouseWheelListener
+        //
+        public void mouseWheelMoved(MouseWheelEvent e) {
+            e.consume();
+        }
     }
 
     //
@@ -1287,11 +1312,24 @@
         else {
             screenBounds = new Rectangle(p, toolkit.getScreenSize());
         }
-
-        Rectangle rect = new Rectangle(px,py,pw,ph);
-        if (py+ph > screenBounds.y+screenBounds.height
-            && ph < screenBounds.height) {
-            rect.y = -rect.height;
+        int borderHeight = 0;
+        Border popupBorder = getBorder();
+        if (popupBorder != null) {
+            Insets borderInsets = popupBorder.getBorderInsets(this);
+            borderHeight = borderInsets.top + borderInsets.bottom;
+            screenBounds.width -= (borderInsets.left + borderInsets.right);
+            screenBounds.height -= borderHeight;
+        }
+        Rectangle rect = new Rectangle(px, py, pw, ph);
+        if (py + ph > screenBounds.y + screenBounds.height) {
+            if (ph <= -screenBounds.y - borderHeight) {
+                // popup goes above
+                rect.y = -ph - borderHeight;
+            } else {
+                // a full screen height popup
+                rect.y = screenBounds.y + Math.max(0, (screenBounds.height - ph) / 2 );
+                rect.height = Math.min(screenBounds.height, ph);
+            }
         }
         return rect;
     }
--- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLabelUI.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLabelUI.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -504,7 +504,7 @@
                 doPress(label);
             }
             else if (key == RELEASE) {
-                doRelease(label);
+                doRelease(label, e.getActionCommand() != null);
             }
         }
 
@@ -517,33 +517,77 @@
                     SwingUtilities.replaceUIInputMap(label, JComponent.WHEN_FOCUSED, inputMap);
                 }
                 int dka = label.getDisplayedMnemonic();
-                inputMap.put(KeyStroke.getKeyStroke(dka, BasicLookAndFeel.getFocusAcceleratorKeyMask(), true), RELEASE);
+                putOnRelease(inputMap, dka, BasicLookAndFeel
+                        .getFocusAcceleratorKeyMask());
                 // Need this when the sticky keys are enabled
-                inputMap.put(KeyStroke.getKeyStroke(dka, 0, true), RELEASE);
+                putOnRelease(inputMap, dka, 0);
                 // Need this if ALT is released before the accelerator
-                inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ALT, 0, true), RELEASE);
+                putOnRelease(inputMap, KeyEvent.VK_ALT, 0);
                 label.requestFocus();
             }
         }
 
-        private void doRelease(JLabel label) {
+        private void doRelease(JLabel label, boolean isCommand) {
             Component labelFor = label.getLabelFor();
             if (labelFor != null && labelFor.isEnabled()) {
-                InputMap inputMap = SwingUtilities.getUIInputMap(label, JComponent.WHEN_FOCUSED);
-                if (inputMap != null) {
-                    // inputMap should never be null.
+                if (label.hasFocus()) {
+                    InputMap inputMap = SwingUtilities.getUIInputMap(label,
+                            JComponent.WHEN_FOCUSED);
+                    if (inputMap != null) {
+                        // inputMap should never be null.
+                        int dka = label.getDisplayedMnemonic();
+                        removeOnRelease(inputMap, dka, BasicLookAndFeel
+                                .getFocusAcceleratorKeyMask());
+                        removeOnRelease(inputMap, dka, 0);
+                        removeOnRelease(inputMap, KeyEvent.VK_ALT, 0);
+                    }
+                    inputMap = SwingUtilities.getUIInputMap(label,
+                            JComponent.WHEN_IN_FOCUSED_WINDOW);
+                    if (inputMap == null) {
+                        inputMap = new InputMapUIResource();
+                        SwingUtilities.replaceUIInputMap(label,
+                                JComponent.WHEN_IN_FOCUSED_WINDOW, inputMap);
+                    }
                     int dka = label.getDisplayedMnemonic();
-                    inputMap.remove(KeyStroke.getKeyStroke(dka, BasicLookAndFeel.getFocusAcceleratorKeyMask(), true));
-                    inputMap.remove(KeyStroke.getKeyStroke(dka, 0, true));
-                    inputMap.remove(KeyStroke.getKeyStroke(KeyEvent.VK_ALT, 0, true));
-                }
-                if (labelFor instanceof Container &&
-                        ((Container) labelFor).isFocusCycleRoot()) {
-                    labelFor.requestFocus();
+                    if (isCommand) {
+                        putOnRelease(inputMap, KeyEvent.VK_ALT, 0);
+                    } else {
+                        putOnRelease(inputMap, dka, BasicLookAndFeel
+                                .getFocusAcceleratorKeyMask());
+                        // Need this when the sticky keys are enabled
+                        putOnRelease(inputMap, dka, 0);
+                    }
+                    if (labelFor instanceof Container &&
+                            ((Container) labelFor).isFocusCycleRoot()) {
+                        labelFor.requestFocus();
+                    } else {
+                        SwingUtilities2.compositeRequestFocus(labelFor);
+                    }
                 } else {
-                    SwingUtilities2.compositeRequestFocus(labelFor);
+                    InputMap inputMap = SwingUtilities.getUIInputMap(label,
+                            JComponent.WHEN_IN_FOCUSED_WINDOW);
+                    int dka = label.getDisplayedMnemonic();
+                    if (inputMap != null) {
+                        if (isCommand) {
+                            removeOnRelease(inputMap, dka, BasicLookAndFeel
+                                    .getFocusAcceleratorKeyMask());
+                            removeOnRelease(inputMap, dka, 0);
+                        } else {
+                            removeOnRelease(inputMap, KeyEvent.VK_ALT, 0);
+                        }
+                    }
                 }
             }
         }
+
+        private void putOnRelease(InputMap inputMap, int keyCode, int modifiers) {
+            inputMap.put(KeyStroke.getKeyStroke(keyCode, modifiers, true),
+                    RELEASE);
+        }
+
+        private void removeOnRelease(InputMap inputMap, int keyCode, int modifiers) {
+            inputMap.remove(KeyStroke.getKeyStroke(keyCode, modifiers, true));
+        }
+
     }
 }
--- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java	Wed Jul 05 20:37:09 2017 +0200
@@ -914,7 +914,9 @@
                     processMouseEvent(me);
                 break;
             case MouseEvent.MOUSE_WHEEL:
-                if (isInPopup(src)) {
+                if (isInPopup(src)
+                    || ((src instanceof JComboBox) && ((JComboBox) src).isPopupVisible())) {
+
                     return;
                 }
                 cancelPopupMenu();
--- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicRadioButtonUI.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicRadioButtonUI.java	Wed Jul 05 20:37:09 2017 +0200
@@ -438,7 +438,7 @@
         // to the button group or not
         Component getFocusTransferBaseComponent(boolean next){
             Component focusBaseComp = activeBtn;
-            Window container = SwingUtilities.getWindowAncestor(activeBtn);
+            Container container = focusBaseComp.getFocusCycleRootAncestor();
             if (container != null) {
                 FocusTraversalPolicy policy = container.getFocusTraversalPolicy();
                 Component comp = next ? policy.getComponentAfter(container, activeBtn)
--- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSpinnerUI.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSpinnerUI.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -989,7 +989,7 @@
                                 ((JSpinner.DefaultEditor)newEditor).getTextField();
                             if (tf != null) {
                                 if (tf.getFont() instanceof UIResource) {
-                                    tf.setFont(spinner.getFont());
+                                    tf.setFont(new FontUIResource(spinner.getFont()));
                                 }
                                 tf.addFocusListener(nextButtonHandler);
                                 tf.addFocusListener(previousButtonHandler);
@@ -1002,12 +1002,12 @@
                     }
                     else if ("font".equals(propertyName)) {
                         JComponent editor = spinner.getEditor();
-                        if (editor!=null && editor instanceof JSpinner.DefaultEditor) {
+                        if (editor instanceof JSpinner.DefaultEditor) {
                             JTextField tf =
                                 ((JSpinner.DefaultEditor)editor).getTextField();
                             if (tf != null) {
                                 if (tf.getFont() instanceof UIResource) {
-                                    tf.setFont(spinner.getFont());
+                                    tf.setFont(new FontUIResource(spinner.getFont()));
                                 }
                             }
                         }
--- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -936,10 +936,11 @@
             ((AbstractDocument)doc).readLock();
         }
         try {
-            if ((d.width > (i.left + i.right)) && (d.height > (i.top + i.bottom))) {
-                rootView.setSize(d.width - i.left - i.right, d.height - i.top - i.bottom);
+            if ((d.width > (i.left + i.right + caretMargin)) && (d.height > (i.top + i.bottom))) {
+                rootView.setSize(d.width - i.left - i.right -
+                        caretMargin, d.height - i.top - i.bottom);
             }
-            else if (d.width == 0 && d.height == 0) {
+            else if (d.width == 0 || d.height == 0) {
                 // Probably haven't been layed out yet, force some sort of
                 // initial sizing.
                 rootView.setSize(Integer.MAX_VALUE, Integer.MAX_VALUE);
--- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalRootPaneUI.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalRootPaneUI.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,15 +27,11 @@
 
 import java.awt.event.*;
 import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
 import javax.swing.*;
-import javax.swing.border.*;
 import javax.swing.event.*;
 import javax.swing.plaf.*;
 import javax.swing.plaf.basic.*;
 import java.awt.*;
-import java.io.*;
-import java.security.*;
 
 /**
  * Provides the metal look and feel implementation of <code>RootPaneUI</code>.
@@ -441,7 +437,6 @@
          * @param the Container for which this layout manager is being used
          * @return a Dimension object containing the layout's preferred size
          */
-        @SuppressWarnings("deprecation")
         public Dimension preferredLayoutSize(Container parent) {
             Dimension cpd, mbd, tpd;
             int cpWidth = 0;
@@ -463,8 +458,8 @@
                 cpHeight = cpd.height;
             }
 
-            if(root.getMenuBar() != null) {
-                mbd = root.getMenuBar().getPreferredSize();
+            if(root.getJMenuBar() != null) {
+                mbd = root.getJMenuBar().getPreferredSize();
                 if (mbd != null) {
                     mbWidth = mbd.width;
                     mbHeight = mbd.height;
@@ -494,7 +489,6 @@
          * @param the Container for which this layout manager is being used
          * @return a Dimension object containing the layout's minimum size
          */
-        @SuppressWarnings("deprecation")
         public Dimension minimumLayoutSize(Container parent) {
             Dimension cpd, mbd, tpd;
             int cpWidth = 0;
@@ -516,8 +510,8 @@
                 cpHeight = cpd.height;
             }
 
-            if(root.getMenuBar() != null) {
-                mbd = root.getMenuBar().getMinimumSize();
+            if(root.getJMenuBar() != null) {
+                mbd = root.getJMenuBar().getMinimumSize();
                 if (mbd != null) {
                     mbWidth = mbd.width;
                     mbHeight = mbd.height;
@@ -546,7 +540,6 @@
          * @param the Container for which this layout manager is being used
          * @return a Dimension object containing the layout's maximum size
          */
-        @SuppressWarnings("deprecation")
         public Dimension maximumLayoutSize(Container target) {
             Dimension cpd, mbd, tpd;
             int cpWidth = Integer.MAX_VALUE;
@@ -566,8 +559,8 @@
                 }
             }
 
-            if(root.getMenuBar() != null) {
-                mbd = root.getMenuBar().getMaximumSize();
+            if(root.getJMenuBar() != null) {
+                mbd = root.getJMenuBar().getMaximumSize();
                 if (mbd != null) {
                     mbWidth = mbd.width;
                     mbHeight = mbd.height;
@@ -610,7 +603,6 @@
          *
          * @param the Container for which this layout manager is being used
          */
-        @SuppressWarnings("deprecation")
         public void layoutContainer(Container parent) {
             JRootPane root = (JRootPane) parent;
             Rectangle b = root.getBounds();
@@ -640,9 +632,9 @@
                     }
                 }
             }
-            if(root.getMenuBar() != null) {
-                Dimension mbd = root.getMenuBar().getPreferredSize();
-                root.getMenuBar().setBounds(0, nextY, w, mbd.height);
+            if(root.getJMenuBar() != null) {
+                Dimension mbd = root.getJMenuBar().getPreferredSize();
+                root.getJMenuBar().setBounds(0, nextY, w, mbd.height);
                 nextY += mbd.height;
             }
             if(root.getContentPane() != null) {
--- a/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthSplitPaneUI.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthSplitPaneUI.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -134,6 +134,7 @@
                 value = Integer.valueOf(6);
             }
             LookAndFeel.installProperty(splitPane, "dividerSize", value);
+            dividerSize = ((Number)value).intValue();
 
             value = style.get(context, "SplitPane.oneTouchExpandable");
             if (value != null) {
--- a/jdk/src/java.desktop/share/classes/sun/applet/AppletClassLoader.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletClassLoader.java	Wed Jul 05 20:37:09 2017 +0200
@@ -802,7 +802,7 @@
     /**
      * Determine if applet is targeted for JDK 1.1.
      *
-     * @param applet Applet class.
+     * @param  clazz Applet class.
      * @return TRUE if applet is targeted for JDK 1.1;
      *         FALSE if applet is not;
      *         null if applet is unknown.
@@ -815,7 +815,7 @@
     /**
      * Determine if applet is targeted for JDK 1.2.
      *
-     * @param applet Applet class.
+     * @param  clazz Applet class.
      * @return TRUE if applet is targeted for JDK 1.2;
      *         FALSE if applet is not;
      *         null if applet is unknown.
--- a/jdk/src/java.desktop/share/classes/sun/applet/AppletSecurity.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletSecurity.java	Wed Jul 05 20:37:09 2017 +0200
@@ -270,10 +270,10 @@
      * The <code>checkPackageAccess</code> method for class
      * <code>SecurityManager</code>  calls
      * <code>checkPermission</code> with the
-     * <code>RuntimePermission("accessClassInPackage."+pkg)</code>
+     * <code>RuntimePermission("accessClassInPackage."+ pkgname)</code>
      * permission.
      *
-     * @param      pkg   the package name.
+     * @param      pkgname   the package name.
      * @exception  SecurityException  if the caller does not have
      *             permission to access the specified package.
      * @see        java.lang.ClassLoader#loadClass(java.lang.String, boolean)
--- a/jdk/src/java.desktop/share/classes/sun/awt/AppContext.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/AppContext.java	Wed Jul 05 20:37:09 2017 +0200
@@ -190,7 +190,7 @@
      *
      * @see #addPropertyChangeListener
      * @see #removePropertyChangeListener
-     * @see #firePropertyChange
+     * @see PropertyChangeSupport#firePropertyChange
      */
     private PropertyChangeSupport changeSupport = null;
 
@@ -809,7 +809,7 @@
      *
      * @see #addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener)
      * @see #getPropertyChangeListeners(java.lang.String)
-     * @see #removePropertyChangeListener(java.beans.PropertyChangeListener)
+     * @see PropertyChangeSupport#removePropertyChangeListener(java.beans.PropertyChangeListener)
      */
     public synchronized void removePropertyChangeListener(
                              String propertyName,
--- a/jdk/src/java.desktop/share/classes/sun/awt/DefaultMouseInfoPeer.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/DefaultMouseInfoPeer.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,7 @@
 import java.awt.Window;
 import java.awt.peer.MouseInfoPeer;
 
-public class DefaultMouseInfoPeer implements MouseInfoPeer {
+public final class DefaultMouseInfoPeer implements MouseInfoPeer {
 
     /**
      * Package-private constructor to prevent instantiation.
--- a/jdk/src/java.desktop/share/classes/sun/awt/EmbeddedFrame.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/EmbeddedFrame.java	Wed Jul 05 20:37:09 2017 +0200
@@ -552,16 +552,10 @@
         }
         public void setModalBlocked(Dialog blocker, boolean blocked) {}
 
-        /**
-         * @see java.awt.peer.ContainerPeer#restack
-         */
         public void restack() {
             throw new UnsupportedOperationException();
         }
 
-        /**
-         * @see java.awt.peer.ContainerPeer#isRestackSupported
-         */
         public boolean isRestackSupported() {
             return false;
         }
--- a/jdk/src/java.desktop/share/classes/sun/awt/HToolkit.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/HToolkit.java	Wed Jul 05 20:37:09 2017 +0200
@@ -45,8 +45,7 @@
  * with the HeadlessToolkit.  It is primarily used
  * in embedded JRE's that do not have sun/awt/X11 classes.
  */
-public class HToolkit extends SunToolkit
-    implements ComponentFactory {
+public final class HToolkit extends SunToolkit implements ComponentFactory {
 
     private static final KeyboardFocusManagerPeer kfmPeer = new KeyboardFocusManagerPeer() {
         @Override
--- a/jdk/src/java.desktop/share/classes/sun/awt/SunToolkit.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/SunToolkit.java	Wed Jul 05 20:37:09 2017 +0200
@@ -366,8 +366,8 @@
       * status to synchronous for any of its windows, then further focus
       * behaviour is unspecified.
       * <p>
-      * @param    w window for which the lightweight focus request status
-      *             should be set
+      * @param    changed the window for which the lightweight focus request
+      *           status should be set
       * @param    status the value of lightweight focus request status
       */
 
@@ -1459,9 +1459,9 @@
      * <p> Notice that realSync isn't guaranteed to work if recurring
      * actions occur, such as if during processing of some event
      * another request which may generate some events occurs.  By
-     * default, sync tries to perform as much as {@value MAX_ITERS}
+     * default, sync tries to perform as much as {@value #MAX_ITERS}
      * cycles of event processing, allowing for roughly {@value
-     * MAX_ITERS} additional requests.
+     * #MAX_ITERS} additional requests.
      *
      * <p> For example, requestFocus() generates native request, which
      * generates one or two Java focus events, which then generate a
--- a/jdk/src/java.desktop/share/classes/sun/awt/datatransfer/SunClipboard.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/datatransfer/SunClipboard.java	Wed Jul 05 20:37:09 2017 +0200
@@ -151,7 +151,7 @@
 
 
     /**
-     * @see java.awt.Clipboard#getAvailableDataFlavors
+     * @see java.awt.datatransfer.Clipboard#getAvailableDataFlavors
      * @since 1.5
      */
     public DataFlavor[] getAvailableDataFlavors() {
@@ -167,7 +167,7 @@
     }
 
     /**
-     * @see java.awt.Clipboard#isDataFlavorAvailable
+     * @see java.awt.datatransfer.Clipboard#isDataFlavorAvailable
      * @since 1.5
      */
     public boolean isDataFlavorAvailable(DataFlavor flavor) {
@@ -186,7 +186,7 @@
     }
 
     /**
-     * @see java.awt.Clipboard#getData
+     * @see java.awt.datatransfer.Clipboard#getData
      * @since 1.5
      */
     public Object getData(DataFlavor flavor)
--- a/jdk/src/java.desktop/share/classes/sun/awt/geom/PathConsumer2D.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/geom/PathConsumer2D.java	Wed Jul 05 20:37:09 2017 +0200
@@ -27,30 +27,30 @@
 
 public interface PathConsumer2D {
     /**
-     * @see java.awt.geom.Path2D.Float.moveTo
+     * @see java.awt.geom.Path2D.Float#moveTo
      */
     public void moveTo(float x, float y);
 
     /**
-     * @see java.awt.geom.Path2D.Float.lineTo
+     * @see java.awt.geom.Path2D.Float#lineTo
      */
     public void lineTo(float x, float y);
 
     /**
-     * @see java.awt.geom.Path2D.Float.quadTo
+     * @see java.awt.geom.Path2D.Float#quadTo
      */
     public void quadTo(float x1, float y1,
                        float x2, float y2);
 
     /**
-     * @see java.awt.geom.Path2D.Float.curveTo
+     * @see java.awt.geom.Path2D.Float#curveTo
      */
     public void curveTo(float x1, float y1,
                         float x2, float y2,
                         float x3, float y3);
 
     /**
-     * @see java.awt.geom.Path2D.Float.closePath
+     * @see java.awt.geom.Path2D.Float#closePath
      */
     public void closePath();
 
--- a/jdk/src/java.desktop/share/classes/sun/awt/im/ExecutableInputMethodManager.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/im/ExecutableInputMethodManager.java	Wed Jul 05 20:37:09 2017 +0200
@@ -519,7 +519,7 @@
      * Writes the preferred input method descriptor class name into
      * the user's Preferences tree in accordance with the given locale.
      *
-     * @param inputMethodLocator input method locator to remember.
+     * @param locator input method locator to remember.
      */
     private synchronized void putPreferredInputMethod(InputMethodLocator locator) {
         InputMethodDescriptor descriptor = locator.getDescriptor();
--- a/jdk/src/java.desktop/share/classes/sun/awt/image/ByteBandedRaster.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ByteBandedRaster.java	Wed Jul 05 20:37:09 2017 +0200
@@ -176,7 +176,7 @@
      * Returns data offset for the specified band.  The data offset
      * is the index into the band's data array
      * in which the first sample of the first scanline is stored.
-     * @param The band whose offset is returned.
+     * @param band The band whose offset is returned.
      */
     public int getDataOffset(int band) {
         return dataOffsets[band];
@@ -222,11 +222,11 @@
      * and references anything other than an array of transferType.
      * @param x        The X coordinate of the pixel location.
      * @param y        The Y coordinate of the pixel location.
-     * @param outData  An object reference to an array of type defined by
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length getNumDataElements().
      *                 If null an array of appropriate type and size will be
      *                 allocated.
-     * @return         An object reference to an array of type defined by
+     * @return An object reference to an array of type defined by
      *                 getTransferType() with the request pixel data.
      */
     public Object getDataElements(int x, int y, Object obj) {
@@ -267,9 +267,9 @@
      * </pre>
      * @param x        The X coordinate of the upper left pixel location.
      * @param y        The Y coordinate of the upper left pixel location.
-     * @param width    Width of the pixel rectangle.
-     * @param height   Height of the pixel rectangle.
-     * @param outData  An object reference to an array of type defined by
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length w*h*getNumDataElements().
      *                 If null an array of appropriate type and size will be
      *                 allocated.
@@ -320,8 +320,8 @@
      * </pre>
      * @param x        The X coordinate of the upper left pixel location.
      * @param y        The Y coordinate of the upper left pixel location.
-     * @param width    Width of the pixel rectangle.
-     * @param height   Height of the pixel rectangle.
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
      * @param band     The band to return.
      * @param outData  If non-null, data elements for all bands
      *                 at the specified location are returned in this array.
@@ -368,8 +368,8 @@
      * </pre>
      * @param x        The X coordinate of the upper left pixel location.
      * @param y        The Y coordinate of the upper left pixel location.
-     * @param width    Width of the pixel rectangle.
-     * @param height   Height of the pixel rectangle.
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
      * @param outData  If non-null, data elements for all bands
      *                 at the specified location are returned in this array.
      * @return         Data array with data elements for all bands.
@@ -412,7 +412,7 @@
      * and references anything other than an array of transferType.
      * @param x        The X coordinate of the pixel location.
      * @param y        The Y coordinate of the pixel location.
-     * @param inData   An object reference to an array of type defined by
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length getNumDataElements()
      *                 containing the pixel data to place at x,y.
      */
@@ -505,7 +505,7 @@
      * @param y        The Y coordinate of the upper left pixel location.
      * @param w        Width of the pixel rectangle.
      * @param h        Height of the pixel rectangle.
-     * @param inData   An object reference to an array of type defined by
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length w*h*getNumDataElements()
      *                 containing the pixel data to place between x,y and
      *                 x+h, y+h.
--- a/jdk/src/java.desktop/share/classes/sun/awt/image/ByteComponentRaster.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ByteComponentRaster.java	Wed Jul 05 20:37:09 2017 +0200
@@ -253,7 +253,7 @@
      * and references anything other than an array of transferType.
      * @param x        The X coordinate of the pixel location.
      * @param y        The Y coordinate of the pixel location.
-     * @param outData  An object reference to an array of type defined by
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length getNumDataElements().
      *                 If null an array of appropriate type and size will be
      *                 allocated.
@@ -299,9 +299,9 @@
      * </pre>
      * @param x        The X coordinate of the upper left pixel location.
      * @param y        The Y coordinate of the upper left pixel location.
-     * @param width    Width of the pixel rectangle.
-     * @param height   Height of the pixel rectangle.
-     * @param outData  An object reference to an array of type defined by
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length w*h*getNumDataElements().
      *                 If null an array of appropriate type and size will be
      *                 allocated.
@@ -352,8 +352,8 @@
      * </pre>
      * @param x        The X coordinate of the upper left pixel location.
      * @param y        The Y coordinate of the upper left pixel location.
-     * @param width    Width of the pixel rectangle.
-     * @param height   Height of the pixel rectangle.
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
      * @param band     The band to return.
      * @param outData  If non-null, data elements for all bands
      *                 at the specified location are returned in this array.
@@ -415,8 +415,8 @@
      * </pre>
      * @param x        The X coordinate of the upper left pixel location.
      * @param y        The Y coordinate of the upper left pixel location.
-     * @param width    Width of the pixel rectangle.
-     * @param height   Height of the pixel rectangle.
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
      * @param outData  If non-null, data elements for all bands
      *                 at the specified location are returned in this array.
      * @return         Data array with data elements for all bands.
@@ -458,7 +458,7 @@
      * and references anything other than an array of transferType.
      * @param x        The X coordinate of the pixel location.
      * @param y        The Y coordinate of the pixel location.
-     * @param inData   An object reference to an array of type defined by
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length getNumDataElements()
      *                 containing the pixel data to place at x,y.
      */
@@ -577,7 +577,7 @@
      * @param y        The Y coordinate of the upper left pixel location.
      * @param w        Width of the pixel rectangle.
      * @param h        Height of the pixel rectangle.
-     * @param inData   An object reference to an array of type defined by
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length w*h*getNumDataElements()
      *                 containing the pixel data to place between x,y and
      *                 x+h, y+h.
--- a/jdk/src/java.desktop/share/classes/sun/awt/image/ByteInterleavedRaster.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ByteInterleavedRaster.java	Wed Jul 05 20:37:09 2017 +0200
@@ -305,7 +305,7 @@
      * and references anything other than an array of transferType.
      * @param x        The X coordinate of the pixel location.
      * @param y        The Y coordinate of the pixel location.
-     * @param outData  An object reference to an array of type defined by
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length getNumDataElements().
      *                 If null an array of appropriate type and size will be
      *                 allocated.
@@ -351,9 +351,9 @@
      * </pre>
      * @param x        The X coordinate of the upper left pixel location.
      * @param y        The Y coordinate of the upper left pixel location.
-     * @param width    Width of the pixel rectangle.
-     * @param height   Height of the pixel rectangle.
-     * @param outData  An object reference to an array of type defined by
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length w*h*getNumDataElements().
      *                 If null an array of appropriate type and size will be
      *                 allocated.
@@ -376,8 +376,8 @@
      * </pre>
      * @param x        The X coordinate of the upper left pixel location.
      * @param y        The Y coordinate of the upper left pixel location.
-     * @param width    Width of the pixel rectangle.
-     * @param height   Height of the pixel rectangle.
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
      * @param band     The band to return.
      * @param outData  If non-null, data elements for all bands
      *                 at the specified location are returned in this array.
@@ -437,8 +437,8 @@
      * </pre>
      * @param x        The X coordinate of the upper left pixel location.
      * @param y        The Y coordinate of the upper left pixel location.
-     * @param width    Width of the pixel rectangle.
-     * @param height   Height of the pixel rectangle.
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
      * @param outData  If non-null, data elements for all bands
      *                 at the specified location are returned in this array.
      * @return         Data array with data elements for all bands.
@@ -536,7 +536,7 @@
      * and references anything other than an array of transferType.
      * @param x        The X coordinate of the pixel location.
      * @param y        The Y coordinate of the pixel location.
-     * @param inData   An object reference to an array of type defined by
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length getNumDataElements()
      *                 containing the pixel data to place at x,y.
      */
@@ -666,7 +666,7 @@
      * @param y        The Y coordinate of the upper left pixel location.
      * @param w        Width of the pixel rectangle.
      * @param h        Height of the pixel rectangle.
-     * @param inData   An object reference to an array of type defined by
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length w*h*getNumDataElements()
      *                 containing the pixel data to place between x,y and
      *                 x+h, y+h.
--- a/jdk/src/java.desktop/share/classes/sun/awt/image/BytePackedRaster.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/image/BytePackedRaster.java	Wed Jul 05 20:37:09 2017 +0200
@@ -234,7 +234,7 @@
      * and references anything other than an array of transferType.
      * @param x        The X coordinate of the pixel location.
      * @param y        The Y coordinate of the pixel location.
-     * @param outData  An object reference to an array of type defined by
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length getNumDataElements().
      *                 If null an array of appropriate type and size will be
      *                 allocated.
@@ -306,9 +306,9 @@
      * </pre>
      * @param x        The X coordinate of the upper left pixel location.
      * @param y        The Y coordinate of the upper left pixel location.
-     * @param width    Width of the pixel rectangle.
-     * @param height   Height of the pixel rectangle.
-     * @param outData  An object reference to an array of type defined by
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length w*h*getNumDataElements().
      *                 If null an array of appropriate type and size will be
      *                 allocated.
@@ -358,8 +358,8 @@
      * </pre>
      * @param x        The X coordinate of the upper left pixel location.
      * @param y        The Y coordinate of the upper left pixel location.
-     * @param width    Width of the pixel rectangle.
-     * @param height   Height of the pixel rectangle.
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
      * @param band     The band to return, is ignored.
      * @param outData  If non-null, data elements
      *                 at the specified locations are returned in this array.
@@ -383,8 +383,8 @@
      * </pre>
      * @param x        The X coordinate of the upper left pixel location.
      * @param y        The Y coordinate of the upper left pixel location.
-     * @param width    Width of the pixel rectangle.
-     * @param height   Height of the pixel rectangle.
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
      * @param outData  If non-null, data elements
      *                 at the specified locations are returned in this array.
      * @return         Byte array with data elements.
@@ -499,7 +499,7 @@
      * and references anything other than an array of transferType.
      * @param x        The X coordinate of the pixel location.
      * @param y        The Y coordinate of the pixel location.
-     * @param inData   An object reference to an array of type defined by
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length getNumDataElements()
      *                 containing the pixel data to place at x,y.
      */
@@ -857,7 +857,7 @@
      * @param y        The Y coordinate of the upper left pixel location.
      * @param w        Width of the pixel rectangle.
      * @param h        Height of the pixel rectangle.
-     * @param inData   An object reference to an array of type defined by
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length w*h*getNumDataElements()
      *                 containing the pixel data to place between x,y and
      *                 x+h, y+h.
--- a/jdk/src/java.desktop/share/classes/sun/awt/image/ImageFetchable.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ImageFetchable.java	Wed Jul 05 20:37:09 2017 +0200
@@ -33,7 +33,7 @@
  * threads which manage the applications User Interface.
  *
  * @see ImageFetcher
- * @see ImageProducer
+ * @see java.awt.image.ImageProducer
  *
  * @author      Jim Graham
  */
@@ -42,7 +42,7 @@
      * This method is called by one of the ImageFetcher threads to start
      * the flow of information from the ImageProducer to the ImageConsumer.
      * @see ImageFetcher
-     * @see ImageProducer
+     * @see java.awt.image.ImageProducer
      */
     public void doFetch();
 }
--- a/jdk/src/java.desktop/share/classes/sun/awt/image/IntegerComponentRaster.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/image/IntegerComponentRaster.java	Wed Jul 05 20:37:09 2017 +0200
@@ -263,7 +263,7 @@
      * and references anything other than an array of transferType.
      * @param x        The X coordinate of the pixel location.
      * @param y        The Y coordinate of the pixel location.
-     * @param outData  An object reference to an array of type defined by
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length getNumDataElements().
      *                 If null an array of appropriate type and size will be
      *                 allocated.
@@ -309,9 +309,9 @@
      * </pre>
      * @param x        The X coordinate of the upper left pixel location.
      * @param y        The Y coordinate of the upper left pixel location.
-     * @param width    Width of the pixel rectangle.
-     * @param height   Height of the pixel rectangle.
-     * @param outData  An object reference to an array of type defined by
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length w*h*getNumDataElements().
      *                 If null an array of appropriate type and size will be
      *                 allocated.
@@ -358,7 +358,7 @@
      * and references anything other than an array of transferType.
      * @param x        The X coordinate of the pixel location.
      * @param y        The Y coordinate of the pixel location.
-     * @param inData   An object reference to an array of type defined by
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length getNumDataElements()
      *                 containing the pixel data to place at x,y.
      */
@@ -489,7 +489,7 @@
      * @param y        The Y coordinate of the upper left pixel location.
      * @param w        Width of the pixel rectangle.
      * @param h        Height of the pixel rectangle.
-     * @param inData   An object reference to an array of type defined by
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length w*h*getNumDataElements()
      *                 containing the pixel data to place between x,y and
      *                 x+h, y+h.
--- a/jdk/src/java.desktop/share/classes/sun/awt/image/IntegerInterleavedRaster.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/image/IntegerInterleavedRaster.java	Wed Jul 05 20:37:09 2017 +0200
@@ -206,7 +206,7 @@
      * and references anything other than an array of transferType.
      * @param x        The X coordinate of the pixel location.
      * @param y        The Y coordinate of the pixel location.
-     * @param outData  An object reference to an array of type defined by
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length getNumDataElements().
      *                 If null an array of appropriate type and size will be
      *                 allocated.
@@ -249,9 +249,9 @@
      * </pre>
      * @param x        The X coordinate of the upper left pixel location.
      * @param y        The Y coordinate of the upper left pixel location.
-     * @param width    Width of the pixel rectangle.
-     * @param height   Height of the pixel rectangle.
-     * @param outData  An object reference to an array of type defined by
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length w*h*getNumDataElements().
      *                 If null an array of appropriate type and size will be
      *                 allocated.
@@ -291,7 +291,7 @@
      * and references anything other than an array of transferType.
      * @param x        The X coordinate of the pixel location.
      * @param y        The Y coordinate of the pixel location.
-     * @param inData   An object reference to an array of type defined by
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length getNumDataElements()
      *                 containing the pixel data to place at x,y.
      */
@@ -410,7 +410,7 @@
      * @param y        The Y coordinate of the upper left pixel location.
      * @param w        Width of the pixel rectangle.
      * @param h        Height of the pixel rectangle.
-     * @param inData   An object reference to an array of type defined by
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length w*h*getNumDataElements()
      *                 containing the pixel data to place between x,y and
      *                 x+h, y+h.
--- a/jdk/src/java.desktop/share/classes/sun/awt/image/ShortBandedRaster.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ShortBandedRaster.java	Wed Jul 05 20:37:09 2017 +0200
@@ -172,7 +172,7 @@
      * Returns the data offset for the specified band.  The data offset
      * is the index into the band's data array
      * in which the first sample of the first scanline is stored.
-     * @param   The band whose offset is returned.
+     * @param band The band whose offset is returned.
      */
     public int getDataOffset(int band) {
         return dataOffsets[band];
@@ -218,7 +218,7 @@
      * and references anything other than an array of transferType.
      * @param x        The X coordinate of the pixel location.
      * @param y        The Y coordinate of the pixel location.
-     * @param outData  An object reference to an array of type defined by
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length getNumDataElements().
      *                 If null an array of appropriate type and size will be
      *                 allocated.
@@ -262,9 +262,9 @@
      * </pre>
      * @param x        The X coordinate of the upper left pixel location.
      * @param y        The Y coordinate of the upper left pixel location.
-     * @param width    Width of the pixel rectangle.
-     * @param height   Height of the pixel rectangle.
-     * @param outData  An object reference to an array of type defined by
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length w*h*getNumDataElements().
      *                 If null an array of appropriate type and size will be
      *                 allocated.
@@ -315,8 +315,8 @@
      * </pre>
      * @param x        The X coordinate of the upper left pixel location.
      * @param y        The Y coordinate of the upper left pixel location.
-     * @param width    Width of the pixel rectangle.
-     * @param height   Height of the pixel rectangle.
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
      * @param band     The band to return.
      * @param outData  If non-null, data elements for all bands
      *                 at the specified location are returned in this array.
@@ -363,8 +363,8 @@
      * </pre>
      * @param x        The X coordinate of the upper left pixel location.
      * @param y        The Y coordinate of the upper left pixel location.
-     * @param width    Width of the pixel rectangle.
-     * @param height   Height of the pixel rectangle.
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
      * @param outData  If non-null, data elements for all bands
      *                 at the specified location are returned in this array.
      * @return         Data array with data elements for all bands.
@@ -407,7 +407,7 @@
      * and references anything other than an array of transferType.
      * @param x        The X coordinate of the pixel location.
      * @param y        The Y coordinate of the pixel location.
-     * @param inData   An object reference to an array of type defined by
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length getNumDataElements()
      *                 containing the pixel data to place at x,y.
      */
@@ -503,7 +503,7 @@
      * @param y        The Y coordinate of the upper left pixel location.
      * @param w        Width of the pixel rectangle.
      * @param h        Height of the pixel rectangle.
-     * @param inData   An object reference to an array of type defined by
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length w*h*getNumDataElements()
      *                 containing the pixel data to place between x,y and
      *                 x+h, y+h.
--- a/jdk/src/java.desktop/share/classes/sun/awt/image/ShortComponentRaster.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ShortComponentRaster.java	Wed Jul 05 20:37:09 2017 +0200
@@ -252,7 +252,7 @@
      * and references anything other than an array of transferType.
      * @param x        The X coordinate of the pixel location.
      * @param y        The Y coordinate of the pixel location.
-     * @param outData  An object reference to an array of type defined by
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length getNumDataElements().
      *                 If null an array of appropriate type and size will be
      *                 allocated.
@@ -298,9 +298,9 @@
      * </pre>
      * @param x        The X coordinate of the upper left pixel location.
      * @param y        The Y coordinate of the upper left pixel location.
-     * @param width    Width of the pixel rectangle.
-     * @param height   Height of the pixel rectangle.
-     * @param outData  An object reference to an array of type defined by
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length w*h*getNumDataElements().
      *                 If null an array of appropriate type and size will be
      *                 allocated.
@@ -351,8 +351,8 @@
      * </pre>
      * @param x        The X coordinate of the upper left pixel location.
      * @param y        The Y coordinate of the upper left pixel location.
-     * @param width    Width of the sample rectangle.
-     * @param height   Height of the sample rectangle.
+     * @param w        Width of the sample rectangle.
+     * @param h        Height of the sample rectangle.
      * @param band     The band to return.
      * @param outData  If non-null, data elements for all bands
      *                 at the specified location are returned in this array.
@@ -414,8 +414,8 @@
      * </pre>
      * @param x        The X coordinate of the upper left pixel location.
      * @param y        The Y coordinate of the upper left pixel location.
-     * @param width    Width of the pixel rectangle.
-     * @param height   Height of the pixel rectangle.
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
      * @param outData  If non-null, data elements for all bands
      *                 at the specified location are returned in this array.
      * @return         Data array with data elements for all bands.
@@ -456,7 +456,7 @@
      * and references anything other than an array of transferType.
      * @param x        The X coordinate of the pixel location.
      * @param y        The Y coordinate of the pixel location.
-     * @param inData   An object reference to an array of type defined by
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length getNumDataElements()
      *                 containing the pixel data to place at x,y.
      */
@@ -553,7 +553,7 @@
      * @param y        The Y coordinate of the upper left pixel location.
      * @param w        Width of the pixel rectangle.
      * @param h        Height of the pixel rectangle.
-     * @param inData   An object reference to an array of type defined by
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length w*h*getNumDataElements()
      *                 containing the pixel data to place between x,y and
      *                 x+h, y+h.
--- a/jdk/src/java.desktop/share/classes/sun/awt/image/ShortInterleavedRaster.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ShortInterleavedRaster.java	Wed Jul 05 20:37:09 2017 +0200
@@ -225,7 +225,7 @@
      * and references anything other than an array of transferType.
      * @param x        The X coordinate of the pixel location.
      * @param y        The Y coordinate of the pixel location.
-     * @param outData  An object reference to an array of type defined by
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length getNumDataElements().
      *                 If null an array of appropriate type and size will be
      *                 allocated.
@@ -271,9 +271,9 @@
      * </pre>
      * @param x        The X coordinate of the upper left pixel location.
      * @param y        The Y coordinate of the upper left pixel location.
-     * @param width    Width of the pixel rectangle.
-     * @param height   Height of the pixel rectangle.
-     * @param outData  An object reference to an array of type defined by
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length w*h*getNumDataElements().
      *                 If null an array of appropriate type and size will be
      *                 allocated.
@@ -324,8 +324,8 @@
      * </pre>
      * @param x        The X coordinate of the upper left pixel location.
      * @param y        The Y coordinate of the upper left pixel location.
-     * @param width    Width of the sample rectangle.
-     * @param height   Height of the sample rectangle.
+     * @param w        Width of the sample rectangle.
+     * @param h        Height of the sample rectangle.
      * @param band     The band to return.
      * @param outData  If non-null, data elements for all bands
      *                 at the specified location are returned in this array.
@@ -387,8 +387,8 @@
      * </pre>
      * @param x        The X coordinate of the upper left pixel location.
      * @param y        The Y coordinate of the upper left pixel location.
-     * @param width    Width of the pixel rectangle.
-     * @param height   Height of the pixel rectangle.
+     * @param w        Width of the pixel rectangle.
+     * @param h        Height of the pixel rectangle.
      * @param outData  If non-null, data elements for all bands
      *                 at the specified location are returned in this array.
      * @return         Data array with data elements for all bands.
@@ -429,7 +429,7 @@
      * and references anything other than an array of transferType.
      * @param x        The X coordinate of the pixel location.
      * @param y        The Y coordinate of the pixel location.
-     * @param inData   An object reference to an array of type defined by
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length getNumDataElements()
      *                 containing the pixel data to place at x,y.
      */
@@ -525,7 +525,7 @@
      * @param y        The Y coordinate of the upper left pixel location.
      * @param w        Width of the pixel rectangle.
      * @param h        Height of the pixel rectangle.
-     * @param inData   An object reference to an array of type defined by
+     * @param obj      An object reference to an array of type defined by
      *                 getTransferType() and length w*h*getNumDataElements()
      *                 containing the pixel data to place between x,y and
      *                 x+h, y+h.
--- a/jdk/src/java.desktop/share/classes/sun/awt/shell/ShellFolderColumnInfo.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/shell/ShellFolderColumnInfo.java	Wed Jul 05 20:37:09 2017 +0200
@@ -40,7 +40,7 @@
     private SortOrder sortOrder;
     private Comparator<?> comparator;
     /**
-     * <code>false</code> (default) if the {@link comparator} expects folders as arguments,
+     * <code>false</code> (default) if the {@link #comparator} expects folders as arguments,
      * and <code>true</code> if folder's column values. The first option is used default for comparison
      * on Windows and also for separating files from directories when sorting using
      * ShellFolderManager's inner comparator.
--- a/jdk/src/java.desktop/share/classes/sun/awt/util/IdentityArrayList.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/util/IdentityArrayList.java	Wed Jul 05 20:37:09 2017 +0200
@@ -68,7 +68,7 @@
  * synchronizing on some object that naturally encapsulates the list.
  *
  * If no such object exists, the list should be "wrapped" using the
- * {@link Collections#synchronizedList Collections.synchronizedList}
+ * {@link java.util.Collections#synchronizedList Collections.synchronizedList}
  * method.  This is best done at creation time, to prevent accidental
  * unsynchronized access to the list:<pre>
  *   List list = Collections.synchronizedList(new IdentityArrayList(...));</pre>
--- a/jdk/src/java.desktop/share/classes/sun/awt/util/IdentityLinkedList.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/util/IdentityLinkedList.java	Wed Jul 05 20:37:09 2017 +0200
@@ -41,7 +41,7 @@
  * the <tt>IdentityLinkedList</tt> class provides uniformly named methods to
  * <tt>get</tt>, <tt>remove</tt> and <tt>insert</tt> an element at the
  * beginning and end of the list.  These operations allow linked lists to be
- * used as a stack, {@linkplain Queue queue}, or {@linkplain Deque
+ * used as a stack, {@linkplain java.util.Queue queue}, or {@linkplain Deque
  * double-ended queue}. <p>
  *
  * The class implements the <tt>Deque</tt> interface, providing
@@ -62,7 +62,7 @@
  * encapsulates the list.
  *
  * If no such object exists, the list should be "wrapped" using the
- * {@link Collections#synchronizedList Collections.synchronizedList}
+ * {@link java.util.Collections#synchronizedList Collections.synchronizedList}
  * method.  This is best done at creation time, to prevent accidental
  * unsynchronized access to the list:<pre>
  *   List list = Collections.synchronizedList(new IdentityLinkedList(...));</pre>
@@ -478,7 +478,7 @@
      * Adds the specified element as the tail (last element) of this list.
      *
      * @param e the element to add
-     * @return <tt>true</tt> (as specified by {@link Queue#offer})
+     * @return <tt>true</tt> (as specified by {@link java.util.Queue#offer})
      * @since 1.5
      */
     public boolean offer(E e) {
--- a/jdk/src/java.desktop/share/classes/sun/font/ScriptRun.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/font/ScriptRun.java	Wed Jul 05 20:37:09 2017 +0200
@@ -138,7 +138,7 @@
      * Get the script code for the script of the current script run.
      *
      * @return the script code for the script of the current script run.
-     * @see #Script
+     * @see Script
      */
     public int getScriptCode() {
         return scriptCode;
@@ -274,7 +274,7 @@
      * @param scriptOne one of the script codes.
      * @param scriptTwo the other script code.
      * @return <code>true</code> if the two scripts are the same.
-     * @see com.ibm.icu.lang.Script
+     * @see Script
      */
     private static boolean sameScript(int scriptOne, int scriptTwo) {
         return scriptOne == scriptTwo || scriptOne <= Script.INHERITED || scriptTwo <= Script.INHERITED;
--- a/jdk/src/java.desktop/share/classes/sun/font/StandardTextSource.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/font/StandardTextSource.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,42 +33,43 @@
 import java.awt.font.FontRenderContext;
 import java.awt.font.LineMetrics;
 
-public class StandardTextSource extends TextSource {
-  char[] chars;
-  int start;
-  int len;
-  int cstart;
-  int clen;
-  int level; // assumed all uniform
-  int flags; // see GlyphVector.java
-  Font font;
-  FontRenderContext frc;
-  CoreMetrics cm;
+final class StandardTextSource extends TextSource {
+
+    private final char[] chars;
+    private final int start;
+    private final int len;
+    private final int cstart;
+    private final int clen;
+    private final int level; // assumed all uniform
+    private final int flags; // see GlyphVector.java
+    private final Font font;
+    private final FontRenderContext frc;
+    private final CoreMetrics cm;
 
-  /**
-   * Create a simple implementation of a TextSource.
-   *
-   * Chars is an array containing clen chars in the context, in
-   * logical order, contiguously starting at cstart.  Start and len
-   * represent that portion of the context representing the true
-   * source; start, like cstart, is relative to the start of the
-   * character array.
-   *
-   * Level is the bidi level (0-63 for the entire context. Flags is
-   * the layout flags. Font is the font, frc is the render context,
-   * and lm is the line metrics for the entire source text, but not
-   * necessarily the context.
-   */
-  public StandardTextSource(char[] chars,
-                            int start,
-                            int len,
-                            int cstart,
-                            int clen,
-                            int level,
-                            int flags,
-                            Font font,
-                            FontRenderContext frc,
-                            CoreMetrics cm) {
+    /**
+     * Create a simple implementation of a TextSource.
+     *
+     * Chars is an array containing clen chars in the context, in
+     * logical order, contiguously starting at cstart.  Start and len
+     * represent that portion of the context representing the true
+     * source; start, like cstart, is relative to the start of the
+     * character array.
+     *
+     * Level is the bidi level (0-63 for the entire context. Flags is
+     * the layout flags. Font is the font, frc is the render context,
+     * and lm is the line metrics for the entire source text, but not
+     * necessarily the context.
+     */
+    StandardTextSource(char[] chars,
+                       int start,
+                       int len,
+                       int cstart,
+                       int clen,
+                       int level,
+                       int flags,
+                       Font font,
+                       FontRenderContext frc,
+                       CoreMetrics cm) {
     if (chars == null) {
       throw new IllegalArgumentException("bad chars: null");
     }
@@ -97,7 +98,7 @@
       throw new IllegalArgumentException("bad frc: null");
     }
 
-    this.chars = chars.clone();
+    this.chars = chars;
     this.start = start;
     this.len = len;
     this.cstart = cstart;
@@ -115,40 +116,10 @@
     }
   }
 
-  /** Create a StandardTextSource whose context is coextensive with the source. */
-  public StandardTextSource(char[] chars,
-                            int start,
-                            int len,
-                            int level,
-                            int flags,
-                            Font font,
-                            FontRenderContext frc,
-                            CoreMetrics cm) {
-    this(chars, start, len, start, len, level, flags, font, frc, cm);
-  }
-
-  /** Create a StandardTextSource whose context and source are coextensive with the entire char array. */
-  public StandardTextSource(char[] chars,
-                            int level,
-                            int flags,
-                            Font font,
-                            FontRenderContext frc) {
-    this(chars, 0, chars.length, 0, chars.length, level, flags, font, frc, null);
-  }
-
-  /** Create a StandardTextSource whose context and source are all the text in the String. */
-  public StandardTextSource(String str,
-                            int level,
-                            int flags,
-                            Font font,
-                            FontRenderContext frc) {
-    this(str.toCharArray(), 0, str.length(), 0, str.length(), level, flags, font, frc, null);
-  }
-
   // TextSource API
 
   public char[] getChars() {
-    return chars.clone();
+    return chars;
   }
 
   public int getStart() {
--- a/jdk/src/java.desktop/share/classes/sun/font/TextLabelFactory.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/font/TextLabelFactory.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -41,19 +41,19 @@
    *
    * @see Font
    * @see FontRenderContext
-   * @see GlyphVector
+   * @see java.awt.font.GlyphVector
    * @see TextLabel
    * @see ExtendedTextLabel
    * @see Bidi
-   * @see TextLayout
+   * @see java.awt.font.TextLayout
    */
 
-public class TextLabelFactory {
-  private FontRenderContext frc;
-  private char[] text;
-  private Bidi bidi;
+public final class TextLabelFactory {
+  private final FontRenderContext frc;
+  private final char[] text;
+  private final Bidi bidi;
   private Bidi lineBidi;
-  private int flags;
+  private final int flags;
   private int lineStart;
   private int lineLimit;
 
--- a/jdk/src/java.desktop/share/classes/sun/java2d/NullSurfaceData.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/NullSurfaceData.java	Wed Jul 05 20:37:09 2017 +0200
@@ -86,7 +86,7 @@
      * In most cases, the returned Raster might contain more pixels
      * than requested.
      *
-     * @see useTightBBoxes
+     * @see #useTightBBoxes
      */
     public Raster getRaster(int x, int y, int w, int h) {
         throw new InvalidPipeException("should be NOP");
@@ -101,7 +101,7 @@
      * the pixels has to be made when doing a getRaster.  The
      * fewer pixels copied, the faster the operation will go.
      *
-     * @see getRaster
+     * @see #getRaster
      */
     public boolean useTightBBoxes() {
         return false;
--- a/jdk/src/java.desktop/share/classes/sun/java2d/SunCompositeContext.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/SunCompositeContext.java	Wed Jul 05 20:37:09 2017 +0200
@@ -88,13 +88,13 @@
      * @param src2 The second source tile for the compositing operation.
      * @param dst The tile where the result of the operation is stored.
      */
-    public void compose(Raster srcArg, Raster dstIn, WritableRaster dstOut) {
+    public void compose(Raster src1, Raster src2, WritableRaster dst) {
         WritableRaster src;
         int w;
         int h;
 
-        if (dstIn != dstOut) {
-            dstOut.setDataElements(0, 0, dstIn);
+        if (src2 != dst) {
+            dst.setDataElements(0, 0, src2);
         }
 
         // REMIND: We should be able to create a SurfaceData from just
@@ -102,20 +102,20 @@
         // create a SurfaceData from a BufferedImage then we need to
         // make a WritableRaster since it is needed to construct a
         // BufferedImage.
-        if (srcArg instanceof WritableRaster) {
-            src = (WritableRaster) srcArg;
+        if (src1 instanceof WritableRaster) {
+            src = (WritableRaster) src1;
         } else {
-            src = srcArg.createCompatibleWritableRaster();
-            src.setDataElements(0, 0, srcArg);
+            src = src1.createCompatibleWritableRaster();
+            src.setDataElements(0, 0, src1);
         }
 
-        w = Math.min(src.getWidth(), dstIn.getWidth());
-        h = Math.min(src.getHeight(), dstIn.getHeight());
+        w = Math.min(src.getWidth(), src2.getWidth());
+        h = Math.min(src.getHeight(), src2.getHeight());
 
         BufferedImage srcImg = new BufferedImage(srcCM, src,
                                                  srcCM.isAlphaPremultiplied(),
                                                  null);
-        BufferedImage dstImg = new BufferedImage(dstCM, dstOut,
+        BufferedImage dstImg = new BufferedImage(dstCM, dst,
                                                  dstCM.isAlphaPremultiplied(),
                                                  null);
 
--- a/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java	Wed Jul 05 20:37:09 2017 +0200
@@ -874,13 +874,13 @@
      * space.  The rendering attributes taken into account include the
      * clip, transform, and stroke attributes.
      * @param rect The area in device space to check for a hit.
-     * @param p The path to check for a hit.
+     * @param s The path to check for a hit.
      * @param onStroke Flag to choose between testing the stroked or
      * the filled path.
      * @return True if there is a hit, false otherwise.
      * @see #setStroke
-     * @see #fillPath
-     * @see #drawPath
+     * @see #fill(Shape)
+     * @see #draw(Shape)
      * @see #transform
      * @see #setTransform
      * @see #clip
@@ -1295,7 +1295,7 @@
 
     /**
      * Returns the preferences for the rendering algorithms.
-     * @param hintCategory The category of hint to be set. The strings
+     * @param hintKey The category of hint to be set. The strings
      * are defined in the RenderingHints class.
      * @return The preferences for rendering algorithms. The strings
      * are defined in the RenderingHints class.
@@ -1577,7 +1577,7 @@
      * Cx'(p) = Cx(Tx(p)).
      * A copy of the Tx is made, if necessary, so further
      * modifications to Tx do not affect rendering.
-     * @param Tx The Transform object to be composed with the current
+     * @param xform The Transform object to be composed with the current
      * transform.
      * @see #setTransform
      * @see AffineTransform
@@ -1606,7 +1606,6 @@
      * Sets the Transform in the current graphics state.
      * @param Tx The Transform object to be used in the rendering process.
      * @see #transform
-     * @see TransformChain
      * @see AffineTransform
      */
     @Override
@@ -1789,8 +1788,8 @@
      * of the component, use appropriate methods of the component.
      * @param color The background color that should be used in
      * subsequent calls to clearRect().
-     * @see getBackground
-     * @see Graphics.clearRect()
+     * @see #getBackground
+     * @see Graphics#clearRect
      */
     public void setBackground(Color color) {
         backgroundColor = color;
@@ -1798,7 +1797,7 @@
 
     /**
      * Returns the background color used for clearing a region.
-     * @see setBackground
+     * @see #setBackground
      */
     public Color getBackground() {
         return backgroundColor;
@@ -1806,7 +1805,7 @@
 
     /**
      * Returns the current Stroke in the Graphics2D state.
-     * @see setStroke
+     * @see #setStroke
      */
     public Stroke getStroke() {
         return stroke;
@@ -2056,7 +2055,7 @@
      * with the current transform in the Graphics2D state before being
      * intersected with the current clip. This method is used to make the
      * current clip smaller. To make the clip larger, use any setClip method.
-     * @param p The Path to be intersected with the current clip.
+     * @param s The Path to be intersected with the current clip.
      */
     public void clip(Shape s) {
         s = transformShape(s);
@@ -2483,7 +2482,7 @@
      * Strokes the outline of a Path using the settings of the current
      * graphics state.  The rendering attributes applied include the
      * clip, transform, paint or color, composite and stroke attributes.
-     * @param p The path to be drawn.
+     * @param s The path to be drawn.
      * @see #setStroke
      * @see #setPaint
      * @see java.awt.Graphics#setColor
--- a/jdk/src/java.desktop/share/classes/sun/java2d/SurfaceData.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/SurfaceData.java	Wed Jul 05 20:37:09 2017 +0200
@@ -939,7 +939,7 @@
      * In most cases, the returned Raster might contain more pixels
      * than requested.
      *
-     * @see useTightBBoxes
+     * @see #useTightBBoxes
      */
     public abstract Raster getRaster(int x, int y, int w, int h);
 
@@ -952,7 +952,7 @@
      * the pixels has to be made when doing a getRaster.  The
      * fewer pixels copied, the faster the operation will go.
      *
-     * @see getRaster
+     * @see #getRaster
      */
     public boolean useTightBBoxes() {
         // Note: The native equivalent would trigger on VISIBLE_TO_NATIVE
--- a/jdk/src/java.desktop/share/classes/sun/java2d/pipe/PixelToParallelogramConverter.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/pipe/PixelToParallelogramConverter.java	Wed Jul 05 20:37:09 2017 +0200
@@ -56,7 +56,7 @@
      * @param minPenSize minimum pen size for dropout control
      * @param normPosition sub-pixel location to normalize endpoints
      *                     for STROKE_NORMALIZE cases
-     * @param adjustFill boolean to control whethere normalization
+     * @param adjustfill boolean to control whethere normalization
      *                   constants are also applied to fill operations
      *                   (normally true for non-AA, false for AA)
      */
--- a/jdk/src/java.desktop/share/classes/sun/java2d/pipe/RenderingEngine.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/pipe/RenderingEngine.java	Wed Jul 05 20:37:09 2017 +0200
@@ -66,7 +66,7 @@
  * line width can get before dropouts occur.  Rendering with a BasicStroke
  * is defined to never allow the line to have breaks, gaps, or dropouts
  * even if the width is set to 0.0f, so this information allows the
- * {@link SunGraphics2D} class to detect the "thin line" case and set
+ * {@link sun.java2d.SunGraphics2D} class to detect the "thin line" case and set
  * the rendering attributes accordingly.
  * </dl>
  * At startup the runtime will load a single instance of this class.
@@ -177,11 +177,11 @@
      * The specified {@code src} {@link Shape} is widened according
      * to the parameters specified by the {@link BasicStroke} object.
      * Adjustments are made to the path as appropriate for the
-     * {@link VALUE_STROKE_NORMALIZE} hint if the {@code normalize}
-     * boolean parameter is true.
+     * {@link java.awt.RenderingHints#VALUE_STROKE_NORMALIZE} hint if the
+     * {@code normalize} boolean parameter is true.
      * Adjustments are made to the path as appropriate for the
-     * {@link VALUE_ANTIALIAS_ON} hint if the {@code antialias}
-     * boolean parameter is true.
+     * {@link java.awt.RenderingHints#VALUE_ANTIALIAS_ON} hint if the
+     * {@code antialias} boolean parameter is true.
      * <p>
      * The geometry of the widened path is forwarded to the indicated
      * {@link PathConsumer2D} object as it is calculated.
--- a/jdk/src/java.desktop/share/classes/sun/java2d/pipe/hw/AccelDeviceEventNotifier.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/pipe/hw/AccelDeviceEventNotifier.java	Wed Jul 05 20:37:09 2017 +0200
@@ -137,7 +137,7 @@
      *
      * @param screen a screen number with which the device which is a source of
      * the event is associated with
-     * @param eventType a type of the event
+     * @param deviceEventType a type of the event
      * @see #DEVICE_DISPOSED
      * @see #DEVICE_RESET
      */
--- a/jdk/src/java.desktop/share/classes/sun/java2d/pipe/hw/AccelGraphicsConfig.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/pipe/hw/AccelGraphicsConfig.java	Wed Jul 05 20:37:09 2017 +0200
@@ -77,7 +77,7 @@
      * events.
      *
      * Note: a hard link to the listener may be kept so it must be explicitly
-     * removed via {@link #removeDeviceEventListener()}.
+     * removed via {@link #removeDeviceEventListener}.
      *
      * @param l the listener
      * @see AccelDeviceEventListener
--- a/jdk/src/java.desktop/share/classes/sun/java2d/pipe/hw/ContextCapabilities.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/pipe/hw/ContextCapabilities.java	Wed Jul 05 20:37:09 2017 +0200
@@ -65,7 +65,7 @@
     /**
      * Constructs a {@code ContextCapabilities} object.
      * @param caps an {@code int} representing the capabilities
-     * @param a {@code String} representing the name of the adapter, or null,
+     * @param adapterId {@code String} representing the name of the adapter, or null,
      * in which case the adapterId will be set to "unknown adapter".
      */
     protected ContextCapabilities(int caps, String adapterId) {
--- a/jdk/src/java.desktop/share/classes/sun/java2d/pisces/PiscesCache.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/pisces/PiscesCache.java	Wed Jul 05 20:37:09 2017 +0200
@@ -29,8 +29,6 @@
 
 /**
  * An object used to cache pre-rendered complex paths.
- *
- * @see PiscesRenderer#render
  */
 final class PiscesCache {
 
--- a/jdk/src/java.desktop/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java	Wed Jul 05 20:37:09 2017 +0200
@@ -108,11 +108,11 @@
      * The specified {@code src} {@link Shape} is widened according
      * to the parameters specified by the {@link BasicStroke} object.
      * Adjustments are made to the path as appropriate for the
-     * {@link VALUE_STROKE_NORMALIZE} hint if the {@code normalize}
-     * boolean parameter is true.
+     * {@link java.awt.RenderingHints#VALUE_STROKE_NORMALIZE} hint if the
+     * {@code normalize} boolean parameter is true.
      * Adjustments are made to the path as appropriate for the
-     * {@link VALUE_ANTIALIAS_ON} hint if the {@code antialias}
-     * boolean parameter is true.
+     * {@link java.awt.RenderingHints#VALUE_ANTIALIAS_ON} hint if the
+     * {@code antialias} boolean parameter is true.
      * <p>
      * The geometry of the widened path is forwarded to the indicated
      * {@link PathConsumer2D} object as it is calculated.
--- a/jdk/src/java.desktop/share/classes/sun/print/DialogOwner.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/print/DialogOwner.java	Wed Jul 05 20:37:09 2017 +0200
@@ -45,10 +45,9 @@
     private Frame dlgOwner;
 
     /**
-     * Construct a new dialog type selection enumeration value with the
-     * given integer value.
+     * Construct a new dialog owner attribute with the given frame.
      *
-     * @param  value  Integer value.
+     * @param  frame the frame that owns the print dialog
      */
     public DialogOwner(Frame frame) {
         dlgOwner = frame;
--- a/jdk/src/java.desktop/share/classes/sun/print/OpenBook.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/print/OpenBook.java	Wed Jul 05 20:37:09 2017 +0200
@@ -74,8 +74,8 @@
 
     /**
      * Return the PageFormat of the page specified by 'pageIndex'.
-     * @param int The zero based index of the page whose
-     *            PageFormat is being requested.
+     * @param pageIndex The zero based index of the page whose
+     *                  PageFormat is being requested.
      * @return The PageFormat describing the size and orientation
      */
     public PageFormat getPageFormat(int pageIndex) {
@@ -85,8 +85,8 @@
     /**
      * Return the Printable instance responsible for rendering
      * the page specified by 'pageIndex'.
-     * @param int The zero based index of the page whose
-     *            Printable is being requested.
+     * @param pageIndex The zero based index of the page whose
+     *                  Printable is being requested.
      * @return The Printable that will draw the page.
      */
     public Printable getPrintable(int pageIndex)
--- a/jdk/src/java.desktop/share/classes/sun/print/PSPathGraphics.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/print/PSPathGraphics.java	Wed Jul 05 20:37:09 2017 +0200
@@ -126,7 +126,7 @@
      * such as Hebrew and Arabic, the glyphs can be rendered from right to
      * left, in which case the coordinate supplied is the location of the
      * leftmost character on the baseline.
-     * @param s the <code>String</code> to be rendered
+     * @param str the <code>String</code> to be rendered
      * @param x,&nbsp;y the coordinates where the <code>String</code>
      * should be rendered
      * @see #setPaint
@@ -256,7 +256,7 @@
      * is transformed by the supplied AffineTransform and
      * drawn using PS to the printer context.
      *
-     * @param   img     The image to be drawn.
+     * @param   image   The image to be drawn.
      *                  This method does nothing if <code>img</code> is null.
      * @param   xform   Used to transform the image before drawing.
      *                  This can be null.
--- a/jdk/src/java.desktop/share/classes/sun/print/PeekGraphics.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/print/PeekGraphics.java	Wed Jul 05 20:37:09 2017 +0200
@@ -361,9 +361,9 @@
      * use this font.
      * @param  font   the font.
      * @see     java.awt.Graphics#getFont
-     * @see     java.awt.Graphics#drawChars(java.lang.String, int, int)
-     * @see     java.awt.Graphics#drawString(byte[], int, int, int, int)
-     * @see     java.awt.Graphics#drawBytes(char[], int, int, int, int)
+     * @see     java.awt.Graphics#drawChars(char[], int, int, int, int)
+     * @see     java.awt.Graphics#drawString(String, int, int)
+     * @see     java.awt.Graphics#drawBytes(byte[], int, int, int, int)
      * @since   1.0
     */
     public void setFont(Font font) {
@@ -1446,7 +1446,7 @@
      * Draws a string of text.
      * The rendering attributes applied include the clip, transform,
      * paint or color, font and composite attributes.
-     * @param s The string to be drawn.
+     * @param str The string to be drawn.
      * @param x,y The coordinates where the string should be drawn.
      * @see #setPaint
      * @see java.awt.Graphics#setColor
@@ -1548,7 +1548,7 @@
      * @param comp The Composite object to be used for drawing.
      * @see java.awt.Graphics#setXORMode
      * @see java.awt.Graphics#setPaintMode
-     * @see AlphaComposite
+     * @see java.awt.AlphaComposite
      */
     public void setComposite(Composite comp) {
         mGraphics.setComposite(comp);
@@ -1560,8 +1560,8 @@
      * @param paint The Paint object to be used to generate color in
      * the rendering process.
      * @see java.awt.Graphics#setColor
-     * @see GradientPaint
-     * @see TexturePaint
+     * @see java.awt.GradientPaint
+     * @see java.awt.TexturePaint
      */
     public void setPaint(Paint paint) {
         mGraphics.setPaint(paint);
@@ -1594,7 +1594,7 @@
      * Returns the preferences for the rendering algorithms.
      * @param hintCategory The category of hint to be set.
      * @return The preferences for rendering algorithms.
-     * @see RenderingHings
+     * @see RenderingHints
      */
     public Object getRenderingHint(Key hintCategory) {
         return mGraphics.getRenderingHint(hintCategory);
@@ -1647,7 +1647,6 @@
      * @param Tx The Transform object to be composed with the current
      * transform.
      * @see #setTransform
-     * @see TransformChain
      * @see AffineTransform
      */
     public void transform(AffineTransform Tx) {
@@ -1658,7 +1657,6 @@
      * Sets the Transform in the current graphics state.
      * @param Tx The Transform object to be used in the rendering process.
      * @see #transform
-     * @see TransformChain
      * @see AffineTransform
      */
     public void setTransform(AffineTransform Tx) {
@@ -1700,8 +1698,8 @@
      * of the component, use appropriate methods of the component.
      * @param color The background color that should be used in
      * subsequent calls to clearRect().
-     * @see getBackground
-     * @see Graphics.clearRect()
+     * @see #getBackground
+     * @see Graphics#clearRect
      */
     public void setBackground(Color color) {
         mGraphics.setBackground(color);
@@ -1709,7 +1707,7 @@
 
     /**
      * Returns the background color used for clearing a region.
-     * @see setBackground
+     * @see #setBackground
      */
     public Color getBackground() {
         return mGraphics.getBackground();
@@ -1717,7 +1715,7 @@
 
     /**
      * Returns the current Stroke in the Graphics2D state.
-     * @see setStroke
+     * @see #setStroke
      */
     public Stroke getStroke() {
         return mGraphics.getStroke();
--- a/jdk/src/java.desktop/share/classes/sun/print/PrintJob2D.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/print/PrintJob2D.java	Wed Jul 05 20:37:09 2017 +0200
@@ -79,7 +79,7 @@
  * A class which initiates and executes a print job using
  * the underlying PrinterJob graphics conversions.
  *
- * @see Toolkit#getPrintJob
+ * @see java.awt.Toolkit#getPrintJob
  *
  */
 public class PrintJob2D extends PrintJob implements Printable, Runnable {
@@ -750,7 +750,7 @@
      * The page is sent to the printer when the graphics
      * object is disposed.  This graphics object will also implement
      * the PrintGraphics interface.
-     * @see PrintGraphics
+     * @see java.awt.PrintGraphics
      */
     public Graphics getGraphics() {
 
@@ -937,7 +937,7 @@
      * If the requested page does not exist then this method returns
      * NO_SUCH_PAGE; otherwise PAGE_EXISTS is returned.
      * The <code>Graphics</code> class or subclass implements the
-     * {@link PrinterGraphics} interface to provide additional
+     * {@link java.awt.PrintGraphics} interface to provide additional
      * information.  If the <code>Printable</code> object
      * aborts the print job then it throws a {@link PrinterException}.
      * @param graphics the context into which the page is drawn
--- a/jdk/src/java.desktop/share/classes/sun/print/ProxyGraphics2D.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/print/ProxyGraphics2D.java	Wed Jul 05 20:37:09 2017 +0200
@@ -297,9 +297,9 @@
      * use this font.
      * @param  font   the font.
      * @see     java.awt.Graphics#getFont
-     * @see     java.awt.Graphics#drawChars(java.lang.String, int, int)
-     * @see     java.awt.Graphics#drawString(byte[], int, int, int, int)
-     * @see     java.awt.Graphics#drawBytes(char[], int, int, int, int)
+     * @see     java.awt.Graphics#drawChars(char[], int, int, int, int)
+     * @see     java.awt.Graphics#drawString(String, int, int)
+     * @see     java.awt.Graphics#drawBytes(byte[], int, int, int, int)
      * @since   1.0
     */
     public void setFont(Font font) {
@@ -1345,7 +1345,7 @@
      * Draws a string of text.
      * The rendering attributes applied include the clip, transform,
      * paint or color, font and composite attributes.
-     * @param s The string to be drawn.
+     * @param str The string to be drawn.
      * @param x,y The coordinates where the string should be drawn.
      * @see #setPaint
      * @see java.awt.Graphics#setColor
@@ -1432,7 +1432,7 @@
      * @param comp The Composite object to be used for drawing.
      * @see java.awt.Graphics#setXORMode
      * @see java.awt.Graphics#setPaintMode
-     * @see AlphaComposite
+     * @see java.awt.AlphaComposite
      */
     public void setComposite(Composite comp) {
         mGraphics.setComposite(comp);
@@ -1444,8 +1444,8 @@
      * @param paint The Paint object to be used to generate color in
      * the rendering process.
      * @see java.awt.Graphics#setColor
-     * @see GradientPaint
-     * @see TexturePaint
+     * @see java.awt.GradientPaint
+     * @see java.awt.TexturePaint
      */
     public void setPaint(Paint paint) {
         mGraphics.setPaint(paint);
@@ -1455,7 +1455,7 @@
      * Sets the Stroke in the current graphics state.
      * @param s The Stroke object to be used to stroke a Shape in
      * the rendering process.
-     * @see BasicStroke
+     * @see java.awt.BasicStroke
      */
     public void setStroke(Stroke s) {
         mGraphics.setStroke(s);
@@ -1478,7 +1478,7 @@
      * Returns the preferences for the rendering algorithms.
      * @param hintCategory The category of hint to be set.
      * @return The preferences for rendering algorithms.
-     * @see RenderingHings
+     * @see RenderingHints
      */
     public Object getRenderingHint(Key hintCategory) {
         return mGraphics.getRenderingHint(hintCategory);
@@ -1531,7 +1531,6 @@
      * @param Tx The Transform object to be composed with the current
      * transform.
      * @see #setTransform
-     * @see TransformChain
      * @see AffineTransform
      */
     public void transform(AffineTransform Tx) {
@@ -1542,7 +1541,6 @@
      * Sets the Transform in the current graphics state.
      * @param Tx The Transform object to be used in the rendering process.
      * @see #transform
-     * @see TransformChain
      * @see AffineTransform
      */
     public void setTransform(AffineTransform Tx) {
@@ -1584,8 +1582,8 @@
      * of the component, use appropriate methods of the component.
      * @param color The background color that should be used in
      * subsequent calls to clearRect().
-     * @see getBackground
-     * @see Graphics.clearRect()
+     * @see #getBackground
+     * @see Graphics#clearRect
      */
     public void setBackground(Color color) {
         mGraphics.setBackground(color);
@@ -1593,7 +1591,7 @@
 
     /**
      * Returns the background color used for clearing a region.
-     * @see setBackground
+     * @see #setBackground
      */
     public Color getBackground() {
         return mGraphics.getBackground();
@@ -1601,7 +1599,7 @@
 
     /**
      * Returns the current Stroke in the Graphics2D state.
-     * @see setStroke
+     * @see #setStroke
      */
     public Stroke getStroke() {
         return mGraphics.getStroke();
--- a/jdk/src/java.desktop/share/classes/sun/print/ProxyPrintGraphics.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/print/ProxyPrintGraphics.java	Wed Jul 05 20:37:09 2017 +0200
@@ -69,7 +69,7 @@
      * <code>Graphics</code> object, but with a new translation and
      * clip area.
      * Refer to
-     * {@link sun.print.ProxyGraphics#createGraphics}
+     * {@link sun.print.ProxyGraphics#create(int, int, int, int)}
      * for a complete description of this method.
      * <p>
      * @param      x   the <i>x</i> coordinate.
--- a/jdk/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java	Wed Jul 05 20:37:09 2017 +0200
@@ -498,7 +498,7 @@
      * Throws <code>PrinterException</code> if the specified service
      * cannot support the <code>Pageable</code> and
      * <code>Printable</code> interfaces necessary to support 2D printing.
-     * @param a print service which supports 2D printing.
+     * @param service print service which supports 2D printing.
      *
      * @throws PrinterException if the specified service does not support
      * 2D printing or no longer available.
@@ -1024,7 +1024,7 @@
      * The pages in the document to be printed by this PrinterJob
      * are drawn by the Printable object 'painter'. The PageFormat
      * for each page is the default page format.
-     * @param Printable Called to render each page of the document.
+     * @param painter Called to render each page of the document.
      */
     public void setPrintable(Printable painter) {
         setPageable(new OpenBook(defaultPage(new PageFormat()), painter));
@@ -1034,9 +1034,9 @@
      * The pages in the document to be printed by this PrinterJob
      * are drawn by the Printable object 'painter'. The PageFormat
      * of each page is 'format'.
-     * @param Printable Called to render each page of the document.
-     * @param PageFormat The size and orientation of each page to
-     *                   be printed.
+     * @param painter Called to render each page of the document.
+     * @param format  The size and orientation of each page to
+     *                be printed.
      */
     public void setPrintable(Printable painter, PageFormat format) {
         setPageable(new OpenBook(format, painter));
@@ -1048,7 +1048,7 @@
      * Pageable instance 'document'. 'document' will be queried
      * for the number of pages as well as the PageFormat and
      * Printable for each page.
-     * @param Pageable The document to be printed. It may not be null.
+     * @param document The document to be printed. It may not be null.
      * @exception NullPointerException the Pageable passed in was null.
      * @see PageFormat
      * @see Printable
--- a/jdk/src/java.desktop/share/classes/sun/swing/CachedPainter.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/swing/CachedPainter.java	Wed Jul 05 20:37:09 2017 +0200
@@ -89,7 +89,7 @@
      * @param y Y-coordinate to render to
      * @param w Width to render in
      * @param h Height to render in
-     * @param arg Variable arguments that will be passed to paintToImage
+     * @param args Variable arguments that will be passed to paintToImage
      */
     public void paint(Component c, Graphics g, int x,
                          int y, int w, int h, Object... args) {
--- a/jdk/src/java.desktop/share/classes/sun/swing/UIAction.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/swing/UIAction.java	Wed Jul 05 20:37:09 2017 +0200
@@ -54,7 +54,6 @@
  * <code>isEnabled(Component)</code>, and be aware that the passed in
  * <code>Component</code> may be null.
  *
- * @see com.sun.java.swing.ExtendedAction
  * @see javax.swing.Action
  * @author Scott Violet
  */
--- a/jdk/src/java.desktop/share/classes/sun/swing/plaf/synth/DefaultSynthStyle.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/swing/plaf/synth/DefaultSynthStyle.java	Wed Jul 05 20:37:09 2017 +0200
@@ -289,7 +289,7 @@
     /**
      * Sets the insets.
      *
-     * @param Insets.
+     * @param insets the new insets.
      */
     public void setInsets(Insets insets) {
         this.insets = insets;
@@ -300,7 +300,7 @@
      * insets will be placed in it, otherwise a new Insets object will be
      * created and returned.
      *
-     * @param context SynthContext identifying requestor
+     * @param state SynthContext identifying requestor
      * @param to Where to place Insets
      * @return Insets.
      */
@@ -435,7 +435,7 @@
      * Returns the default value for a particular property.  This is only
      * invoked if this style doesn't define a property for <code>key</code>.
      *
-     * @param state SynthContext identifying requestor
+     * @param context SynthContext identifying requestor
      * @param key Property being requested.
      * @return Value of the named property
      */
@@ -724,8 +724,6 @@
          *
          * @param state Component state(s) that this StateInfo should be used
          * for
-         * @param painter Painter responsible for rendering
-         * @param bgPainter Painter responsible for rendering the background
          * @param font Font for this state
          * @param colors Colors for this state
          */
--- a/jdk/src/java.desktop/share/classes/sun/swing/plaf/synth/Paint9Painter.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/swing/plaf/synth/Paint9Painter.java	Wed Jul 05 20:37:09 2017 +0200
@@ -118,7 +118,7 @@
      * @param dInsets Destination insets specifying the portion of the image
      *                will be stretched or tiled, if <code>null</code> empty
      *                <code>Insets</code> will be used.
-     * @param paintType Specifies what type of algorithm to use in painting
+     * @param type Specifies what type of algorithm to use in painting
      * @param mask Specifies portion of image to render, if
      *             <code>PAINT_ALL</code> is specified, any other regions
      *             specified will not be painted, for example
--- a/jdk/src/java.desktop/share/classes/sun/swing/text/TextComponentPrintable.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/swing/text/TextComponentPrintable.java	Wed Jul 05 20:37:09 2017 +0200
@@ -212,7 +212,7 @@
      * level {@code JEditorPanes}.  For instance if there is a frame
      * inside the frame it will return the top frame only.
      *
-     * @param c the container to find all frames under
+     * @param container the container to find all frames under
      * @param list {@code List} to append the results too
      */
     private static void getFrames(final Container container, List<JEditorPane> list) {
--- a/jdk/src/java.desktop/unix/classes/sun/awt/FcFontManager.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/FcFontManager.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -98,8 +98,7 @@
         return info;
     }
 
-    protected native String getFontPathNative(boolean noType1Fonts,
-                                              boolean isX11GE);
+    native String getFontPathNative(boolean noType1Fonts, boolean isX11GE);
 
     protected synchronized String getFontPath(boolean noType1Fonts) {
         return getFontPathNative(noType1Fonts, false);
--- a/jdk/src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java	Wed Jul 05 20:37:09 2017 +0200
@@ -189,7 +189,7 @@
      * @param stockId String which defines the stock id of the gtk item.
      * For a complete list reference the API at www.gtk.org for StockItems.
      * @param iconSize One of the GtkIconSize values defined in GTKConstants
-     * @param textDirection One of the TextDirection values defined in
+     * @param direction One of the TextDirection values defined in
      * GTKConstants
      * @param detail Render detail that is passed to the native engine (feel
      * free to pass null)
--- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XAtom.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XAtom.java	Wed Jul 05 20:37:09 2017 +0200
@@ -338,7 +338,6 @@
 
     /**  Gets the window property for the specified window
      * @param window window id to use
-     * @param str value to set to.
      * @return string with the property.
      * @since 1.5
      */
--- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XComponentPeer.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XComponentPeer.java	Wed Jul 05 20:37:09 2017 +0200
@@ -680,7 +680,6 @@
      *      obtained
      * @return the font metrics for <code>font</code>
      * @see       #getFont
-     * @see       #getPeer
      * @see       java.awt.peer.ComponentPeer#getFontMetrics(Font)
      * @see       Toolkit#getFontMetrics(Font)
      * @since     1.0
--- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XListPeer.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XListPeer.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1952,7 +1952,6 @@
          * Paint the horizontal scrollbar to the screen
          *
          * @param g the graphics context to draw into
-         * @param colors the colors used to draw the scrollbar
          * @param paintAll paint the whole scrollbar if true, just the thumb if false
          */
         void paintHorScrollbar(Graphics g, boolean paintAll) {
@@ -1964,7 +1963,6 @@
          * Paint the vertical scrollbar to the screen
          *
          * @param g the graphics context to draw into
-         * @param colors the colors used to draw the scrollbar
          * @param paintAll paint the whole scrollbar if true, just the thumb if false
          */
         void paintVerScrollbar(Graphics g, boolean paintAll) {
--- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMenuBarPeer.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMenuBarPeer.java	Wed Jul 05 20:37:09 2017 +0200
@@ -222,7 +222,7 @@
     }
 
     /**
-     * @see XBaseMenuWindow.map
+     * @see XBaseMenuWindow#map
      */
     protected MappingData map() {
         XMenuItemPeer[] itemVector = copyItems();
@@ -292,7 +292,7 @@
     }
 
     /**
-     * @see XBaseMenuWindow.getSubmenuBounds
+     * @see XBaseMenuWindow#getSubmenuBounds
      */
     protected Rectangle getSubmenuBounds(Rectangle itemBounds, Dimension windowSize) {
         Rectangle globalBounds = toGlobal(itemBounds);
@@ -362,7 +362,7 @@
      ************************************************/
 
     /**
-     * @see XBaseMenuWindow.doDispose()
+     * @see XBaseMenuWindow#doDispose()
      */
     protected void doDispose() {
         super.doDispose();
@@ -388,7 +388,7 @@
 
     /**
      * Performs ungrabbing of input
-     * @see XBaseWindow.ungrabInputImpl()
+     * @see XBaseWindow#ungrabInputImpl()
      */
     void ungrabInputImpl() {
         selectItem(null, false);
--- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMenuItemPeer.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMenuItemPeer.java	Wed Jul 05 20:37:09 2017 +0200
@@ -437,7 +437,7 @@
      * Sets mapping of item to window.
      * @param bounds bounds of item in container's coordinates
      * @param textOrigin point for drawString in container's coordinates
-     * @see XBaseMenuWindow.map()
+     * @see XBaseMenuWindow#map()
      */
     void map(Rectangle bounds, Point textOrigin) {
         this.bounds = bounds;
--- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMenuWindow.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMenuWindow.java	Wed Jul 05 20:37:09 2017 +0200
@@ -192,14 +192,14 @@
      ************************************************/
 
     /**
-     * @see XBaseMenuWindow.getParentMenuWindow()
+     * @see XBaseMenuWindow#getParentMenuWindow()
      */
     protected XBaseMenuWindow getParentMenuWindow() {
         return (menuPeer != null) ? menuPeer.getContainer() : null;
     }
 
     /**
-     * @see XBaseMenuWindow.map()
+     * @see XBaseMenuWindow#map()
      */
     protected MappingData map() {
         //TODO:Implement popup-menu caption mapping and painting and tear-off
@@ -274,7 +274,7 @@
     }
 
     /**
-     * @see XBaseMenuWindow.getSubmenuBounds()
+     * @see XBaseMenuWindow#getSubmenuBounds
      */
     protected Rectangle getSubmenuBounds(Rectangle itemBounds, Dimension windowSize) {
         Rectangle globalBounds = toGlobal(itemBounds);
--- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XScrollbar.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XScrollbar.java	Wed Jul 05 20:37:09 2017 +0200
@@ -161,8 +161,6 @@
      * paint the scrollbar
      * @param g the graphics context to paint into
      * @param colors the colors to use when painting the scrollbar
-     * @param width the width of the scrollbar
-     * @param height the height of the scrollbar
      * @param paintAll paint the whole scrollbar if true, just the thumb is false
      */
     void paint(Graphics g, Color colors[], boolean paintAll) {
@@ -393,7 +391,7 @@
 
     /**
      * Scroll one unit.
-     * @see notifyValue
+     * @see #notifyValue
      */
     void scroll() {
         switch (mode) {
@@ -607,7 +605,6 @@
      * @param minimum is the minimum value of the scrollbar
      * @param maximum is the maximum value of the scrollbar
      * @param unitSize is the unit size for increment or decrement of the value
-     * @param page is the block size for increment or decrement of the value
      * @see #setValues
      */
     synchronized void setValues(int value, int visible, int minimum, int maximum,
@@ -631,7 +628,7 @@
 
     /**
      * Sets the value of this Scrollbar to the specified value.
-     * @param value the new value of the Scrollbar. If this value is
+     * @param newValue the new value of the Scrollbar. If this value is
      * below the current minimum or above the current maximum minus
      * the visible amount, it becomes the new one of those values,
      * respectively.
@@ -655,7 +652,7 @@
 
     /**
      * Sets the minimum value for this Scrollbar.
-     * @param minimum the minimum value of the scrollbar
+     * @param newMinimum the minimum value of the scrollbar
      */
     synchronized void setMinimum(int newMinimum) {
         /* Use setValues so that a consistent policy
@@ -675,7 +672,7 @@
 
     /**
      * Sets the maximum value for this Scrollbar.
-     * @param maximum the maximum value of the scrollbar
+     * @param newMaximum the maximum value of the scrollbar
      */
     synchronized void setMaximum(int newMaximum) {
         /* Use setValues so that a consistent policy
@@ -694,7 +691,7 @@
     /**
      * Sets the visible amount of this Scrollbar, which is the range
      * of values represented by the width of the scroll bar's bubble.
-     * @param visible the amount visible per page
+     * @param newAmount the amount visible per page
      */
     synchronized void setVisibleAmount(int newAmount) {
         setValues(val, newAmount, min, max);
@@ -759,7 +756,7 @@
 
     /**
      * Returns the scale factor for the thumbArea ( thumbAreaH / (max - min)).
-     * @see #getArrowAreaSize
+     * @see #getArrowAreaWidth
      */
     private double getScaleFactor(){
         double f = (double)(barLength - 2*getArrowAreaWidth()) / Math.max(1,(max - min));
--- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java	Wed Jul 05 20:37:09 2017 +0200
@@ -616,14 +616,19 @@
                         }
                     }
                 }
-                if( keyEventLog.isLoggable(PlatformLogger.Level.FINE) && (ev.get_type() == XConstants.KeyPress || ev.get_type() == XConstants.KeyRelease) ) {
-                    keyEventLog.fine("before XFilterEvent:"+ev);
+                if (keyEventLog.isLoggable(PlatformLogger.Level.FINE) && (
+                        ev.get_type() == XConstants.KeyPress
+                                || ev.get_type() == XConstants.KeyRelease)) {
+                    keyEventLog.fine("before XFilterEvent:" + ev);
                 }
                 if (XlibWrapper.XFilterEvent(ev.getPData(), w)) {
                     continue;
                 }
-                if( keyEventLog.isLoggable(PlatformLogger.Level.FINE) && (ev.get_type() == XConstants.KeyPress || ev.get_type() == XConstants.KeyRelease) ) {
-                    keyEventLog.fine("after XFilterEvent:"+ev); // IS THIS CORRECT?
+                if (keyEventLog.isLoggable(PlatformLogger.Level.FINE) && (
+                        ev.get_type() == XConstants.KeyPress
+                                || ev.get_type() == XConstants.KeyRelease)) {
+                    keyEventLog.fine(
+                            "after XFilterEvent:" + ev); // IS THIS CORRECT?
                 }
 
                 dispatchEvent(ev);
@@ -639,21 +644,28 @@
         }
     }
 
+    /**
+     * Listener installed to detect display changes.
+     */
+    private static final DisplayChangedListener displayChangedHandler =
+            new DisplayChangedListener() {
+                @Override
+                public void displayChanged() {
+                    // 7045370: Reset the cached values
+                    XToolkit.screenWidth = -1;
+                    XToolkit.screenHeight = -1;
+                }
+
+                @Override
+                public void paletteChanged() {
+                }
+            };
+
     static {
         GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
         if (ge instanceof SunGraphicsEnvironment) {
-            ((SunGraphicsEnvironment)ge).addDisplayChangedListener(
-                new DisplayChangedListener() {
-                    @Override
-                    public void displayChanged() {
-                        // 7045370: Reset the cached values
-                        XToolkit.screenWidth = -1;
-                        XToolkit.screenHeight = -1;
-                    }
-
-                    @Override
-                    public void paletteChanged() {}
-            });
+            ((SunGraphicsEnvironment) ge).addDisplayChangedListener(
+                    displayChangedHandler);
         }
     }
 
@@ -663,7 +675,9 @@
             try {
                 XWindowAttributes pattr = new XWindowAttributes();
                 try {
-                    XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), XToolkit.getDefaultRootWindow(), pattr.pData);
+                    XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(),
+                                                     XToolkit.getDefaultRootWindow(),
+                                                     pattr.pData);
                     screenWidth  = pattr.get_width();
                     screenHeight = pattr.get_height();
                 } finally {
--- a/jdk/src/java.desktop/unix/classes/sun/awt/X11FontManager.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11FontManager.java	Wed Jul 05 20:37:09 2017 +0200
@@ -44,7 +44,6 @@
 import sun.font.CompositeFont;
 import sun.font.FontManager;
 import sun.font.SunFontManager;
-import sun.font.FontConfigManager;
 import sun.font.FcFontConfiguration;
 import sun.font.FontAccess;
 import sun.font.FontUtilities;
--- a/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsConfig.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsConfig.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,6 @@
 
 import java.awt.AWTException;
 import java.awt.BufferCapabilities;
-import java.awt.BufferCapabilities.FlipContents;
 import java.awt.Component;
 import java.awt.Toolkit;
 import java.awt.GraphicsConfiguration;
@@ -35,7 +34,6 @@
 import java.awt.Image;
 import java.awt.ImageCapabilities;
 import java.awt.Transparency;
-import java.awt.image.BufferedImage;
 import java.awt.image.ColorModel;
 import java.awt.color.ColorSpace;
 import java.awt.image.ComponentColorModel;
@@ -55,13 +53,12 @@
 import sun.awt.image.OffScreenImage;
 import sun.awt.image.SunVolatileImage;
 import sun.awt.image.SurfaceManager;
-import sun.awt.X11ComponentPeer;
 
 /**
  * This is an implementation of a GraphicsConfiguration object for a
  * single X11 visual.
  *
- * @see GraphicsEnvironment
+ * @see java.awt.GraphicsEnvironment
  * @see GraphicsDevice
  */
 public class X11GraphicsConfig extends GraphicsConfiguration
@@ -314,7 +311,7 @@
         return pGetBounds(screen.getScreen());
     }
 
-    public native Rectangle pGetBounds(int screenNum);
+    private native Rectangle pGetBounds(int screenNum);
 
     private static class XDBECapabilities extends BufferCapabilities {
         public XDBECapabilities() {
--- a/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java	Wed Jul 05 20:37:09 2017 +0200
@@ -52,10 +52,8 @@
  * @see GraphicsEnvironment
  * @see GraphicsConfiguration
  */
-public class X11GraphicsDevice
-    extends GraphicsDevice
-    implements DisplayChangedListener
-{
+public final class X11GraphicsDevice extends GraphicsDevice
+        implements DisplayChangedListener {
     int screen;
     HashMap<SurfaceType, Object> x11ProxyKeyMap = new HashMap<>();
 
@@ -201,16 +199,15 @@
     /*
      * Returns the depth for the given index of graphics configurations.
      */
-    public native int getConfigDepth (int index, int screen);
+    private native int getConfigDepth(int index, int screen);
 
     /*
      * Returns the colormap for the given index of graphics configurations.
      */
-    public native int getConfigColormap (int index, int screen);
-
+    private native int getConfigColormap(int index, int screen);
 
     // Whether or not double-buffering extension is supported
-    public static native boolean isDBESupported();
+    static native boolean isDBESupported();
     // Callback for adding a new double buffer visual into our set
     private void addDoubleBufferVisual(int visNum) {
         doubleBufferVisuals.add(Integer.valueOf(visNum));
--- a/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsEnvironment.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsEnvironment.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,13 +29,6 @@
 import java.awt.GraphicsDevice;
 import java.awt.Point;
 import java.awt.Rectangle;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.FileNotFoundException;
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.StreamTokenizer;
 import java.net.InetAddress;
 import java.net.NetworkInterface;
 import java.net.SocketException;
@@ -43,11 +36,6 @@
 
 import java.util.*;
 
-import sun.font.MFontConfiguration;
-import sun.font.FcFontConfiguration;
-import sun.font.Font2D;
-import sun.font.FontManager;
-import sun.font.NativeFont;
 import sun.java2d.SunGraphicsEnvironment;
 import sun.java2d.SurfaceManagerFactory;
 import sun.java2d.UnixSurfaceManagerFactory;
@@ -60,11 +48,10 @@
  * for X11 environments.
  *
  * @see GraphicsDevice
- * @see GraphicsConfiguration
+ * @see java.awt.GraphicsConfiguration
  */
-public class X11GraphicsEnvironment
-    extends SunGraphicsEnvironment
-{
+public final class X11GraphicsEnvironment extends SunGraphicsEnvironment {
+
     private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11GraphicsEnvironment");
     private static final PlatformLogger screenLog = PlatformLogger.getLogger("sun.awt.screen.X11GraphicsEnvironment");
 
@@ -200,7 +187,7 @@
         return new X11GraphicsDevice(screennum);
     }
 
-    protected native int getDefaultScreenNum();
+    private native int getDefaultScreenNum();
     /**
      * Returns the default screen graphics device.
      */
--- a/jdk/src/java.desktop/unix/classes/sun/awt/X11InputMethod.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11InputMethod.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,16 +35,9 @@
 import java.awt.Container;
 import java.awt.EventQueue;
 import java.awt.Window;
-import java.awt.im.InputContext;
 import java.awt.im.InputMethodHighlight;
 import java.awt.im.spi.InputMethodContext;
 import sun.awt.im.InputMethodAdapter;
-import java.awt.event.InputEvent;
-import java.awt.event.KeyEvent;
-import java.awt.event.MouseEvent;
-import java.awt.event.FocusEvent;
-import java.awt.event.ComponentEvent;
-import java.awt.event.WindowEvent;
 import java.awt.event.InputMethodEvent;
 import java.awt.font.TextAttribute;
 import java.awt.font.TextHitInfo;
@@ -555,7 +548,7 @@
      * method is invoked from the event handler in canvas.c in the
      * AWT Toolkit thread context and thus inside the AWT Lock.
      * @param   str     committed text
-     * @param   long    when
+     * @param   when    when
      */
     // NOTE: This method may be called by privileged threads.
     //       This functionality is implemented in a package-private method
@@ -1095,7 +1088,7 @@
     /*
      * Native methods
      */
-    protected native String resetXIC();
+    private native String resetXIC();
     private native void disposeXIC();
     private native boolean setCompositionEnabledNative(boolean enable);
     private native boolean isCompositionEnabledNative();
--- a/jdk/src/java.desktop/unix/classes/sun/font/FontConfigManager.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/unix/classes/sun/font/FontConfigManager.java	Wed Jul 05 20:37:09 2017 +0200
@@ -436,12 +436,6 @@
         return (fcInfo.compFont = new CompositeFont(physFont, jdkFont));
     }
 
-    /**
-     *
-     * @param locale
-     * @param fcFamily
-     * @return
-     */
     public FcCompFont[] getFontConfigFonts() {
         return fontConfigFonts;
     }
--- a/jdk/src/java.desktop/unix/native/common/awt/utility/rect.h	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/unix/native/common/awt/utility/rect.h	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2014 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2014, 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
--- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_InputMethod.c	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_InputMethod.c	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -904,7 +904,6 @@
 static Bool
 createXIC(JNIEnv * env, X11InputMethodData *pX11IMData, Window w)
 {
-    XIC active_ic, passive_ic;
     XVaNestedList preedit = NULL;
     XVaNestedList status = NULL;
     XIMStyle on_the_spot_styles = XIMPreeditCallbacks,
@@ -974,6 +973,12 @@
     }
 
     if (active_styles == on_the_spot_styles) {
+        pX11IMData->ic_passive = XCreateIC(X11im,
+                                   XNClientWindow, w,
+                                   XNFocusWindow, w,
+                                   XNInputStyle, passive_styles,
+                                   NULL);
+
         callbacks = (XIMCallback *)malloc(sizeof(XIMCallback) * NCALLBACKS);
         if (callbacks == (XIMCallback *)NULL)
             return False;
@@ -1024,12 +1029,6 @@
                                               NULL);
         XFree((void *)preedit);
 #endif /* __linux__ || MACOSX */
-        pX11IMData->ic_passive = XCreateIC(X11im,
-                                           XNClientWindow, w,
-                                           XNFocusWindow, w,
-                                           XNInputStyle, passive_styles,
-                                           NULL);
-
     } else {
         pX11IMData->ic_active = XCreateIC(X11im,
                                           XNClientWindow, w,
--- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c	Wed Jul 05 20:37:09 2017 +0200
@@ -1313,9 +1313,6 @@
             {
                 result = gtk2_widgets[_GTK_COMBO_BOX_TEXT_FIELD_TYPE] =
                      (*fp_gtk_entry_new)();
-
-                GtkSettings* settings = fp_gtk_widget_get_settings(result);
-                fp_g_object_set(settings, "gtk-cursor-blink", FALSE, NULL);
             }
             result = gtk2_widgets[_GTK_COMBO_BOX_TEXT_FIELD_TYPE];
             break;
@@ -1360,10 +1357,6 @@
             {
                 gtk2_widgets[_GTK_ENTRY_TYPE] =
                     (*fp_gtk_entry_new)();
-
-                GtkSettings* settings =
-                    fp_gtk_widget_get_settings(gtk2_widgets[_GTK_ENTRY_TYPE]);
-                fp_g_object_set(settings, "gtk-cursor-blink", FALSE, NULL);
             }
             result = gtk2_widgets[_GTK_ENTRY_TYPE];
             break;
@@ -1555,9 +1548,6 @@
             {
                 result = gtk2_widgets[_GTK_SPIN_BUTTON_TYPE] =
                     (*fp_gtk_spin_button_new)(NULL, 0, 0);
-
-                GtkSettings* settings = fp_gtk_widget_get_settings(result);
-                fp_g_object_set(settings, "gtk-cursor-blink", FALSE, NULL);
             }
             result = gtk2_widgets[_GTK_SPIN_BUTTON_TYPE];
             break;
@@ -2507,14 +2497,20 @@
 
     return result;
 }
-/*
+
 jobject get_integer_property(JNIEnv *env, GtkSettings* settings, const gchar* key)
 {
-    gint    intval = NULL;
-
+    gint intval = NULL;
     (*fp_g_object_get)(settings, key, &intval, NULL);
     return create_Integer(env, intval);
-}*/
+}
+
+jobject get_boolean_property(JNIEnv *env, GtkSettings* settings, const gchar* key)
+{
+    gint intval = NULL;
+    (*fp_g_object_get)(settings, key, &intval, NULL);
+    return create_Boolean(env, intval);
+}
 
 jobject gtk2_get_setting(JNIEnv *env, Setting property)
 {
@@ -2526,6 +2522,10 @@
             return get_string_property(env, settings, "gtk-font-name");
         case GTK_ICON_SIZES:
             return get_string_property(env, settings, "gtk-icon-sizes");
+        case GTK_CURSOR_BLINK:
+            return get_boolean_property(env, settings, "gtk-cursor-blink");
+        case GTK_CURSOR_BLINK_TIME:
+            return get_integer_property(env, settings, "gtk-cursor-blink-time");
     }
 
     return NULL;
--- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -140,7 +140,9 @@
 typedef enum _Setting
 {
     GTK_FONT_NAME,
-    GTK_ICON_SIZES
+    GTK_ICON_SIZES,
+    GTK_CURSOR_BLINK,
+    GTK_CURSOR_BLINK_TIME
 } Setting;
 
 /* GTK types, here to eliminate need for GTK headers at compile time */
--- a/jdk/src/java.desktop/windows/classes/sun/awt/Win32FontManager.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/windows/classes/sun/awt/Win32FontManager.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -279,9 +279,9 @@
          });
     }
 
-    protected static native void registerFontWithPlatform(String fontName);
+    private static native void registerFontWithPlatform(String fontName);
 
-    protected static native void deRegisterFontWithPlatform(String fontName);
+    private static native void deRegisterFontWithPlatform(String fontName);
 
     /**
      * populate the map with the most common windows fonts.
--- a/jdk/src/java.desktop/windows/classes/sun/awt/Win32GraphicsDevice.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/windows/classes/sun/awt/Win32GraphicsDevice.java	Wed Jul 05 20:37:09 2017 +0200
@@ -226,7 +226,7 @@
      * are disabled.  Do not call this function with an index of 0.
      * @param index a PixelFormat index
      */
-    protected native boolean isPixFmtSupported(int index, int screen);
+    private native boolean isPixFmtSupported(int index, int screen);
 
     /**
      * Returns the PixelFormatID of the default graphics configuration
--- a/jdk/src/java.desktop/windows/classes/sun/awt/Win32GraphicsEnvironment.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/windows/classes/sun/awt/Win32GraphicsEnvironment.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,19 +28,11 @@
 import java.awt.AWTError;
 import java.awt.GraphicsConfiguration;
 import java.awt.GraphicsDevice;
-import java.awt.GraphicsEnvironment;
-import java.awt.Toolkit;
 import java.awt.peer.ComponentPeer;
-import java.io.File;
-import java.io.IOException;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.ListIterator;
-import java.util.NoSuchElementException;
-import java.util.StringTokenizer;
-import sun.awt.DisplayChangedListener;
-import sun.awt.SunDisplayChanger;
-import sun.awt.windows.WPrinterJob;
+
 import sun.awt.windows.WToolkit;
 import sun.java2d.SunGraphicsEnvironment;
 import sun.java2d.SurfaceManagerFactory;
@@ -57,9 +49,8 @@
  * @see GraphicsConfiguration
  */
 
-public class Win32GraphicsEnvironment
-    extends SunGraphicsEnvironment
-{
+public final class Win32GraphicsEnvironment extends SunGraphicsEnvironment {
+
     static {
         // Ensure awt is loaded already.  Also, this forces static init
         // of WToolkit and Toolkit, which we depend upon
@@ -91,7 +82,7 @@
     }
 
     protected native int getNumScreens();
-    protected native int getDefaultScreen();
+    private native int getDefaultScreen();
 
     public GraphicsDevice getDefaultScreenDevice() {
         GraphicsDevice[] screens = getScreenDevices();
--- a/jdk/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolder2.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolder2.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -163,6 +163,27 @@
         }
     }
 
+    // Known Folder data
+    static class KnownFolderDefinition {
+        String guid;
+        int category;
+        String name;
+        String description;
+        String parent;
+        String relativePath;
+        String parsingName;
+        String tooltip;
+        String localizedName;
+        String icon;
+        String security;
+        long attributes;
+        int defenitionFlags;
+        String ftidType;
+        String path;
+        String saveLocation;
+        static final List<KnownFolderDefinition> libraries = getLibraries();
+    }
+
     static class FolderDisposer implements sun.java2d.DisposerRecord {
         /*
          * This is cached as a concession to getFolderType(), which needs
@@ -578,7 +599,22 @@
                 return s;
             }
         }
-        return getDisplayNameOf(parentIShellFolder, relativePIDL, SHGDN_FORPARSING);
+        String path = getDisplayNameOf(parentIShellFolder, relativePIDL,
+                        SHGDN_FORPARSING);
+        // if this is a library its default save location is taken as a path
+        // this is a temp fix until java.io starts support Libraries
+        if( path != null && path.startsWith("::{") &&
+                path.toLowerCase().endsWith(".library-ms")) {
+            for (KnownFolderDefinition kf : KnownFolderDefinition.libraries) {
+                if( path.toLowerCase().endsWith(
+                            kf.relativePath.toLowerCase()) &&
+                            path.toUpperCase().startsWith(
+                            kf.parsingName.substring(0, 40).toUpperCase()) ) {
+                    return kf.saveLocation;
+                }
+            }
+        }
+        return path;
     }
 
     // Needs to be accessible to Win32ShellFolderManager2
@@ -848,6 +884,9 @@
                                                   long relativePIDL,
                                                   int attrs);
 
+    // Returns data of all Known Folders registered in the system
+    private static native KnownFolderDefinition[] loadKnownFolders();
+
     /**
      * @return The name used to display this shell folder
      */
@@ -1178,4 +1217,26 @@
             return result == null ? 0 : result;
         }
     }
+
+    // Extracts libraries and their default save locations from Known Folders list
+    private static List<KnownFolderDefinition> getLibraries() {
+        return invoke(new Callable<List<KnownFolderDefinition>>() {
+            @Override
+            public List<KnownFolderDefinition> call() throws Exception {
+                KnownFolderDefinition[] all = loadKnownFolders();
+                List<KnownFolderDefinition> folders = new ArrayList<>();
+                if (all != null) {
+                    for (KnownFolderDefinition kf : all) {
+                        if (kf.relativePath == null || kf.parsingName == null ||
+                                kf.saveLocation == null) {
+                            continue;
+                        }
+                        folders.add(kf);
+                    }
+                }
+                return folders;
+            }
+        });
+    }
+
 }
--- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WComponentPeer.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WComponentPeer.java	Wed Jul 05 20:37:09 2017 +0200
@@ -663,7 +663,7 @@
      * This method is intentionally not synchronized as it is called while
      * holding other locks.
      *
-     * @see sun.java2d.d3d.D3DScreenUpdateManager#validate(D3DWindowSurfaceData)
+     * @see sun.java2d.d3d.D3DScreenUpdateManager#validate
      */
     public Color getBackgroundNoSync() {
         return background;
--- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WObjectPeer.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WObjectPeer.java	Wed Jul 05 20:37:09 2017 +0200
@@ -31,9 +31,9 @@
     }
 
     // The Windows handle for the native widget.
-    long pData;
+    volatile long pData;
     // if the native peer has been destroyed
-    boolean destroyed = false;
+    volatile boolean destroyed = false;
     // The associated AWT object.
     Object target;
 
--- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPathGraphics.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPathGraphics.java	Wed Jul 05 20:37:09 2017 +0200
@@ -386,7 +386,7 @@
      * such as Hebrew and Arabic, the glyphs can be rendered from right to
      * left, in which case the coordinate supplied is the location of the
      * leftmost character on the baseline.
-     * @param s the <code>String</code> to be rendered
+     * @param str the <code>String</code> to be rendered
      * @param x,&nbsp;y the coordinates where the <code>String</code>
      * should be rendered
      * @see #setPaint
@@ -877,7 +877,7 @@
      * is transformed by the supplied AffineTransform and
      * drawn using GDI to the printer context.
      *
-     * @param   img     The image to be drawn.
+     * @param   image   The image to be drawn.
      * @param   xform   Used to transform the image before drawing.
      *                  This can be null.
      * @param   bgcolor This color is drawn where the image has transparent
--- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java	Wed Jul 05 20:37:09 2017 +0200
@@ -591,7 +591,7 @@
      * Throws <code>PrinterException</code> if the specified service
      * cannot support the <code>Pageable</code> and
      * </code>Printable</code> interfaces necessary to support 2D printing.
-     * @param a print service which supports 2D printing.
+     * @param service print service which supports 2D printing.
      *
      * @throws PrinterException if the specified service does not support
      * 2D printing.
--- a/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DScreenUpdateManager.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DScreenUpdateManager.java	Wed Jul 05 20:37:09 2017 +0200
@@ -59,7 +59,7 @@
  * GDIWindowSurfaceData. A background thread handles the swap chain flips.
  *
  * There are some restrictions to which windows we would use this for.
- * @see #createScreenSurface()
+ * @see #createScreenSurface
  */
 public class D3DScreenUpdateManager extends ScreenUpdateManager
     implements Runnable
@@ -290,7 +290,7 @@
     /**
      * Adds a surface to the list of tracked surfaces.
      *
-     * @param d3dw the surface to be added
+     * @param sd the surface to be added
      */
     private void trackScreenSurface(SurfaceData sd) {
         if (!done && sd instanceof D3DWindowSurfaceData) {
--- a/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceData.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceData.java	Wed Jul 05 20:37:09 2017 +0200
@@ -118,7 +118,7 @@
 
     /**
      * To be used with getNativeResource() only.
-     * @see #getNativeResource()
+     * @see #getNativeResource
      */
     public static final int D3D_DEVICE_RESOURCE= 100;
     /*
--- a/jdk/src/java.desktop/windows/classes/sun/java2d/opengl/WGLSurfaceData.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/windows/classes/sun/java2d/opengl/WGLSurfaceData.java	Wed Jul 05 20:37:09 2017 +0200
@@ -244,7 +244,7 @@
      * Updates the layered window with the contents of the surface.
      *
      * @param psdops pointer to the native ogl sd structure
-     * @param pData pointer to the AwtWindow peer data
+     * @param peer pointer to the AwtWindow peer data
      * @param w width of the window
      * @param h height of the window
      * @see sun.awt.windows.TranslucentWindowPainter
--- a/jdk/src/java.desktop/windows/native/libawt/windows/ShellFolder2.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/ShellFolder2.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -64,6 +64,19 @@
 
 //#include <sun_awt_shell_Win32ShellFolder2.h>
 
+#ifndef DASSERT
+#define DASSERT(x)
+#endif
+#define DEFINE_FIELD_ID(var, cls, field, type)                            \
+    jfieldID var = env->GetFieldID(cls, field, type);                     \
+    DASSERT(var != NULL);                                                 \
+    CHECK_NULL_RETURN(var, NULL);
+
+#define EXCEPTION_CHECK                                                   \
+   if(env->ExceptionCheck()) {                                            \
+        throw std::bad_alloc();                                           \
+   }
+
 // Shell Functions
 typedef BOOL (WINAPI *DestroyIconType)(HICON);
 typedef HINSTANCE (WINAPI *FindExecutableType)(LPCTSTR,LPCTSTR,LPTSTR);
@@ -1263,5 +1276,216 @@
     return 0;
 }
 
+/*
+ * Class:     sun_awt_shell_Win32ShellFolder2
+ * Method:    loadKnownFolders
+ * Signature: (V)[BLsun/awt/shell/Win32ShellFolder2$KnownfolderDefenition;
+ */
+JNIEXPORT jobjectArray JNICALL Java_sun_awt_shell_Win32ShellFolder2_loadKnownFolders
+    (JNIEnv* env, jclass cls )
+{
+    CoInitialize(NULL);
+    IKnownFolderManager* pkfm = NULL;
+    HRESULT hr = CoCreateInstance(CLSID_KnownFolderManager, NULL,
+                                CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pkfm));
+    if (!SUCCEEDED(hr)) return NULL;
+
+    TRY;
+
+    jclass cl = env->FindClass("sun/awt/shell/Win32ShellFolder2$KnownFolderDefinition");
+    CHECK_NULL_RETURN(cl, NULL);
+    DEFINE_FIELD_ID(field_guid, cl, "guid", "Ljava/lang/String;")
+    DEFINE_FIELD_ID(field_name, cl, "name", "Ljava/lang/String;");
+    DEFINE_FIELD_ID(field_description, cl, "description", "Ljava/lang/String;");
+    DEFINE_FIELD_ID(field_parent, cl, "parent", "Ljava/lang/String;");
+    DEFINE_FIELD_ID(field_relativePath, cl, "relativePath", "Ljava/lang/String;");
+    DEFINE_FIELD_ID(field_parsingName, cl, "parsingName", "Ljava/lang/String;");
+    DEFINE_FIELD_ID(field_tooltip, cl, "tooltip", "Ljava/lang/String;");
+    DEFINE_FIELD_ID(field_localizedName, cl, "localizedName", "Ljava/lang/String;");
+    DEFINE_FIELD_ID(field_icon, cl, "icon", "Ljava/lang/String;");
+    DEFINE_FIELD_ID(field_security, cl, "security", "Ljava/lang/String;");
+    DEFINE_FIELD_ID(field_path, cl, "path", "Ljava/lang/String;");
+    DEFINE_FIELD_ID(field_saveLocation, cl, "saveLocation", "Ljava/lang/String;");
+    DEFINE_FIELD_ID(field_category, cl, "category", "I");
+    DEFINE_FIELD_ID(field_attributes, cl, "attributes", "J");
+    DEFINE_FIELD_ID(field_defenitionFlags, cl, "defenitionFlags", "I");
+    DEFINE_FIELD_ID(field_ftidType, cl, "ftidType", "Ljava/lang/String;");
+
+    jobjectArray result;
+    KNOWNFOLDERID* pFoldersIds = NULL;
+    UINT count = 0;
+    if (SUCCEEDED(pkfm->GetFolderIds(&pFoldersIds, &count))) {
+        jmethodID initMethod;
+        try {
+            result = env->NewObjectArray(count, cl, NULL);
+            initMethod = env->GetMethodID(cl, "<init>", "()V");
+            EXCEPTION_CHECK
+        } catch (std::bad_alloc&) {
+            CoTaskMemFree(pFoldersIds);
+            pkfm->Release();
+            throw;
+        }
+        for(UINT i = 0; i < count; ++i)
+        {
+            jobject fld;
+            const KNOWNFOLDERID& folderId = pFoldersIds[i];
+            LPOLESTR guid = NULL;
+            try {
+                fld = env->NewObject(cl, initMethod);
+                if (fld) {
+                    env->SetObjectArrayElement(result, i, fld);
+                }
+                EXCEPTION_CHECK
+
+                if (SUCCEEDED(StringFromCLSID(folderId, &guid))) {
+                    jstring jstr = JNU_NewStringPlatform(env, guid);
+                    if (jstr) {
+                        env->SetObjectField(fld, field_guid, jstr);
+                    }
+                    CoTaskMemFree(guid);
+                    EXCEPTION_CHECK
+                }
+            } catch (std::bad_alloc&) {
+                CoTaskMemFree(pFoldersIds);
+                pkfm->Release();
+                throw;
+            }
+
+            IKnownFolder* pFolder = NULL;
+            if (SUCCEEDED(pkfm->GetFolder(folderId, &pFolder))) {
+                KNOWNFOLDER_DEFINITION kfDef;
+                if (SUCCEEDED(pFolder->GetFolderDefinition(&kfDef)))
+                {
+                    try {
+                        jstring jstr = JNU_NewStringPlatform(env, kfDef.pszName);
+                        if(jstr) {
+                            env->SetObjectField(fld, field_name, jstr);
+                        }
+                        EXCEPTION_CHECK
+                        if (kfDef.pszDescription) {
+                            jstr = JNU_NewStringPlatform(env, kfDef.pszDescription);
+                            if (jstr) {
+                                env->SetObjectField(fld, field_description, jstr);
+                            }
+                            EXCEPTION_CHECK
+                        }
+                        EXCEPTION_CHECK
+                        if (SUCCEEDED(StringFromCLSID(kfDef.fidParent, &guid))) {
+                            jstr = JNU_NewStringPlatform(env, guid);
+                            if (jstr) {
+                                env->SetObjectField(fld, field_parent, jstr);
+                            }
+                            CoTaskMemFree(guid);
+                            EXCEPTION_CHECK
+                        }
+                        if (kfDef.pszRelativePath) {
+                            jstr = JNU_NewStringPlatform(env, kfDef.pszRelativePath);
+                            if (jstr) {
+                                env->SetObjectField(fld, field_relativePath, jstr);
+                            }
+                            EXCEPTION_CHECK
+                        }
+                        if (kfDef.pszParsingName) {
+                            jstr = JNU_NewStringPlatform(env, kfDef.pszParsingName);
+                            if (jstr) {
+                                env->SetObjectField(fld, field_parsingName, jstr);
+                            }
+                            EXCEPTION_CHECK
+                        }
+                        if (kfDef.pszTooltip) {
+                            jstr = JNU_NewStringPlatform(env, kfDef.pszTooltip);
+                            if (jstr) {
+                                env->SetObjectField(fld, field_tooltip, jstr);
+                            }
+                            EXCEPTION_CHECK
+                        }
+                        if (kfDef.pszLocalizedName) {
+                            jstr = JNU_NewStringPlatform(env, kfDef.pszLocalizedName);
+                            if (jstr) {
+                                env->SetObjectField(fld, field_localizedName, jstr);
+                            }
+                            EXCEPTION_CHECK
+                        }
+                        if (kfDef.pszIcon) {
+                            jstr = JNU_NewStringPlatform(env, kfDef.pszIcon);
+                            if (jstr) {
+                                env->SetObjectField(fld, field_icon, jstr);
+                            }
+                            EXCEPTION_CHECK
+                        }
+                        if (kfDef.pszSecurity) {
+                            jstr = JNU_NewStringPlatform(env, kfDef.pszSecurity);
+                            if (jstr) {
+                                env->SetObjectField(fld, field_security, jstr);
+                            }
+                            EXCEPTION_CHECK
+                        }
+                        if (SUCCEEDED(StringFromCLSID(kfDef.ftidType, &guid))) {
+                            jstr = JNU_NewStringPlatform(env, guid);
+                            if (jstr) {
+                                env->SetObjectField(fld, field_ftidType, jstr);
+                            }
+                            CoTaskMemFree(guid);
+                            EXCEPTION_CHECK
+                        }
+                        env->SetIntField(fld, field_category, kfDef.category);
+                        env->SetIntField(fld, field_defenitionFlags, kfDef.kfdFlags);
+                        env->SetLongField(fld, field_attributes, kfDef.dwAttributes);
+
+                        LPWSTR folderPath = NULL;
+                        if (SUCCEEDED(pFolder->GetPath(KF_FLAG_NO_ALIAS, &folderPath))
+                                    && folderPath) {
+                            jstr = JNU_NewStringPlatform(env, folderPath);
+                            if (jstr) {
+                                env->SetObjectField(fld, field_path, jstr);
+                            }
+                            CoTaskMemFree(folderPath);
+                            EXCEPTION_CHECK
+                        }
+
+                        IShellLibrary *plib = NULL;
+                        hr = CoCreateInstance(CLSID_ShellLibrary, NULL,
+                                         CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&plib));
+                        if (SUCCEEDED(hr)) {
+                            hr = plib->LoadLibraryFromKnownFolder(folderId, STGM_READWRITE);
+                            if (SUCCEEDED(hr)) {
+                                IShellItem *item = NULL;
+                                hr = plib->GetDefaultSaveFolder(DSFT_DETECT,
+                                        IID_PPV_ARGS(&item));
+                                if (SUCCEEDED(hr) && item) {
+                                    LPWSTR loc = NULL;
+                                    hr = item->GetDisplayName(SIGDN_FILESYSPATH, &loc);
+                                    if (SUCCEEDED(hr) && loc)
+                                    {
+                                        jstr = JNU_NewStringPlatform(env, loc);
+                                        if (jstr) {
+                                            env->SetObjectField(fld, field_saveLocation, jstr);
+                                        }
+                                        CoTaskMemFree(loc);
+                                    }
+                                    item->Release();
+                                }
+                            }
+                            plib->Release();
+                            EXCEPTION_CHECK
+                        }
+                        FreeKnownFolderDefinitionFields(&kfDef);
+                    } catch (std::bad_alloc&) {
+                        FreeKnownFolderDefinitionFields(&kfDef);
+                        pFolder->Release();
+                        CoTaskMemFree(pFoldersIds);
+                        pkfm->Release();
+                        throw;
+                    }
+                }
+            }
+            pFolder->Release();
+        }
+        CoTaskMemFree(pFoldersIds);
+    }
+    pkfm->Release();
+    return result;
+    CATCH_BAD_ALLOC_RET(NULL);
+}
 
 } // extern "C"
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -1864,6 +1864,7 @@
 
     AwtFrame::activateEmbeddingTopLevelMID = env->GetMethodID(cls, "activateEmbeddingTopLevel", "()V");
     DASSERT(AwtFrame::activateEmbeddingTopLevelMID != NULL);
+    CHECK_NULL(AwtFrame::activateEmbeddingTopLevelMID);
 
     AwtFrame::isEmbeddedInIEID = env->GetFieldID(cls, "isEmbeddedInIE", "Z");
     DASSERT(AwtFrame::isEmbeddedInIEID != NULL);
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_Menu.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Menu.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -239,6 +239,7 @@
     }
     jobject menuItem = env->CallObjectMethod(target, AwtMenu::getItemMID,
                                              index);
+    if (!menuItem) return NULL; // menu item was removed concurrently
     DASSERT(!safe_ExceptionOccurred(env));
 
     jobject wMenuItemPeer = GetPeerForTarget(env, menuItem);
@@ -264,9 +265,9 @@
     }
     /* target is a java.awt.Menu */
     jobject target = GetTarget(env);
-
+    if(!target || env->ExceptionCheck()) return;
     int nCount = CountItem(target);
-    for (int i = 0; i < nCount; i++) {
+    for (int i = 0; i < nCount && !env->ExceptionCheck(); i++) {
         AwtMenuItem* awtMenuItem = GetItem(target, i);
         if (awtMenuItem != NULL) {
             SendDrawItem(awtMenuItem, drawInfo);
@@ -294,8 +295,9 @@
     }
    /* target is a java.awt.Menu */
     jobject target = GetTarget(env);
+    if(!target || env->ExceptionCheck()) return;
     int nCount = CountItem(target);
-    for (int i = 0; i < nCount; i++) {
+    for (int i = 0; i < nCount && !env->ExceptionCheck(); i++) {
         AwtMenuItem* awtMenuItem = GetItem(target, i);
         if (awtMenuItem != NULL) {
             SendMeasureItem(awtMenuItem, hDC, measureInfo);
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_MenuBar.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_MenuBar.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -156,13 +156,16 @@
     }
 
     jobject menu = env->CallObjectMethod(target, AwtMenuBar::getMenuMID,index);
+    if (!menu) return NULL; // menu item was removed concurrently
     DASSERT(!safe_ExceptionOccurred(env));
 
     jobject menuItemPeer = GetPeerForTarget(env, menu);
     PDATA pData;
-    JNI_CHECK_PEER_RETURN_NULL(menuItemPeer);
+    JNI_CHECK_PEER_GOTO(menuItemPeer, done);
+
     AwtMenuItem* awtMenuItem = (AwtMenuItem*)pData;
 
+done:
     env->DeleteLocalRef(menu);
     env->DeleteLocalRef(menuItemPeer);
 
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_MenuItem.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_MenuItem.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -112,6 +112,7 @@
 
     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
     if (m_peerObject != NULL) {
+        JNI_SET_DESTROYED(m_peerObject);
         JNI_SET_PDATA(m_peerObject, NULL);
         env->DeleteGlobalRef(m_peerObject);
         m_peerObject = NULL;
--- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_new.cpp	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_new.cpp	Wed Jul 05 20:37:09 2017 +0200
@@ -172,6 +172,9 @@
             env->ExceptionClear();
             // rethrow exception
             env->Throw(xcp);
+            // temp solution to reveal all concurrency issues in jtreg and JCK
+            // we will switch it back to silent mode before the release
+            env->ExceptionDescribe();
             return xcp;
         }
     }
--- a/jdk/src/java.management/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.management/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,14 +33,12 @@
 import com.sun.jmx.remote.util.EnvHelp;
 
 import java.io.InvalidObjectException;
-import java.lang.annotation.Annotation;
 import java.lang.annotation.ElementType;
 import java.lang.ref.WeakReference;
 import java.lang.reflect.Array;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.GenericArrayType;
-import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.ParameterizedType;
@@ -1138,55 +1136,13 @@
         to getters.  */
     private static final class CompositeBuilderViaConstructor
             extends CompositeBuilder {
-        static class AnnotationHelper {
-            private static Class<? extends Annotation> constructorPropertiesClass;
-            private static Method valueMethod;
-            static {
-                findConstructorPropertiesClass();
-            }
-
-            @SuppressWarnings("unchecked")
-            private static void findConstructorPropertiesClass() {
-                try {
-                    constructorPropertiesClass = (Class<? extends Annotation>)
-                        Class.forName("java.beans.ConstructorProperties", false,
-                                      DefaultMXBeanMappingFactory.class.getClassLoader());
-                    valueMethod = constructorPropertiesClass.getMethod("value");
-                } catch (ClassNotFoundException cnf) {
-                    // java.beans not present
-                } catch (NoSuchMethodException e) {
-                    // should not reach here
-                    throw new InternalError(e);
-                }
-            }
-
-            static boolean isAvailable() {
-                return constructorPropertiesClass != null;
-            }
-
-            static String[] getPropertyNames(Constructor<?> constr) {
-                if (!isAvailable())
-                    return null;
-
-                Annotation a = constr.getAnnotation(constructorPropertiesClass);
-                if (a == null) return null;
-
-                try {
-                    return (String[]) valueMethod.invoke(a);
-                } catch (InvocationTargetException e) {
-                    throw new InternalError(e);
-                } catch (IllegalAccessException e) {
-                    throw new InternalError(e);
-                }
-            }
-        }
 
         CompositeBuilderViaConstructor(Class<?> targetClass, String[] itemNames) {
             super(targetClass, itemNames);
         }
 
         String applicable(Method[] getters) throws InvalidObjectException {
-            if (!AnnotationHelper.isAvailable())
+            if (!JavaBeansAccessor.isAvailable())
                 return "@ConstructorProperties annotation not available";
 
             Class<?> targetClass = getTargetClass();
@@ -1196,7 +1152,7 @@
             List<Constructor<?>> annotatedConstrList = newList();
             for (Constructor<?> constr : constrs) {
                 if (Modifier.isPublic(constr.getModifiers())
-                        && AnnotationHelper.getPropertyNames(constr) != null)
+                        && JavaBeansAccessor.getConstructorPropertiesValue(constr) != null)
                     annotatedConstrList.add(constr);
             }
 
@@ -1225,7 +1181,7 @@
             // so we can test unambiguity.
             Set<BitSet> getterIndexSets = newSet();
             for (Constructor<?> constr : annotatedConstrList) {
-                String[] propertyNames = AnnotationHelper.getPropertyNames(constr);
+                String[] propertyNames = JavaBeansAccessor.getConstructorPropertiesValue(constr);
 
                 Type[] paramTypes = constr.getGenericParameterTypes();
                 if (paramTypes.length != propertyNames.length) {
--- a/jdk/src/java.management/share/classes/com/sun/jmx/mbeanserver/Introspector.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.management/share/classes/com/sun/jmx/mbeanserver/Introspector.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -56,7 +56,7 @@
 import javax.management.AttributeNotFoundException;
 import javax.management.openmbean.CompositeData;
 
-import sun.misc.JavaBeansIntrospectorAccess;
+import sun.misc.JavaBeansAccess;
 import sun.misc.SharedSecrets;
 import sun.reflect.misc.MethodUtil;
 import sun.reflect.misc.ReflectUtil;
@@ -552,10 +552,8 @@
                 // Java Beans introspection
                 //
                 Class<?> clazz = complex.getClass();
-                Method readMethod;
-                if (BeansIntrospector.isAvailable()) {
-                    readMethod = BeansIntrospector.getReadMethod(clazz, element);
-                } else {
+                Method readMethod = JavaBeansAccessor.getReadMethod(clazz, element);
+                if (readMethod == null) {
                     // Java Beans not available so use simple introspection
                     // to locate method
                     readMethod = SimpleIntrospector.getReadMethod(clazz, element);
@@ -580,30 +578,6 @@
     }
 
     /**
-     * Provides access to java.beans.Introspector if available.
-     */
-    private static class BeansIntrospector {
-        private static final JavaBeansIntrospectorAccess JBIA;
-        static {
-            // ensure that java.beans.Introspector is initialized (if present)
-            try {
-                Class.forName("java.beans.Introspector", true,
-                              BeansIntrospector.class.getClassLoader());
-            } catch (ClassNotFoundException ignore) { }
-
-            JBIA = SharedSecrets.getJavaBeansIntrospectorAccess();
-        }
-
-        static boolean isAvailable() {
-            return JBIA != null;
-        }
-
-        static Method getReadMethod(Class<?> clazz, String property) throws Exception {
-            return JBIA.getReadMethod(clazz, property);
-        }
-    }
-
-    /**
      * A simple introspector that uses reflection to analyze a class and
      * identify its "getter" methods. This class is intended for use only when
      * Java Beans is not present (which implies that there isn't explicit
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.management/share/classes/com/sun/jmx/mbeanserver/JavaBeansAccessor.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 com.sun.jmx.mbeanserver;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import sun.misc.JavaBeansAccess;
+import sun.misc.SharedSecrets;
+
+/**
+ * A centralized place for gaining access to java.beans related functionality -
+ * if available.
+ */
+class JavaBeansAccessor {
+    static {
+        // ensure that java.beans.Introspector is initialized (if present)
+        // it will fill in the SharedSecrets
+        try {
+            Class.forName("java.beans.Introspector", true,
+                          JavaBeansAccessor.class.getClassLoader());
+        } catch (ClassNotFoundException ignore) { }
+    }
+
+    private static JavaBeansAccess getJavaBeansAccess() {
+        return SharedSecrets.getJavaBeansAccess();
+    }
+
+    static boolean isAvailable() {
+        return getJavaBeansAccess() != null;
+    }
+
+    /**
+     * Returns the getter method for a property of the given name
+     * @param clazz The JavaBeans class
+     * @param property The property name
+     * @return The resolved property getter name or null
+     * @throws Exception
+     */
+    static Method getReadMethod(Class<?> clazz, String property) throws Exception {
+        JavaBeansAccess jba = getJavaBeansAccess();
+        return jba != null ? jba.getReadMethod(clazz, property) : null;
+    }
+
+    /**
+     * Return the <b>value</b> attribute of the associated
+     * <code>@ConstructorProperties</code> annotation if that is present.
+     * @param ctr The constructor to extract the annotation value from
+     * @return The {@code value} attribute of the <code>@ConstructorProperties</code>
+     *         annotation or {@code null} if the constructor is not annotated by
+     *         this annotation or the annotation is not accessible.
+     */
+    static String[] getConstructorPropertiesValue(Constructor<?> ctr) {
+        JavaBeansAccess jba = getJavaBeansAccess();
+        return jba != null ? jba.getConstructorPropertiesValue(ctr) : null;
+    }
+}
--- a/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/Connection.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/Connection.java	Wed Jul 05 20:37:09 2017 +0200
@@ -393,9 +393,14 @@
     BerDecoder readReply(LdapRequest ldr)
             throws IOException, NamingException {
         BerDecoder rber;
-        boolean waited = false;
 
-        while (((rber = ldr.getReplyBer()) == null) && !waited) {
+        // Track down elapsed time to workaround spurious wakeups
+        long elapsedMilli = 0;
+        long elapsedNano = 0;
+
+        while (((rber = ldr.getReplyBer()) == null) &&
+                (readTimeout <= 0 || elapsedMilli < readTimeout))
+        {
             try {
                 // If socket closed, don't even try
                 synchronized (this) {
@@ -409,11 +414,15 @@
                     rber = ldr.getReplyBer();
                     if (rber == null) {
                         if (readTimeout > 0) {  // Socket read timeout is specified
+                            long beginNano = System.nanoTime();
 
-                            // will be woken up before readTimeout only if reply is
+                            // will be woken up before readTimeout if reply is
                             // available
-                            ldr.wait(readTimeout);
-                            waited = true;
+                            ldr.wait(readTimeout - elapsedMilli);
+                            elapsedNano += (System.nanoTime() - beginNano);
+                            elapsedMilli += elapsedNano / 1000_000;
+                            elapsedNano %= 1000_000;
+
                         } else {
                             // no timeout is set so we wait infinitely until
                             // a response is received
@@ -430,7 +439,7 @@
             }
         }
 
-        if ((rber == null) && waited) {
+        if ((rber == null) && (elapsedMilli >= readTimeout)) {
             abandonRequest(ldr, null);
             throw new NamingException("LDAP response read timed out, timeout used:"
                             + readTimeout + "ms." );
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.security.jgss/share/classes/META-INF/services/sun.security.ssl.ClientKeyExchangeService	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,2 @@
+sun.security.krb5.internal.ssl.Krb5KeyExchangeService
+
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/Config.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/Config.java	Wed Jul 05 20:37:09 2017 +0200
@@ -260,7 +260,11 @@
     }
 
     /**
-     * Gets all values for the specified keys.
+     * Gets all values (at least one) for the specified keys separated by
+     * a whitespace, or null if there is no such keys.
+     * The values can either be provided on a single line, or on multiple lines
+     * using the same key. When provided on a single line, the value can be
+     * comma or space separated.
      * @throws IllegalArgumentException if any of the keys is illegal
      *         (See {@link #get})
      */
@@ -270,6 +274,7 @@
         StringBuilder sb = new StringBuilder();
         boolean first = true;
         for (String s: v) {
+            s = s.replaceAll("[\\s,]+", " ");
             if (first) {
                 sb.append(s);
                 first = false;
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbCred.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbCred.java	Wed Jul 05 20:37:09 2017 +0200
@@ -34,6 +34,9 @@
 import sun.security.krb5.internal.*;
 import sun.security.krb5.internal.crypto.KeyUsage;
 import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
 import sun.security.util.DerValue;
 
 /**
@@ -76,10 +79,24 @@
         options.set(KDCOptions.FORWARDABLE, true);
 
         HostAddresses sAddrs = null;
-        // XXX Also NT_GSS_KRB5_PRINCIPAL can be a host based principal
+
         // GSSName.NT_HOSTBASED_SERVICE should display with KRB_NT_SRV_HST
-        if (server.getNameType() == PrincipalName.KRB_NT_SRV_HST)
-            sAddrs=  new HostAddresses(server);
+        if (server.getNameType() == PrincipalName.KRB_NT_SRV_HST) {
+            sAddrs = new HostAddresses(server);
+        } else if (server.getNameType() == PrincipalName.KRB_NT_UNKNOWN) {
+            // Sometimes this is also a server
+            if (server.getNameStrings().length >= 2) {
+                String host = server.getNameStrings()[1];
+                try {
+                    InetAddress[] addr = InetAddress.getAllByName(host);
+                    if (addr != null && addr.length > 0) {
+                        sAddrs = new HostAddresses(addr);
+                    }
+                } catch (UnknownHostException ioe) {
+                    // maybe we guessed wrong, let sAddrs be null
+                }
+            }
+        }
 
         KrbTgsReq tgsReq = new KrbTgsReq(options, tgt, tgService,
                                          null, null, null, null, sAddrs, null, null, null);
--- a/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/HostAddresses.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/HostAddresses.java	Wed Jul 05 20:37:09 2017 +0200
@@ -31,16 +31,14 @@
 
 package sun.security.krb5.internal;
 
+import sun.security.krb5.Config;
 import sun.security.krb5.PrincipalName;
 import sun.security.krb5.KrbException;
 import sun.security.krb5.Asn1Exception;
 import sun.security.util.*;
-import java.util.Vector;
-import java.util.ArrayList;
-import java.net.InetAddress;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.UnknownHostException;
+
+import java.net.*;
+import java.util.*;
 import java.io.IOException;
 import sun.security.krb5.internal.ccache.CCacheOutputStream;
 
@@ -293,34 +291,35 @@
      */
     public static HostAddresses getLocalAddresses() throws IOException
     {
-        String hostname = null;
-        InetAddress[] inetAddresses = null;
+        Set<InetAddress> all = new LinkedHashSet<>();
         try {
-            InetAddress localHost = InetAddress.getLocalHost();
-            hostname = localHost.getHostName();
-            inetAddresses = InetAddress.getAllByName(hostname);
-            HostAddress[] hAddresses = new HostAddress[inetAddresses.length];
-            for (int i = 0; i < inetAddresses.length; i++)
-                {
-                    hAddresses[i] = new HostAddress(inetAddresses[i]);
-                }
             if (DEBUG) {
-                System.out.println(">>> KrbKdcReq local addresses for "
-                                   + hostname + " are: ");
-
-                for (int i = 0; i < inetAddresses.length; i++) {
-                    System.out.println("\n\t" + inetAddresses[i]);
-                    if (inetAddresses[i] instanceof Inet4Address)
-                        System.out.println("IPv4 address");
-                    if (inetAddresses[i] instanceof Inet6Address)
-                        System.out.println("IPv6 address");
+                System.out.println(">>> KrbKdcReq local addresses are:");
+            }
+            String extra = Config.getInstance().getAll(
+                    "libdefaults", "extra_addresses");
+            if (extra != null) {
+                for (String s: extra.split("\\s+")) {
+                    all.add(InetAddress.getByName(s));
+                    if (DEBUG) {
+                        System.out.println("   extra_addresses: "
+                                + InetAddress.getByName(s));
+                    }
                 }
             }
-            return (new HostAddresses(hAddresses));
+            for (NetworkInterface ni:
+                    Collections.list(NetworkInterface.getNetworkInterfaces())) {
+                if (DEBUG) {
+                    System.out.println("   NetworkInterface " + ni + ":");
+                    System.out.println("      "
+                            + Collections.list(ni.getInetAddresses()));
+                }
+                all.addAll(Collections.list(ni.getInetAddresses()));
+            }
+            return new HostAddresses(all.toArray(new InetAddress[all.size()]));
         } catch (Exception exc) {
             throw new IOException(exc.toString());
         }
-
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/ssl/KerberosPreMasterSecret.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2003, 2010, 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.security.krb5.internal.ssl;
+
+import java.io.*;
+import java.security.*;
+import java.util.Arrays;
+
+import javax.net.ssl.*;
+
+import sun.security.krb5.EncryptionKey;
+import sun.security.krb5.EncryptedData;
+import sun.security.krb5.KrbException;
+import sun.security.krb5.internal.crypto.KeyUsage;
+
+import sun.security.ssl.Debug;
+import sun.security.ssl.HandshakeInStream;
+import sun.security.ssl.HandshakeMessage;
+import sun.security.ssl.ProtocolVersion;
+
+/**
+ * This is the Kerberos premaster secret in the Kerberos client key
+ * exchange message (CLIENT --> SERVER); it holds the
+ * Kerberos-encrypted pre-master secret. The secret is encrypted using the
+ * Kerberos session key.  The padding and size of the resulting message
+ * depends on the session key type, but the pre-master secret is
+ * always exactly 48 bytes.
+ *
+ */
+final class KerberosPreMasterSecret {
+
+    private ProtocolVersion protocolVersion; // preMaster [0,1]
+    private byte preMaster[];           // 48 bytes
+    private byte encrypted[];
+
+    /**
+     * Constructor used by client to generate premaster secret.
+     *
+     * Client randomly creates a pre-master secret and encrypts it
+     * using the Kerberos session key; only the server can decrypt
+     * it, using the session key available in the service ticket.
+     *
+     * @param protocolVersion used to set preMaster[0,1]
+     * @param generator random number generator for generating premaster secret
+     * @param sessionKey Kerberos session key for encrypting premaster secret
+     */
+    KerberosPreMasterSecret(ProtocolVersion protocolVersion,
+            SecureRandom generator, EncryptionKey sessionKey) throws IOException {
+
+        if (sessionKey.getEType() ==
+                EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD) {
+            throw new IOException(
+                    "session keys with des3-cbc-hmac-sha1-kd encryption type " +
+                            "are not supported for TLS Kerberos cipher suites");
+        }
+
+        this.protocolVersion = protocolVersion;
+        preMaster = generatePreMaster(generator, protocolVersion);
+
+        // Encrypt premaster secret
+        try {
+            EncryptedData eData = new EncryptedData(sessionKey, preMaster,
+                    KeyUsage.KU_UNKNOWN);
+            encrypted = eData.getBytes();  // not ASN.1 encoded.
+
+        } catch (KrbException e) {
+            throw (SSLKeyException)new SSLKeyException
+                    ("Kerberos premaster secret error").initCause(e);
+        }
+    }
+
+    /*
+     * Constructor used by server to decrypt encrypted premaster secret.
+     * The protocol version in preMaster[0,1] must match either currentVersion
+     * or clientVersion, otherwise, the premaster secret is set to
+     * a random one to foil possible attack.
+     *
+     * @param currentVersion version of protocol being used
+     * @param clientVersion version requested by client
+     * @param generator random number generator used to generate
+     *        bogus premaster secret if premaster secret verification fails
+     * @param input input stream from which to read the encrypted
+     *        premaster secret
+     * @param sessionKey Kerberos session key to be used for decryption
+     */
+    KerberosPreMasterSecret(ProtocolVersion currentVersion,
+            ProtocolVersion clientVersion,
+            SecureRandom generator, byte[] encrypted,
+            EncryptionKey sessionKey) throws IOException {
+
+        if (HandshakeMessage.debug != null && Debug.isOn("handshake")) {
+            if (encrypted != null) {
+                Debug.println(System.out,
+                        "encrypted premaster secret", encrypted);
+            }
+        }
+
+        if (sessionKey.getEType() ==
+                EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD) {
+            throw new IOException(
+                    "session keys with des3-cbc-hmac-sha1-kd encryption type " +
+                            "are not supported for TLS Kerberos cipher suites");
+        }
+
+        // Decrypt premaster secret
+        try {
+            EncryptedData data = new EncryptedData(sessionKey.getEType(),
+                    null /* optional kvno */, encrypted);
+
+            byte[] temp = data.decrypt(sessionKey, KeyUsage.KU_UNKNOWN);
+            if (HandshakeMessage.debug != null && Debug.isOn("handshake")) {
+                if (encrypted != null) {
+                    Debug.println(System.out,
+                            "decrypted premaster secret", temp);
+                }
+            }
+
+            // Remove padding bytes after decryption. Only DES and DES3 have
+            // paddings and we don't support DES3 in TLS (see above)
+
+            if (temp.length == 52 &&
+                    data.getEType() == EncryptedData.ETYPE_DES_CBC_CRC) {
+                // For des-cbc-crc, 4 paddings. Value can be 0x04 or 0x00.
+                if (paddingByteIs(temp, 52, (byte)4) ||
+                        paddingByteIs(temp, 52, (byte)0)) {
+                    temp = Arrays.copyOf(temp, 48);
+                }
+            } else if (temp.length == 56 &&
+                    data.getEType() == EncryptedData.ETYPE_DES_CBC_MD5) {
+                // For des-cbc-md5, 8 paddings with 0x08, or no padding
+                if (paddingByteIs(temp, 56, (byte)8)) {
+                    temp = Arrays.copyOf(temp, 48);
+                }
+            }
+
+            preMaster = temp;
+
+            protocolVersion = ProtocolVersion.valueOf(preMaster[0],
+                    preMaster[1]);
+            if (HandshakeMessage.debug != null && Debug.isOn("handshake")) {
+                System.out.println("Kerberos PreMasterSecret version: "
+                        + protocolVersion);
+            }
+        } catch (Exception e) {
+            // catch exception & process below
+            preMaster = null;
+            protocolVersion = currentVersion;
+        }
+
+        // check if the premaster secret version is ok
+        // the specification says that it must be the maximum version supported
+        // by the client from its ClientHello message. However, many
+        // old implementations send the negotiated version, so accept both
+        // for SSL v3.0 and TLS v1.0.
+        // NOTE that we may be comparing two unsupported version numbers in
+        // the second case, which is why we cannot use object references
+        // equality in this special case
+        boolean versionMismatch = (protocolVersion.v != clientVersion.v);
+
+        /*
+         * we never checked the client_version in server side
+         * for TLS v1.0 and SSL v3.0. For compatibility, we
+         * maintain this behavior.
+         */
+        if (versionMismatch && (clientVersion.v <= 0x0301)) {
+            versionMismatch = (protocolVersion.v != currentVersion.v);
+        }
+
+        /*
+         * Bogus decrypted ClientKeyExchange? If so, conjure a
+         * a random preMaster secret that will fail later during
+         * Finished message processing. This is a countermeasure against
+         * the "interactive RSA PKCS#1 encryption envelop attack" reported
+         * in June 1998. Preserving the executation path will
+         * mitigate timing attacks and force consistent error handling
+         * that will prevent an attacking client from differentiating
+         * different kinds of decrypted ClientKeyExchange bogosities.
+         */
+        if ((preMaster == null) || (preMaster.length != 48)
+                || versionMismatch) {
+            if (HandshakeMessage.debug != null && Debug.isOn("handshake")) {
+                System.out.println("Kerberos PreMasterSecret error, "
+                        + "generating random secret");
+                if (preMaster != null) {
+                    Debug.println(System.out, "Invalid secret", preMaster);
+                }
+            }
+
+            /*
+             * Randomize the preMaster secret with the
+             * ClientHello.client_version, as will produce invalid master
+             * secret to prevent the attacks.
+             */
+            preMaster = generatePreMaster(generator, clientVersion);
+            protocolVersion = clientVersion;
+        }
+    }
+
+    /**
+     * Checks if all paddings of data are b
+     * @param data the block with padding
+     * @param len length of data, >= 48
+     * @param b expected padding byte
+     */
+    private static boolean paddingByteIs(byte[] data, int len, byte b) {
+        for (int i=48; i<len; i++) {
+            if (data[i] != b) return false;
+        }
+        return true;
+    }
+
+    /*
+     * Used by server to generate premaster secret in case of
+     * problem decoding ticket.
+     *
+     * @param protocolVersion used for preMaster[0,1]
+     * @param generator random number generator to use for generating secret.
+     */
+    KerberosPreMasterSecret(ProtocolVersion protocolVersion,
+            SecureRandom generator) {
+
+        this.protocolVersion = protocolVersion;
+        preMaster = generatePreMaster(generator, protocolVersion);
+    }
+
+    private static byte[] generatePreMaster(SecureRandom rand,
+            ProtocolVersion ver) {
+
+        byte[] pm = new byte[48];
+        rand.nextBytes(pm);
+        pm[0] = ver.major;
+        pm[1] = ver.minor;
+
+        return pm;
+    }
+
+    // Clone not needed; internal use only
+    byte[] getUnencrypted() {
+        return preMaster;
+    }
+
+    // Clone not needed; internal use only
+    byte[] getEncrypted() {
+        return encrypted;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/ssl/Krb5KeyExchangeService.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,557 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.security.krb5.internal.ssl;
+
+import sun.security.ssl.ClientKeyExchange;
+import sun.security.ssl.Debug;
+import sun.security.ssl.ClientKeyExchangeService;
+import sun.security.ssl.HandshakeOutStream;
+
+import sun.security.jgss.GSSCaller;
+import sun.security.jgss.krb5.Krb5Util;
+import sun.security.jgss.krb5.ServiceCreds;
+import sun.security.krb5.EncryptedData;
+import sun.security.krb5.EncryptionKey;
+import sun.security.krb5.KrbException;
+import sun.security.krb5.PrincipalName;
+import sun.security.krb5.internal.EncTicketPart;
+import sun.security.krb5.internal.Ticket;
+import sun.security.krb5.internal.crypto.KeyUsage;
+import sun.security.ssl.ProtocolVersion;
+
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import javax.security.auth.Subject;
+import javax.security.auth.kerberos.KerberosKey;
+import javax.security.auth.kerberos.KerberosPrincipal;
+import javax.security.auth.kerberos.KerberosTicket;
+import javax.security.auth.kerberos.KeyTab;
+import javax.security.auth.kerberos.ServicePermission;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.net.InetAddress;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.Principal;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.security.SecureRandom;
+import java.util.Set;
+
+/**
+ * The provider for TLS_KRB_ cipher suites.
+ *
+ * @since 1.9
+ */
+public class Krb5KeyExchangeService implements ClientKeyExchangeService {
+
+    public static final Debug debug = Debug.getInstance("ssl");
+
+    @Override
+    public String[] supported() {
+        return new String[] { "KRB5", "KRB5_EXPORT" };
+    }
+
+    @Override
+    public Object getServiceCreds(AccessControlContext acc) {
+        try {
+            ServiceCreds serviceCreds = AccessController.doPrivileged(
+                    (PrivilegedExceptionAction<ServiceCreds>)
+                            () -> Krb5Util.getServiceCreds(
+                                    GSSCaller.CALLER_SSL_SERVER, null, acc));
+            if (debug != null && Debug.isOn("handshake")) {
+                System.out.println("Using Kerberos creds");
+            }
+            String serverPrincipal = serviceCreds.getName();
+            if (serverPrincipal != null) {
+                // When service is bound, we check ASAP. Otherwise,
+                // will check after client request is received
+                // in in Kerberos ClientKeyExchange
+                SecurityManager sm = System.getSecurityManager();
+                try {
+                    if (sm != null) {
+                        // Eliminate dependency on ServicePermission
+                        sm.checkPermission(new ServicePermission(
+                                serverPrincipal, "accept"), acc);
+                    }
+                } catch (SecurityException se) {
+                    if (debug != null && Debug.isOn("handshake")) {
+                        System.out.println("Permission to access Kerberos"
+                                + " secret key denied");
+                    }
+                    return null;
+                }
+            }
+            return serviceCreds;
+        } catch (PrivilegedActionException e) {
+            // Likely exception here is LoginException
+            if (debug != null && Debug.isOn("handshake")) {
+                System.out.println("Attempt to obtain Kerberos key failed: "
+                        + e.toString());
+            }
+            return null;
+        }
+    }
+
+    @Override
+    public String getServiceHostName(Principal principal) {
+        if (principal == null) {
+            return null;
+        }
+        String hostName = null;
+        try {
+            PrincipalName princName =
+                    new PrincipalName(principal.getName(),
+                            PrincipalName.KRB_NT_SRV_HST);
+            String[] nameParts = princName.getNameStrings();
+            if (nameParts.length >= 2) {
+                hostName = nameParts[1];
+            }
+        } catch (Exception e) {
+            // ignore
+        }
+        return hostName;
+    }
+
+
+    @Override
+    public boolean isRelated(boolean isClient,
+            AccessControlContext acc, Principal p) {
+
+        if (p == null) return false;
+        try {
+            Subject subject = AccessController.doPrivileged(
+                    (PrivilegedExceptionAction<Subject>)
+                            () -> Krb5Util.getSubject(
+                                    isClient ? GSSCaller.CALLER_SSL_CLIENT
+                                            : GSSCaller.CALLER_SSL_SERVER,
+                                    acc));
+            if (subject == null) {
+                if (debug != null && Debug.isOn("session")) {
+                    System.out.println("Kerberos credentials are" +
+                            " not present in the current Subject;" +
+                            " check if " +
+                            " javax.security.auth.useSubjectAsCreds" +
+                            " system property has been set to false");
+                }
+                return false;
+            }
+            Set<Principal> principals =
+                    subject.getPrincipals(Principal.class);
+            if (principals.contains(p)) {
+                // bound to this principal
+                return true;
+            } else {
+                if (isClient) {
+                    return false;
+                } else {
+                    for (KeyTab pc : subject.getPrivateCredentials(KeyTab.class)) {
+                        if (!pc.isBound()) {
+                            return true;
+                        }
+                    }
+                    return false;
+                }
+            }
+        } catch (PrivilegedActionException pae) {
+            if (debug != null && Debug.isOn("session")) {
+                System.out.println("Attempt to obtain" +
+                        " subject failed! " + pae);
+            }
+            return false;
+        }
+
+    }
+
+    public ClientKeyExchange createClientExchange(
+            String serverName, AccessControlContext acc,
+            ProtocolVersion protocolVerson, SecureRandom rand) throws IOException {
+        return new ExchangerImpl(serverName, acc, protocolVerson, rand);
+    }
+
+    public ClientKeyExchange createServerExchange(
+            ProtocolVersion protocolVersion, ProtocolVersion clientVersion,
+            SecureRandom rand, byte[] encodedTicket, byte[] encrypted,
+            AccessControlContext acc, Object serviceCreds) throws IOException {
+        return new ExchangerImpl(protocolVersion, clientVersion, rand,
+                encodedTicket, encrypted, acc, serviceCreds);
+    }
+
+    static class ExchangerImpl extends ClientKeyExchange {
+
+        final private KerberosPreMasterSecret preMaster;
+        final private byte[] encodedTicket;
+        final private KerberosPrincipal peerPrincipal;
+        final private KerberosPrincipal localPrincipal;
+
+        @Override
+        public int messageLength() {
+            return encodedTicket.length + preMaster.getEncrypted().length + 6;
+        }
+
+        @Override
+        public void send(HandshakeOutStream s) throws IOException {
+            s.putBytes16(encodedTicket);
+            s.putBytes16(null);
+            s.putBytes16(preMaster.getEncrypted());
+        }
+
+        @Override
+        public void print(PrintStream s) throws IOException {
+            s.println("*** ClientKeyExchange, Kerberos");
+
+            if (debug != null && Debug.isOn("verbose")) {
+                Debug.println(s, "Kerberos service ticket", encodedTicket);
+                Debug.println(s, "Random Secret", preMaster.getUnencrypted());
+                Debug.println(s, "Encrypted random Secret", preMaster.getEncrypted());
+            }
+        }
+
+        ExchangerImpl(String serverName, AccessControlContext acc,
+                ProtocolVersion protocolVersion, SecureRandom rand) throws IOException {
+
+            // Get service ticket
+            KerberosTicket ticket = getServiceTicket(serverName, acc);
+            encodedTicket = ticket.getEncoded();
+
+            // Record the Kerberos principals
+            peerPrincipal = ticket.getServer();
+            localPrincipal = ticket.getClient();
+
+            // Optional authenticator, encrypted using session key,
+            // currently ignored
+
+            // Generate premaster secret and encrypt it using session key
+            EncryptionKey sessionKey = new EncryptionKey(
+                    ticket.getSessionKeyType(),
+                    ticket.getSessionKey().getEncoded());
+
+            preMaster = new KerberosPreMasterSecret(protocolVersion,
+                    rand, sessionKey);
+        }
+
+        ExchangerImpl(
+                ProtocolVersion protocolVersion, ProtocolVersion clientVersion, SecureRandom rand,
+                byte[] encodedTicket, byte[] encrypted,
+                AccessControlContext acc, Object serviceCreds) throws IOException {
+
+            // Read ticket
+            this.encodedTicket = encodedTicket;
+
+            if (debug != null && Debug.isOn("verbose")) {
+                Debug.println(System.out,
+                        "encoded Kerberos service ticket", encodedTicket);
+            }
+
+            EncryptionKey sessionKey = null;
+            KerberosPrincipal tmpPeer = null;
+            KerberosPrincipal tmpLocal = null;
+
+            try {
+                Ticket t = new Ticket(encodedTicket);
+
+                EncryptedData encPart = t.encPart;
+                PrincipalName ticketSname = t.sname;
+
+                final ServiceCreds creds = (ServiceCreds)serviceCreds;
+                final KerberosPrincipal princ =
+                        new KerberosPrincipal(ticketSname.toString());
+
+                // For bound service, permission already checked at setup
+                if (creds.getName() == null) {
+                    SecurityManager sm = System.getSecurityManager();
+                    try {
+                        if (sm != null) {
+                            // Eliminate dependency on ServicePermission
+                            sm.checkPermission(new ServicePermission(
+                                    ticketSname.toString(), "accept"), acc);
+                        }
+                    } catch (SecurityException se) {
+                        serviceCreds = null;
+                        // Do not destroy keys. Will affect Subject
+                        if (debug != null && Debug.isOn("handshake")) {
+                            System.out.println("Permission to access Kerberos"
+                                    + " secret key denied");
+                            se.printStackTrace(System.out);
+                        }
+                        throw new IOException("Kerberos service not allowedy");
+                    }
+                }
+                KerberosKey[] serverKeys = AccessController.doPrivileged(
+                        new PrivilegedAction<KerberosKey[]>() {
+                            @Override
+                            public KerberosKey[] run() {
+                                return creds.getKKeys(princ);
+                            }
+                        });
+                if (serverKeys.length == 0) {
+                    throw new IOException("Found no key for " + princ +
+                            (creds.getName() == null ? "" :
+                                    (", this keytab is for " + creds.getName() + " only")));
+                }
+
+                /*
+                 * permission to access and use the secret key of the Kerberized
+                 * "host" service is done in ServerHandshaker.getKerberosKeys()
+                 * to ensure server has the permission to use the secret key
+                 * before promising the client
+                 */
+
+                // See if we have the right key to decrypt the ticket to get
+                // the session key.
+                int encPartKeyType = encPart.getEType();
+                Integer encPartKeyVersion = encPart.getKeyVersionNumber();
+                KerberosKey dkey = null;
+                try {
+                    dkey = findKey(encPartKeyType, encPartKeyVersion, serverKeys);
+                } catch (KrbException ke) { // a kvno mismatch
+                    throw new IOException(
+                            "Cannot find key matching version number", ke);
+                }
+                if (dkey == null) {
+                    // %%% Should print string repr of etype
+                    throw new IOException("Cannot find key of appropriate type" +
+                            " to decrypt ticket - need etype " + encPartKeyType);
+                }
+
+                EncryptionKey secretKey = new EncryptionKey(
+                        encPartKeyType,
+                        dkey.getEncoded());
+
+                // Decrypt encPart using server's secret key
+                byte[] bytes = encPart.decrypt(secretKey, KeyUsage.KU_TICKET);
+
+                // Reset data stream after decryption, remove redundant bytes
+                byte[] temp = encPart.reset(bytes);
+                EncTicketPart encTicketPart = new EncTicketPart(temp);
+
+                // Record the Kerberos Principals
+                tmpPeer = new KerberosPrincipal(encTicketPart.cname.getName());
+                tmpLocal = new KerberosPrincipal(ticketSname.getName());
+
+                sessionKey = encTicketPart.key;
+
+                if (debug != null && Debug.isOn("handshake")) {
+                    System.out.println("server principal: " + ticketSname);
+                    System.out.println("cname: " + encTicketPart.cname.toString());
+                }
+            } catch (IOException e) {
+                throw e;
+            } catch (Exception e) {
+                if (debug != null && Debug.isOn("handshake")) {
+                    System.out.println("KerberosWrapper error getting session key,"
+                            + " generating random secret (" + e.getMessage() + ")");
+                }
+                sessionKey = null;
+            }
+
+            //input.getBytes16();   // XXX Read and ignore authenticator
+
+            if (sessionKey != null) {
+                preMaster = new KerberosPreMasterSecret(protocolVersion,
+                        clientVersion, rand, encrypted, sessionKey);
+            } else {
+                // Generate bogus premaster secret
+                preMaster = new KerberosPreMasterSecret(clientVersion, rand);
+            }
+
+            peerPrincipal = tmpPeer;
+            localPrincipal = tmpLocal;
+        }
+
+        // Similar to sun.security.jgss.krb5.Krb5InitCredenetial/Krb5Context
+        private static KerberosTicket getServiceTicket(String serverName,
+                final AccessControlContext acc) throws IOException {
+
+            if ("localhost".equals(serverName) ||
+                    "localhost.localdomain".equals(serverName)) {
+
+                if (debug != null && Debug.isOn("handshake")) {
+                    System.out.println("Get the local hostname");
+                }
+                String localHost = java.security.AccessController.doPrivileged(
+                        new java.security.PrivilegedAction<String>() {
+                            public String run() {
+                                try {
+                                    return InetAddress.getLocalHost().getHostName();
+                                } catch (java.net.UnknownHostException e) {
+                                    if (debug != null && Debug.isOn("handshake")) {
+                                        System.out.println("Warning,"
+                                                + " cannot get the local hostname: "
+                                                + e.getMessage());
+                                    }
+                                    return null;
+                                }
+                            }
+                        });
+                if (localHost != null) {
+                    serverName = localHost;
+                }
+            }
+
+            // Resolve serverName (possibly in IP addr form) to Kerberos principal
+            // name for service with hostname
+            String serviceName = "host/" + serverName;
+            PrincipalName principal;
+            try {
+                principal = new PrincipalName(serviceName,
+                        PrincipalName.KRB_NT_SRV_HST);
+            } catch (SecurityException se) {
+                throw se;
+            } catch (Exception e) {
+                IOException ioe = new IOException("Invalid service principal" +
+                        " name: " + serviceName);
+                ioe.initCause(e);
+                throw ioe;
+            }
+            String realm = principal.getRealmAsString();
+
+            final String serverPrincipal = principal.toString();
+            final String tgsPrincipal = "krbtgt/" + realm + "@" + realm;
+            final String clientPrincipal = null;  // use default
+
+
+            // check permission to obtain a service ticket to initiate a
+            // context with the "host" service
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                sm.checkPermission(new ServicePermission(serverPrincipal,
+                        "initiate"), acc);
+            }
+
+            try {
+                KerberosTicket ticket = AccessController.doPrivileged(
+                        new PrivilegedExceptionAction<KerberosTicket>() {
+                            public KerberosTicket run() throws Exception {
+                                return Krb5Util.getTicketFromSubjectAndTgs(
+                                        GSSCaller.CALLER_SSL_CLIENT,
+                                        clientPrincipal, serverPrincipal,
+                                        tgsPrincipal, acc);
+                            }});
+
+                if (ticket == null) {
+                    throw new IOException("Failed to find any kerberos service" +
+                            " ticket for " + serverPrincipal);
+                }
+                return ticket;
+            } catch (PrivilegedActionException e) {
+                IOException ioe = new IOException(
+                        "Attempt to obtain kerberos service ticket for " +
+                                serverPrincipal + " failed!");
+                ioe.initCause(e);
+                throw ioe;
+            }
+        }
+
+        @Override
+        public SecretKey clientKeyExchange() {
+            byte[] secretBytes = preMaster.getUnencrypted();
+            return new SecretKeySpec(secretBytes, "TlsPremasterSecret");
+        }
+
+        @Override
+        public Principal getPeerPrincipal() {
+            return peerPrincipal;
+        }
+
+        @Override
+        public Principal getLocalPrincipal() {
+            return localPrincipal;
+        }
+
+        /**
+         * Determines if a kvno matches another kvno. Used in the method
+         * findKey(etype, version, keys). Always returns true if either input
+         * is null or zero, in case any side does not have kvno info available.
+         *
+         * Note: zero is included because N/A is not a legal value for kvno
+         * in javax.security.auth.kerberos.KerberosKey. Therefore, the info
+         * that the kvno is N/A might be lost when converting between
+         * EncryptionKey and KerberosKey.
+         */
+        private static boolean versionMatches(Integer v1, int v2) {
+            if (v1 == null || v1 == 0 || v2 == 0) {
+                return true;
+            }
+            return v1.equals(v2);
+        }
+
+        private static KerberosKey findKey(int etype, Integer version,
+                KerberosKey[] keys) throws KrbException {
+            int ktype;
+            boolean etypeFound = false;
+
+            // When no matched kvno is found, returns tke key of the same
+            // etype with the highest kvno
+            int kvno_found = 0;
+            KerberosKey key_found = null;
+
+            for (int i = 0; i < keys.length; i++) {
+                ktype = keys[i].getKeyType();
+                if (etype == ktype) {
+                    int kv = keys[i].getVersionNumber();
+                    etypeFound = true;
+                    if (versionMatches(version, kv)) {
+                        return keys[i];
+                    } else if (kv > kvno_found) {
+                        key_found = keys[i];
+                        kvno_found = kv;
+                    }
+                }
+            }
+            // Key not found.
+            // %%% kludge to allow DES keys to be used for diff etypes
+            if ((etype == EncryptedData.ETYPE_DES_CBC_CRC ||
+                    etype == EncryptedData.ETYPE_DES_CBC_MD5)) {
+                for (int i = 0; i < keys.length; i++) {
+                    ktype = keys[i].getKeyType();
+                    if (ktype == EncryptedData.ETYPE_DES_CBC_CRC ||
+                            ktype == EncryptedData.ETYPE_DES_CBC_MD5) {
+                        int kv = keys[i].getVersionNumber();
+                        etypeFound = true;
+                        if (versionMatches(version, kv)) {
+                            return new KerberosKey(keys[i].getPrincipal(),
+                                    keys[i].getEncoded(),
+                                    etype,
+                                    kv);
+                        } else if (kv > kvno_found) {
+                            key_found = new KerberosKey(keys[i].getPrincipal(),
+                                    keys[i].getEncoded(),
+                                    etype,
+                                    kv);
+                            kvno_found = kv;
+                        }
+                    }
+                }
+            }
+            if (etypeFound) {
+                return key_found;
+            }
+            return null;
+        }
+    }
+}
--- a/jdk/src/java.security.jgss/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,463 +0,0 @@
-/*
- * 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
- * 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.security.ssl.krb5;
-
-import java.io.IOException;
-import java.io.PrintStream;
-import java.security.AccessController;
-import java.security.AccessControlContext;
-import java.security.PrivilegedExceptionAction;
-import java.security.PrivilegedActionException;
-import java.security.SecureRandom;
-import java.net.InetAddress;
-import java.security.PrivilegedAction;
-
-import javax.security.auth.kerberos.KerberosTicket;
-import javax.security.auth.kerberos.KerberosKey;
-import javax.security.auth.kerberos.KerberosPrincipal;
-import javax.security.auth.kerberos.ServicePermission;
-import sun.security.jgss.GSSCaller;
-
-import sun.security.krb5.EncryptionKey;
-import sun.security.krb5.EncryptedData;
-import sun.security.krb5.PrincipalName;
-import sun.security.krb5.internal.Ticket;
-import sun.security.krb5.internal.EncTicketPart;
-import sun.security.krb5.internal.crypto.KeyUsage;
-
-import sun.security.jgss.krb5.Krb5Util;
-import sun.security.jgss.krb5.ServiceCreds;
-import sun.security.krb5.KrbException;
-import sun.security.krb5.internal.Krb5;
-
-import sun.security.ssl.Debug;
-import sun.security.ssl.HandshakeInStream;
-import sun.security.ssl.HandshakeOutStream;
-import sun.security.ssl.Krb5Helper;
-import sun.security.ssl.ProtocolVersion;
-
-/**
- * This is Kerberos option in the client key exchange message
- * (CLIENT -> SERVER). It holds the Kerberos ticket and the encrypted
- * premaster secret encrypted with the session key sealed in the ticket.
- * From RFC 2712:
- *  struct
- *  {
- *    opaque Ticket;
- *    opaque authenticator;            // optional
- *    opaque EncryptedPreMasterSecret; // encrypted with the session key
- *                                     // which is sealed in the ticket
- *  } KerberosWrapper;
- *
- *
- * Ticket and authenticator are encrypted as per RFC 1510 (in ASN.1)
- * Encrypted pre-master secret has the same structure as it does for RSA
- * except for Kerberos, the encryption key is the session key instead of
- * the RSA public key.
- *
- * XXX authenticator currently ignored
- *
- */
-public final class KerberosClientKeyExchangeImpl
-    extends sun.security.ssl.KerberosClientKeyExchange {
-
-    private KerberosPreMasterSecret preMaster;
-    private byte[] encodedTicket;
-    private KerberosPrincipal peerPrincipal;
-    private KerberosPrincipal localPrincipal;
-
-    public KerberosClientKeyExchangeImpl() {
-    }
-
-    /**
-     * Creates an instance of KerberosClientKeyExchange consisting of the
-     * Kerberos service ticket, authenticator and encrypted premaster secret.
-     * Called by client handshaker.
-     *
-     * @param serverName name of server with which to do handshake;
-     *             this is used to get the Kerberos service ticket
-     * @param protocolVersion Maximum version supported by client (i.e,
-     *          version it requested in client hello)
-     * @param rand random number generator to use for generating pre-master
-     *          secret
-     */
-    @Override
-    public void init(String serverName,
-        AccessControlContext acc, ProtocolVersion protocolVersion,
-        SecureRandom rand) throws IOException {
-
-         // Get service ticket
-         KerberosTicket ticket = getServiceTicket(serverName, acc);
-         encodedTicket = ticket.getEncoded();
-
-         // Record the Kerberos principals
-         peerPrincipal = ticket.getServer();
-         localPrincipal = ticket.getClient();
-
-         // Optional authenticator, encrypted using session key,
-         // currently ignored
-
-         // Generate premaster secret and encrypt it using session key
-         EncryptionKey sessionKey = new EncryptionKey(
-                                        ticket.getSessionKeyType(),
-                                        ticket.getSessionKey().getEncoded());
-
-         preMaster = new KerberosPreMasterSecret(protocolVersion,
-             rand, sessionKey);
-    }
-
-    /**
-     * Creates an instance of KerberosClientKeyExchange from its ASN.1 encoding.
-     * Used by ServerHandshaker to verify and obtain premaster secret.
-     *
-     * @param protocolVersion current protocol version
-     * @param clientVersion version requested by client in its ClientHello;
-     *          used by premaster secret version check
-     * @param rand random number generator used for generating random
-     *          premaster secret if ticket and/or premaster verification fails
-     * @param input inputstream from which to get ASN.1-encoded KerberosWrapper
-     * @param acc the AccessControlContext of the handshaker
-     * @param serviceCreds server's creds
-     */
-    @Override
-    public void init(ProtocolVersion protocolVersion,
-        ProtocolVersion clientVersion,
-        SecureRandom rand, HandshakeInStream input, AccessControlContext acc, Object serviceCreds)
-        throws IOException {
-
-        // Read ticket
-        encodedTicket = input.getBytes16();
-
-        if (debug != null && Debug.isOn("verbose")) {
-            Debug.println(System.out,
-                "encoded Kerberos service ticket", encodedTicket);
-        }
-
-        EncryptionKey sessionKey = null;
-
-        try {
-            Ticket t = new Ticket(encodedTicket);
-
-            EncryptedData encPart = t.encPart;
-            PrincipalName ticketSname = t.sname;
-
-            final ServiceCreds creds = (ServiceCreds)serviceCreds;
-            final KerberosPrincipal princ =
-                    new KerberosPrincipal(ticketSname.toString());
-
-            // For bound service, permission already checked at setup
-            if (creds.getName() == null) {
-                SecurityManager sm = System.getSecurityManager();
-                try {
-                    if (sm != null) {
-                        // Eliminate dependency on ServicePermission
-                        sm.checkPermission(Krb5Helper.getServicePermission(
-                                ticketSname.toString(), "accept"), acc);
-                    }
-                } catch (SecurityException se) {
-                    serviceCreds = null;
-                    // Do not destroy keys. Will affect Subject
-                    if (debug != null && Debug.isOn("handshake")) {
-                        System.out.println("Permission to access Kerberos"
-                                + " secret key denied");
-                    }
-                    throw new IOException("Kerberos service not allowedy");
-                }
-            }
-            KerberosKey[] serverKeys = AccessController.doPrivileged(
-                    new PrivilegedAction<KerberosKey[]>() {
-                        @Override
-                        public KerberosKey[] run() {
-                            return creds.getKKeys(princ);
-                        }
-                    });
-            if (serverKeys.length == 0) {
-                throw new IOException("Found no key for " + princ +
-                        (creds.getName() == null ? "" :
-                        (", this keytab is for " + creds.getName() + " only")));
-            }
-
-            /*
-             * permission to access and use the secret key of the Kerberized
-             * "host" service is done in ServerHandshaker.getKerberosKeys()
-             * to ensure server has the permission to use the secret key
-             * before promising the client
-             */
-
-            // See if we have the right key to decrypt the ticket to get
-            // the session key.
-            int encPartKeyType = encPart.getEType();
-            Integer encPartKeyVersion = encPart.getKeyVersionNumber();
-            KerberosKey dkey = null;
-            try {
-                dkey = findKey(encPartKeyType, encPartKeyVersion, serverKeys);
-            } catch (KrbException ke) { // a kvno mismatch
-                throw new IOException(
-                        "Cannot find key matching version number", ke);
-            }
-            if (dkey == null) {
-                // %%% Should print string repr of etype
-                throw new IOException("Cannot find key of appropriate type" +
-                        " to decrypt ticket - need etype " + encPartKeyType);
-            }
-
-            EncryptionKey secretKey = new EncryptionKey(
-                encPartKeyType,
-                dkey.getEncoded());
-
-            // Decrypt encPart using server's secret key
-            byte[] bytes = encPart.decrypt(secretKey, KeyUsage.KU_TICKET);
-
-            // Reset data stream after decryption, remove redundant bytes
-            byte[] temp = encPart.reset(bytes);
-            EncTicketPart encTicketPart = new EncTicketPart(temp);
-
-            // Record the Kerberos Principals
-            peerPrincipal =
-                new KerberosPrincipal(encTicketPart.cname.getName());
-            localPrincipal = new KerberosPrincipal(ticketSname.getName());
-
-            sessionKey = encTicketPart.key;
-
-            if (debug != null && Debug.isOn("handshake")) {
-                System.out.println("server principal: " + ticketSname);
-                System.out.println("cname: " + encTicketPart.cname.toString());
-            }
-        } catch (IOException e) {
-            throw e;
-        } catch (Exception e) {
-            if (debug != null && Debug.isOn("handshake")) {
-                System.out.println("KerberosWrapper error getting session key,"
-                        + " generating random secret (" + e.getMessage() + ")");
-            }
-            sessionKey = null;
-        }
-
-        input.getBytes16();   // XXX Read and ignore authenticator
-
-        if (sessionKey != null) {
-            preMaster = new KerberosPreMasterSecret(protocolVersion,
-                clientVersion, rand, input, sessionKey);
-        } else {
-            // Generate bogus premaster secret
-            preMaster = new KerberosPreMasterSecret(clientVersion, rand);
-        }
-    }
-
-    @Override
-    public int messageLength() {
-        return (6 + encodedTicket.length + preMaster.getEncrypted().length);
-    }
-
-    @Override
-    public void send(HandshakeOutStream s) throws IOException {
-        s.putBytes16(encodedTicket);
-        s.putBytes16(null); // XXX no authenticator
-        s.putBytes16(preMaster.getEncrypted());
-    }
-
-    @Override
-    public void print(PrintStream s) throws IOException {
-        s.println("*** ClientKeyExchange, Kerberos");
-
-        if (debug != null && Debug.isOn("verbose")) {
-            Debug.println(s, "Kerberos service ticket", encodedTicket);
-            Debug.println(s, "Random Secret", preMaster.getUnencrypted());
-            Debug.println(s, "Encrypted random Secret",
-                preMaster.getEncrypted());
-        }
-    }
-
-    // Similar to sun.security.jgss.krb5.Krb5InitCredenetial/Krb5Context
-    private static KerberosTicket getServiceTicket(String serverName,
-        final AccessControlContext acc) throws IOException {
-
-        if ("localhost".equals(serverName) ||
-                "localhost.localdomain".equals(serverName)) {
-
-            if (debug != null && Debug.isOn("handshake")) {
-                System.out.println("Get the local hostname");
-            }
-            String localHost = java.security.AccessController.doPrivileged(
-                new java.security.PrivilegedAction<String>() {
-                public String run() {
-                    try {
-                        return InetAddress.getLocalHost().getHostName();
-                    } catch (java.net.UnknownHostException e) {
-                        if (debug != null && Debug.isOn("handshake")) {
-                            System.out.println("Warning,"
-                                + " cannot get the local hostname: "
-                                + e.getMessage());
-                        }
-                        return null;
-                    }
-                }
-            });
-            if (localHost != null) {
-                serverName = localHost;
-            }
-        }
-
-        // Resolve serverName (possibly in IP addr form) to Kerberos principal
-        // name for service with hostname
-        String serviceName = "host/" + serverName;
-        PrincipalName principal;
-        try {
-            principal = new PrincipalName(serviceName,
-                                PrincipalName.KRB_NT_SRV_HST);
-        } catch (SecurityException se) {
-            throw se;
-        } catch (Exception e) {
-            IOException ioe = new IOException("Invalid service principal" +
-                                " name: " + serviceName);
-            ioe.initCause(e);
-            throw ioe;
-        }
-        String realm = principal.getRealmAsString();
-
-        final String serverPrincipal = principal.toString();
-        final String tgsPrincipal = "krbtgt/" + realm + "@" + realm;
-        final String clientPrincipal = null;  // use default
-
-
-        // check permission to obtain a service ticket to initiate a
-        // context with the "host" service
-        SecurityManager sm = System.getSecurityManager();
-        if (sm != null) {
-           sm.checkPermission(new ServicePermission(serverPrincipal,
-                                "initiate"), acc);
-        }
-
-        try {
-            KerberosTicket ticket = AccessController.doPrivileged(
-                new PrivilegedExceptionAction<KerberosTicket>() {
-                public KerberosTicket run() throws Exception {
-                    return Krb5Util.getTicketFromSubjectAndTgs(
-                        GSSCaller.CALLER_SSL_CLIENT,
-                        clientPrincipal, serverPrincipal,
-                        tgsPrincipal, acc);
-                        }});
-
-            if (ticket == null) {
-                throw new IOException("Failed to find any kerberos service" +
-                        " ticket for " + serverPrincipal);
-            }
-            return ticket;
-        } catch (PrivilegedActionException e) {
-            IOException ioe = new IOException(
-                "Attempt to obtain kerberos service ticket for " +
-                        serverPrincipal + " failed!");
-            ioe.initCause(e);
-            throw ioe;
-        }
-    }
-
-    @Override
-    public byte[] getUnencryptedPreMasterSecret() {
-        return preMaster.getUnencrypted();
-    }
-
-    @Override
-    public KerberosPrincipal getPeerPrincipal() {
-        return peerPrincipal;
-    }
-
-    @Override
-    public KerberosPrincipal getLocalPrincipal() {
-        return localPrincipal;
-    }
-
-    /**
-     * Determines if a kvno matches another kvno. Used in the method
-     * findKey(etype, version, keys). Always returns true if either input
-     * is null or zero, in case any side does not have kvno info available.
-     *
-     * Note: zero is included because N/A is not a legal value for kvno
-     * in javax.security.auth.kerberos.KerberosKey. Therefore, the info
-     * that the kvno is N/A might be lost when converting between
-     * EncryptionKey and KerberosKey.
-     */
-    private static boolean versionMatches(Integer v1, int v2) {
-        if (v1 == null || v1 == 0 || v2 == 0) {
-            return true;
-        }
-        return v1.equals(v2);
-    }
-
-    private static KerberosKey findKey(int etype, Integer version,
-            KerberosKey[] keys) throws KrbException {
-        int ktype;
-        boolean etypeFound = false;
-
-        // When no matched kvno is found, returns tke key of the same
-        // etype with the highest kvno
-        int kvno_found = 0;
-        KerberosKey key_found = null;
-
-        for (int i = 0; i < keys.length; i++) {
-            ktype = keys[i].getKeyType();
-            if (etype == ktype) {
-                int kv = keys[i].getVersionNumber();
-                etypeFound = true;
-                if (versionMatches(version, kv)) {
-                    return keys[i];
-                } else if (kv > kvno_found) {
-                    key_found = keys[i];
-                    kvno_found = kv;
-                }
-            }
-        }
-        // Key not found.
-        // %%% kludge to allow DES keys to be used for diff etypes
-        if ((etype == EncryptedData.ETYPE_DES_CBC_CRC ||
-            etype == EncryptedData.ETYPE_DES_CBC_MD5)) {
-            for (int i = 0; i < keys.length; i++) {
-                ktype = keys[i].getKeyType();
-                if (ktype == EncryptedData.ETYPE_DES_CBC_CRC ||
-                        ktype == EncryptedData.ETYPE_DES_CBC_MD5) {
-                    int kv = keys[i].getVersionNumber();
-                    etypeFound = true;
-                    if (versionMatches(version, kv)) {
-                        return new KerberosKey(keys[i].getPrincipal(),
-                            keys[i].getEncoded(),
-                            etype,
-                            kv);
-                    } else if (kv > kvno_found) {
-                        key_found = new KerberosKey(keys[i].getPrincipal(),
-                                keys[i].getEncoded(),
-                                etype,
-                                kv);
-                        kvno_found = kv;
-                    }
-                }
-            }
-        }
-        if (etypeFound) {
-            return key_found;
-        }
-        return null;
-    }
-}
--- a/jdk/src/java.security.jgss/share/classes/sun/security/ssl/krb5/KerberosPreMasterSecret.java	Thu Jun 04 18:50:30 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,272 +0,0 @@
-/*
- * Copyright (c) 2003, 2010, 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.security.ssl.krb5;
-
-import java.io.*;
-import java.security.*;
-import java.util.Arrays;
-
-import javax.net.ssl.*;
-
-import sun.security.krb5.EncryptionKey;
-import sun.security.krb5.EncryptedData;
-import sun.security.krb5.KrbException;
-import sun.security.krb5.internal.crypto.KeyUsage;
-
-import sun.security.ssl.Debug;
-import sun.security.ssl.HandshakeInStream;
-import sun.security.ssl.HandshakeMessage;
-import sun.security.ssl.ProtocolVersion;
-
-/**
- * This is the Kerberos premaster secret in the Kerberos client key
- * exchange message (CLIENT --> SERVER); it holds the
- * Kerberos-encrypted pre-master secret. The secret is encrypted using the
- * Kerberos session key.  The padding and size of the resulting message
- * depends on the session key type, but the pre-master secret is
- * always exactly 48 bytes.
- *
- */
-final class KerberosPreMasterSecret {
-
-    private ProtocolVersion protocolVersion; // preMaster [0,1]
-    private byte preMaster[];           // 48 bytes
-    private byte encrypted[];
-
-    /**
-     * Constructor used by client to generate premaster secret.
-     *
-     * Client randomly creates a pre-master secret and encrypts it
-     * using the Kerberos session key; only the server can decrypt
-     * it, using the session key available in the service ticket.
-     *
-     * @param protocolVersion used to set preMaster[0,1]
-     * @param generator random number generator for generating premaster secret
-     * @param sessionKey Kerberos session key for encrypting premaster secret
-     */
-    KerberosPreMasterSecret(ProtocolVersion protocolVersion,
-        SecureRandom generator, EncryptionKey sessionKey) throws IOException {
-
-        if (sessionKey.getEType() ==
-            EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD) {
-            throw new IOException(
-               "session keys with des3-cbc-hmac-sha1-kd encryption type " +
-               "are not supported for TLS Kerberos cipher suites");
-        }
-
-        this.protocolVersion = protocolVersion;
-        preMaster = generatePreMaster(generator, protocolVersion);
-
-        // Encrypt premaster secret
-        try {
-            EncryptedData eData = new EncryptedData(sessionKey, preMaster,
-                KeyUsage.KU_UNKNOWN);
-            encrypted = eData.getBytes();  // not ASN.1 encoded.
-
-        } catch (KrbException e) {
-            throw (SSLKeyException)new SSLKeyException
-                ("Kerberos premaster secret error").initCause(e);
-        }
-    }
-
-    /*
-     * Constructor used by server to decrypt encrypted premaster secret.
-     * The protocol version in preMaster[0,1] must match either currentVersion
-     * or clientVersion, otherwise, the premaster secret is set to
-     * a random one to foil possible attack.
-     *
-     * @param currentVersion version of protocol being used
-     * @param clientVersion version requested by client
-     * @param generator random number generator used to generate
-     *        bogus premaster secret if premaster secret verification fails
-     * @param input input stream from which to read the encrypted
-     *        premaster secret
-     * @param sessionKey Kerberos session key to be used for decryption
-     */
-    KerberosPreMasterSecret(ProtocolVersion currentVersion,
-        ProtocolVersion clientVersion,
-        SecureRandom generator, HandshakeInStream input,
-        EncryptionKey sessionKey) throws IOException {
-
-         // Extract encrypted premaster secret from message
-         encrypted = input.getBytes16();
-
-         if (HandshakeMessage.debug != null && Debug.isOn("handshake")) {
-            if (encrypted != null) {
-                Debug.println(System.out,
-                     "encrypted premaster secret", encrypted);
-            }
-         }
-
-        if (sessionKey.getEType() ==
-            EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD) {
-            throw new IOException(
-               "session keys with des3-cbc-hmac-sha1-kd encryption type " +
-               "are not supported for TLS Kerberos cipher suites");
-        }
-
-        // Decrypt premaster secret
-        try {
-            EncryptedData data = new EncryptedData(sessionKey.getEType(),
-                        null /* optional kvno */, encrypted);
-
-            byte[] temp = data.decrypt(sessionKey, KeyUsage.KU_UNKNOWN);
-            if (HandshakeMessage.debug != null && Debug.isOn("handshake")) {
-                 if (encrypted != null) {
-                     Debug.println(System.out,
-                         "decrypted premaster secret", temp);
-                 }
-            }
-
-            // Remove padding bytes after decryption. Only DES and DES3 have
-            // paddings and we don't support DES3 in TLS (see above)
-
-            if (temp.length == 52 &&
-                    data.getEType() == EncryptedData.ETYPE_DES_CBC_CRC) {
-                // For des-cbc-crc, 4 paddings. Value can be 0x04 or 0x00.
-                if (paddingByteIs(temp, 52, (byte)4) ||
-                        paddingByteIs(temp, 52, (byte)0)) {
-                    temp = Arrays.copyOf(temp, 48);
-                }
-            } else if (temp.length == 56 &&
-                    data.getEType() == EncryptedData.ETYPE_DES_CBC_MD5) {
-                // For des-cbc-md5, 8 paddings with 0x08, or no padding
-                if (paddingByteIs(temp, 56, (byte)8)) {
-                    temp = Arrays.copyOf(temp, 48);
-                }
-            }
-
-            preMaster = temp;
-
-            protocolVersion = ProtocolVersion.valueOf(preMaster[0],
-                 preMaster[1]);
-            if (HandshakeMessage.debug != null && Debug.isOn("handshake")) {
-                 System.out.println("Kerberos PreMasterSecret version: "
-                        + protocolVersion);
-            }
-        } catch (Exception e) {
-            // catch exception & process below
-            preMaster = null;
-            protocolVersion = currentVersion;
-        }
-
-        // check if the premaster secret version is ok
-        // the specification says that it must be the maximum version supported
-        // by the client from its ClientHello message. However, many
-        // old implementations send the negotiated version, so accept both
-        // for SSL v3.0 and TLS v1.0.
-        // NOTE that we may be comparing two unsupported version numbers in
-        // the second case, which is why we cannot use object references
-        // equality in this special case
-        boolean versionMismatch = (protocolVersion.v != clientVersion.v);
-
-        /*
-         * we never checked the client_version in server side
-         * for TLS v1.0 and SSL v3.0. For compatibility, we
-         * maintain this behavior.
-         */
-        if (versionMismatch && (clientVersion.v <= 0x0301)) {
-            versionMismatch = (protocolVersion.v != currentVersion.v);
-        }
-
-        /*
-         * Bogus decrypted ClientKeyExchange? If so, conjure a
-         * a random preMaster secret that will fail later during
-         * Finished message processing. This is a countermeasure against
-         * the "interactive RSA PKCS#1 encryption envelop attack" reported
-         * in June 1998. Preserving the executation path will
-         * mitigate timing attacks and force consistent error handling
-         * that will prevent an attacking client from differentiating
-         * different kinds of decrypted ClientKeyExchange bogosities.
-         */
-         if ((preMaster == null) || (preMaster.length != 48)
-                || versionMismatch) {
-            if (HandshakeMessage.debug != null && Debug.isOn("handshake")) {
-                System.out.println("Kerberos PreMasterSecret error, "
-                                   + "generating random secret");
-                if (preMaster != null) {
-                    Debug.println(System.out, "Invalid secret", preMaster);
-                }
-            }
-
-            /*
-             * Randomize the preMaster secret with the
-             * ClientHello.client_version, as will produce invalid master
-             * secret to prevent the attacks.
-             */
-            preMaster = generatePreMaster(generator, clientVersion);
-            protocolVersion = clientVersion;
-        }
-    }
-
-    /**
-     * Checks if all paddings of data are b
-     * @param data the block with padding
-     * @param len length of data, >= 48
-     * @param b expected padding byte
-     */
-    private static boolean paddingByteIs(byte[] data, int len, byte b) {
-        for (int i=48; i<len; i++) {
-            if (data[i] != b) return false;
-        }
-        return true;
-    }
-
-    /*
-     * Used by server to generate premaster secret in case of
-     * problem decoding ticket.
-     *
-     * @param protocolVersion used for preMaster[0,1]
-     * @param generator random number generator to use for generating secret.
-     */
-    KerberosPreMasterSecret(ProtocolVersion protocolVersion,
-        SecureRandom generator) {
-
-        this.protocolVersion = protocolVersion;
-        preMaster = generatePreMaster(generator, protocolVersion);
-    }
-
-    private static byte[] generatePreMaster(SecureRandom rand,
-        ProtocolVersion ver) {
-
-        byte[] pm = new byte[48];
-        rand.nextBytes(pm);
-        pm[0] = ver.major;
-        pm[1] = ver.minor;
-
-        return pm;
-    }
-
-    // Clone not needed; internal use only
-    byte[] getUnencrypted() {
-        return preMaster;
-    }
-
-    // Clone not needed; internal use only
-    byte[] getEncrypted() {
-        return encrypted;
-    }
-}
--- a/jdk/src/java.security.jgss/share/classes/sun/security/ssl/krb5/Krb5ProxyImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,121 +0,0 @@
-/*
- * Copyright (c) 2009, 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.security.ssl.krb5;
-
-import java.security.AccessControlContext;
-import java.security.Permission;
-import java.security.Principal;
-import java.util.Set;
-import javax.crypto.SecretKey;
-import javax.security.auth.Subject;
-import javax.security.auth.kerberos.KerberosKey;
-import javax.security.auth.kerberos.KeyTab;
-import javax.security.auth.kerberos.ServicePermission;
-import javax.security.auth.login.LoginException;
-
-import sun.security.jgss.GSSCaller;
-import sun.security.jgss.krb5.Krb5Util;
-import sun.security.jgss.krb5.ServiceCreds;
-import sun.security.krb5.PrincipalName;
-import sun.security.ssl.Krb5Proxy;
-
-/**
- * An implementation of Krb5Proxy that simply delegates to the appropriate
- * Kerberos APIs.
- */
-public class Krb5ProxyImpl implements Krb5Proxy {
-
-    public Krb5ProxyImpl() { }
-
-    @Override
-    public Subject getClientSubject(AccessControlContext acc)
-            throws LoginException {
-        return Krb5Util.getSubject(GSSCaller.CALLER_SSL_CLIENT, acc);
-    }
-
-    @Override
-    public Subject getServerSubject(AccessControlContext acc)
-            throws LoginException {
-        return Krb5Util.getSubject(GSSCaller.CALLER_SSL_SERVER, acc);
-    }
-
-    @Override
-    public Object getServiceCreds(AccessControlContext acc)
-            throws LoginException {
-        ServiceCreds serviceCreds =
-            Krb5Util.getServiceCreds(GSSCaller.CALLER_SSL_SERVER, null, acc);
-        return serviceCreds;
-    }
-
-    @Override
-    public String getServerPrincipalName(Object serviceCreds) {
-        return ((ServiceCreds)serviceCreds).getName();
-    }
-
-    @Override
-    public String getPrincipalHostName(Principal principal) {
-        if (principal == null) {
-           return null;
-        }
-        String hostName = null;
-        try {
-            PrincipalName princName =
-                new PrincipalName(principal.getName(),
-                        PrincipalName.KRB_NT_SRV_HST);
-            String[] nameParts = princName.getNameStrings();
-            if (nameParts.length >= 2) {
-                hostName = nameParts[1];
-            }
-        } catch (Exception e) {
-            // ignore
-        }
-        return hostName;
-    }
-
-
-    @Override
-    public Permission getServicePermission(String principalName,
-            String action) {
-        return new ServicePermission(principalName, action);
-    }
-
-    @Override
-    public boolean isRelated(Subject subject, Principal princ) {
-        if (princ == null) return false;
-        Set<Principal> principals =
-                subject.getPrincipals(Principal.class);
-        if (principals.contains(princ)) {
-            // bound to this principal
-            return true;
-        }
-        for (KeyTab pc: subject.getPrivateCredentials(KeyTab.class)) {
-            if (!pc.isBound()) {
-                return true;
-            }
-        }
-        return false;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.charsets/share/classes/sun/nio/cs/ext/AbstractCharsetProvider.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2000, 2011, 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.nio.cs.ext;
+
+import java.lang.ref.SoftReference;
+import java.nio.charset.Charset;
+import java.nio.charset.spi.CharsetProvider;
+import java.util.ArrayList;
+import java.util.TreeMap;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import sun.misc.ASCIICaseInsensitiveComparator;
+
+
+/**
+ * Abstract base class for charset providers.
+ *
+ * @author Mark Reinhold
+ */
+
+public class AbstractCharsetProvider
+    extends CharsetProvider
+{
+
+    /* Maps canonical names to class names
+     */
+    private Map<String,String> classMap
+        = new TreeMap<>(ASCIICaseInsensitiveComparator.CASE_INSENSITIVE_ORDER);
+
+    /* Maps alias names to canonical names
+     */
+    private Map<String,String> aliasMap
+        = new TreeMap<>(ASCIICaseInsensitiveComparator.CASE_INSENSITIVE_ORDER);
+
+    /* Maps canonical names to alias-name arrays
+     */
+    private Map<String,String[]> aliasNameMap
+        = new TreeMap<>(ASCIICaseInsensitiveComparator.CASE_INSENSITIVE_ORDER);
+
+    /* Maps canonical names to soft references that hold cached instances
+     */
+    private Map<String,SoftReference<Charset>> cache
+        = new TreeMap<>(ASCIICaseInsensitiveComparator.CASE_INSENSITIVE_ORDER);
+
+    private String packagePrefix;
+
+    protected AbstractCharsetProvider() {
+        packagePrefix = "sun.nio.cs";
+    }
+
+    protected AbstractCharsetProvider(String pkgPrefixName) {
+        packagePrefix = pkgPrefixName;
+    }
+
+    /* Add an entry to the given map, but only if no mapping yet exists
+     * for the given name.
+     */
+    private static <K,V> void put(Map<K,V> m, K name, V value) {
+        if (!m.containsKey(name))
+            m.put(name, value);
+    }
+
+    private static <K,V> void remove(Map<K,V> m, K name) {
+        V x  = m.remove(name);
+        assert (x != null);
+    }
+
+    /* Declare support for the given charset
+     */
+    protected void charset(String name, String className, String[] aliases) {
+        synchronized (this) {
+            put(classMap, name, className);
+            for (int i = 0; i < aliases.length; i++)
+                put(aliasMap, aliases[i], name);
+            put(aliasNameMap, name, aliases);
+            cache.clear();
+        }
+    }
+
+    protected void deleteCharset(String name, String[] aliases) {
+        synchronized (this) {
+            remove(classMap, name);
+            for (int i = 0; i < aliases.length; i++)
+                remove(aliasMap, aliases[i]);
+            remove(aliasNameMap, name);
+            cache.clear();
+        }
+    }
+
+    protected boolean hasCharset(String name) {
+        synchronized (this) {
+            return classMap.containsKey(name);
+        }
+    }
+
+    /* Late initialization hook, needed by some providers
+     */
+    protected void init() { }
+
+    private String canonicalize(String charsetName) {
+        String acn = aliasMap.get(charsetName);
+        return (acn != null) ? acn : charsetName;
+    }
+
+    private Charset lookup(String csn) {
+
+        // Check cache first
+        SoftReference<Charset> sr = cache.get(csn);
+        if (sr != null) {
+            Charset cs = sr.get();
+            if (cs != null)
+                return cs;
+        }
+
+        // Do we even support this charset?
+        String cln = classMap.get(csn);
+
+        if (cln == null)
+            return null;
+
+        // Instantiate the charset and cache it
+        try {
+
+            Class<?> c = Class.forName(packagePrefix + "." + cln,
+                                       true,
+                                       this.getClass().getClassLoader());
+
+            Charset cs = (Charset)c.newInstance();
+            cache.put(csn, new SoftReference<Charset>(cs));
+            return cs;
+        } catch (ClassNotFoundException x) {
+            return null;
+        } catch (IllegalAccessException x) {
+            return null;
+        } catch (InstantiationException x) {
+            return null;
+        }
+    }
+
+    public final Charset charsetForName(String charsetName) {
+        synchronized (this) {
+            init();
+            return lookup(canonicalize(charsetName));
+        }
+    }
+
+    public final Iterator<Charset> charsets() {
+
+        final ArrayList<String> ks;
+        synchronized (this) {
+            init();
+            ks = new ArrayList<>(classMap.keySet());
+        }
+
+        return new Iterator<Charset>() {
+                Iterator<String> i = ks.iterator();
+
+                public boolean hasNext() {
+                    return i.hasNext();
+                }
+
+                public Charset next() {
+                    String csn = i.next();
+                    synchronized (AbstractCharsetProvider.this) {
+                        return lookup(csn);
+                    }
+                }
+
+                public void remove() {
+                    throw new UnsupportedOperationException();
+                }
+            };
+    }
+
+    public final String[] aliases(String charsetName) {
+        synchronized (this) {
+            init();
+            return aliasNameMap.get(charsetName);
+        }
+    }
+
+}
--- a/jdk/src/jdk.charsets/share/classes/sun/nio/cs/ext/ExtendedCharsets.java.template	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/jdk.charsets/share/classes/sun/nio/cs/ext/ExtendedCharsets.java.template	Wed Jul 05 20:37:09 2017 +0200
@@ -32,10 +32,8 @@
 import java.lang.ref.SoftReference;
 import java.nio.charset.Charset;
 import java.nio.charset.spi.CharsetProvider;
-import sun.nio.cs.AbstractCharsetProvider;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
-import sun.nio.cs.AbstractCharsetProvider;
 
 /**
  * Provider for extended charsets.
--- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeGCMCipher.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeGCMCipher.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -125,9 +125,7 @@
             if (ibuffer != null) {
                 result += ibuffer.size();
             }
-            if (isDoFinal) {
-                result -= tagLen/8;
-            }
+            result -= tagLen/8;
         }
         if (result < 0) {
             result = 0;
--- a/jdk/test/ProblemList.txt	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/ProblemList.txt	Wed Jul 05 20:37:09 2017 +0200
@@ -222,8 +222,7 @@
 sun/security/pkcs11/ec/TestKeyFactory.java                      generic-all
 
 # 7164518: no PortUnreachableException on Mac
-# 8051952: Unreachable.java test failing on Windows
-sun/security/krb5/auto/Unreachable.java                         windows-all,macosx-all
+sun/security/krb5/auto/Unreachable.java                         macosx-all
 
 # 8058849
 sun/security/krb5/config/dns.sh                                 generic-all
--- a/jdk/test/TEST.ROOT	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/TEST.ROOT	Wed Jul 05 20:37:09 2017 +0200
@@ -12,7 +12,7 @@
 keys=2d dnd i18n intermittent randomness
 
 # Tests that must run in othervm mode
-othervm.dirs=java/awt java/beans javax/accessibility javax/imageio javax/sound javax/print javax/management com/sun/awt sun/awt sun/java2d sun/pisces javax/xml/jaxp/testng/validation
+othervm.dirs=java/awt java/beans javax/accessibility javax/imageio javax/sound javax/print javax/management com/sun/awt sun/awt sun/java2d sun/pisces javax/xml/jaxp/testng/validation java/lang/ProcessHandle
 
 # Tests that cannot run concurrently
 exclusiveAccess.dirs=java/rmi/Naming java/util/prefs sun/management/jmxremote sun/tools/jstatd sun/security/mscapi java/util/stream javax/rmi
--- a/jdk/test/com/sun/jdi/AllLineLocations.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/com/sun/jdi/AllLineLocations.java	Wed Jul 05 20:37:09 2017 +0200
@@ -27,7 +27,6 @@
  *  @summary Test ReferenceType.allLineLocations
  *  @author Gordon Hirsch
  *
- *  @library scaffold
  *  @modules jdk.jdi
  *  @run build JDIScaffold VMConnection
  *  @run compile -g RefTypes.java
--- a/jdk/test/com/sun/jdi/ClassesByName.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/com/sun/jdi/ClassesByName.java	Wed Jul 05 20:37:09 2017 +0200
@@ -26,7 +26,6 @@
  *  @bug 4287992
  *  @author Robert Field
  *
- *  @library scaffold
  *  @modules jdk.jdi
  *  @run build JDIScaffold VMConnection
  *  @run compile -g HelloWorld.java
--- a/jdk/test/com/sun/jdi/ExceptionEvents.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/com/sun/jdi/ExceptionEvents.java	Wed Jul 05 20:37:09 2017 +0200
@@ -28,7 +28,6 @@
  *
  *  @author Robert Field
  *
- *  @library scaffold
  *  @modules jdk.jdi
  *  @run build TestScaffold VMConnection
  *  @run compile -g ExceptionEvents.java
--- a/jdk/test/com/sun/jdi/FilterMatch.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/com/sun/jdi/FilterMatch.java	Wed Jul 05 20:37:09 2017 +0200
@@ -28,7 +28,6 @@
  *
  *  @author Robert Field/Jim Holmlund
  *
- *  @library scaffold
  *  @modules jdk.jdi
  *  @run build JDIScaffold VMConnection
  *  @run compile -g HelloWorld.java
--- a/jdk/test/com/sun/jdi/FilterNoMatch.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/com/sun/jdi/FilterNoMatch.java	Wed Jul 05 20:37:09 2017 +0200
@@ -28,7 +28,6 @@
  *
  *  @author Robert Field/Jim Holmlund
  *
- *  @library scaffold
  *  @modules jdk.jdi
  *  @run build JDIScaffold VMConnection
  *  @run compile -g HelloWorld.java
--- a/jdk/test/com/sun/jdi/LaunchCommandLine.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/com/sun/jdi/LaunchCommandLine.java	Wed Jul 05 20:37:09 2017 +0200
@@ -27,7 +27,6 @@
  *  @summary Test launcher command line construction
  *  @author Gordon Hirsch
  *
- *  @library scaffold
  *  @modules jdk.jdi
  *  @run build JDIScaffold VMConnection
  *  @run compile -g HelloWorld.java
--- a/jdk/test/com/sun/jdi/ModificationWatchpoints.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/com/sun/jdi/ModificationWatchpoints.java	Wed Jul 05 20:37:09 2017 +0200
@@ -29,7 +29,6 @@
  *  @author Daniel Prusa (or someone in the FFJ group)
  *  @author Robert Field (modified to JDIScaffold)
  *
- *  @library scaffold
  *  @modules jdk.jdi
  *  @run build JDIScaffold VMConnection
  *  @run compile -g ModificationWatchpoints.java
--- a/jdk/test/com/sun/jdi/NativeInstanceFilter.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/com/sun/jdi/NativeInstanceFilter.java	Wed Jul 05 20:37:09 2017 +0200
@@ -28,7 +28,6 @@
  *
  *  @author Keith McGuigan
  *
- *  @library scaffold
  *  @modules jdk.jdi
  *  @run build JDIScaffold VMConnection
  *  @compile -XDignore.symbol.file NativeInstanceFilterTarg.java
--- a/jdk/test/com/sun/jdi/UnpreparedByName.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/com/sun/jdi/UnpreparedByName.java	Wed Jul 05 20:37:09 2017 +0200
@@ -28,7 +28,6 @@
  *  won't be returned by classesByName.
  *  @author Robert Field
  *
- *  @library scaffold
  *  @modules jdk.jdi
  *  @run build JDIScaffold VMConnection
  *  @run compile -g InnerTarg.java
--- a/jdk/test/com/sun/jdi/UnpreparedClasses.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/com/sun/jdi/UnpreparedClasses.java	Wed Jul 05 20:37:09 2017 +0200
@@ -28,7 +28,6 @@
  *  loaded class list are prepared classes.
  *  @author Robert Field
  *
- *  @library scaffold
  *  @modules jdk.jdi
  *  @run build JDIScaffold VMConnection
  *  @run compile -g InnerTarg.java
--- a/jdk/test/com/sun/jdi/Vars.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/com/sun/jdi/Vars.java	Wed Jul 05 20:37:09 2017 +0200
@@ -27,7 +27,6 @@
  *
  *  @author Robert Field
  *
- *  @library scaffold
  *  @modules jdk.jdi
  *  @run build JDIScaffold VMConnection
  *  @run compile -g Vars.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Component/SetEnabledPerformance/SetEnabledPerformance.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.Robot;
+
+import javax.swing.JButton;
+import javax.swing.SwingUtilities;
+
+/**
+ * @test
+ * @bug 8071306
+ * @author Sergey Bylokhov
+ */
+public final class SetEnabledPerformance {
+
+    private static Frame frame;
+
+    private static void createAndShowGUI() {
+        frame = new Frame();
+        frame.setLayout(new FlowLayout(FlowLayout.CENTER, 25, 0));
+        frame.setSize(600, 600);
+        frame.setLocationRelativeTo(null);
+        for (int i = 1; i < 10001; ++i) {
+            frame.add(new JButton("Button " + i));
+        }
+        frame.setVisible(true);
+    }
+
+    public static void main(final String[] args) throws Exception {
+        SwingUtilities.invokeAndWait(() -> createAndShowGUI());
+        final Robot robot = new Robot();
+        robot.waitForIdle();
+        robot.mouseMove(frame.getX() + 15, frame.getY() + 300);
+        robot.waitForIdle();
+        SwingUtilities.invokeAndWait(() -> {
+            long m = System.currentTimeMillis();
+            for (final Component comp : frame.getComponents()) {
+                comp.setEnabled(false);
+            }
+            m = System.currentTimeMillis() - m;
+            System.err.println("Disabled in " + m + " ms");
+            frame.dispose();
+            // we should be much faster, but leaves 1000 for the slow systems
+            if (m > 1000) {
+                throw new RuntimeException("Too slow");
+            }
+        });
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/EventQueue/6980209/bug6980209.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+   @bug 6980209
+   @summary Make tracking SecondaryLoop.enter/exit methods easier
+   @author Semyon Sadetsky
+  */
+
+import sun.util.logging.PlatformLogger;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+
+public class bug6980209 implements ActionListener {
+    private final static PlatformLogger log =
+            PlatformLogger.getLogger("java.awt.event.WaitDispatchSupport");
+    public static final int ATTEMPTS = 100;
+    public static final int EVENTS = 5;
+
+    private static boolean runInEDT;
+    private static JFrame frame;
+    private static int disorderCounter = 0;
+    private static Boolean enterReturn;
+    private static Boolean exitReturn;
+    private static int dispatchedEvents;
+
+    public static void main(String[] args) throws Exception {
+        System.out.println(
+                "PLEASE DO NOT TOUCH KEYBOARD AND MOUSE DURING THE TEST RUN!");
+        // log.setLevel(PlatformLogger.Level.FINE);
+        // log.setLevel(PlatformLogger.Level.FINEST);
+        try {
+            SwingUtilities.invokeAndWait(new Runnable() {
+                public void run() {
+                    frame = new JFrame();
+                    frame.setUndecorated(true);
+                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+                    setup(frame);
+                }
+            });
+            testExitBeforeEnter();
+            System.out.println("Run random test in EDT");
+            runInEDT = true;
+            testRandomly();
+            System.out.println("Run random test in another thread");
+            runInEDT = false;
+            testRandomly();
+            System.out.println("ok");
+
+        } finally {
+            SwingUtilities.invokeAndWait(new Runnable() {
+                @Override
+                public void run() {
+                    frame.dispose();
+                }
+            });
+        }
+    }
+
+    private static void testExitBeforeEnter() throws Exception {
+        final SecondaryLoop loop =
+                Toolkit.getDefaultToolkit().getSystemEventQueue()
+                        .createSecondaryLoop();
+        loop.exit();
+        Robot robot = new Robot();
+        robot.mouseWheel(1);
+        robot.waitForIdle();
+        SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                if(loop.enter()) {
+                    throw new RuntimeException("Wrong enter() return value");
+                }
+            }
+        });
+    }
+
+    private static void testRandomly() throws AWTException {
+        disorderCounter = 0;
+        final Robot robot = new Robot();
+        for (int i = 0; i < ATTEMPTS; i++) {
+            enterReturn = null;
+            exitReturn = null;
+            dispatchedEvents = 0;
+            synchronized (bug6980209.class) {
+                try {
+                    for (int j = 0; j < EVENTS; j++) {
+                        robot.keyPress(KeyEvent.VK_1);
+                        robot.keyRelease(KeyEvent.VK_1);
+                    }
+
+                    // trigger the button action that starts secondary loop
+                    robot.keyPress(KeyEvent.VK_SPACE);
+                    robot.keyRelease(KeyEvent.VK_SPACE);
+
+                    for (int j = 0; j < EVENTS; j++) {
+                        robot.keyPress(KeyEvent.VK_1);
+                        robot.keyRelease(KeyEvent.VK_1);
+                    }
+                    long time = System.nanoTime();
+                    // wait for enter() returns
+                    bug6980209.class.wait(1000);
+                    if (enterReturn == null) {
+                        System.out.println("wait time=" +
+                                ((System.nanoTime() - time) / 1E9) +
+                                " seconds");
+                        throw new RuntimeException(
+                                "It seems the secondary loop will never end");
+                    }
+                    if (!enterReturn) disorderCounter++;
+
+                    robot.waitForIdle();
+                    if (dispatchedEvents <
+                            2 * EVENTS) { //check that all events are dispatched
+                        throw new RuntimeException(
+                                "KeyEvent.VK_1 has been lost!");
+                    }
+
+                } catch (InterruptedException e) {
+                    throw new RuntimeException("Interrupted!");
+                }
+            }
+        }
+        if (disorderCounter == 0) {
+            System.out.println(
+                    "Zero disordered enter/exit caught. It is recommended to run scenario again");
+        } else {
+            System.out.println(
+                    "Disordered calls is " + disorderCounter + " from " +
+                            ATTEMPTS);
+        }
+    }
+
+    private static void setup(final JFrame frame) {
+        JButton jButton = new JButton("Button");
+        frame.getContentPane().add(jButton);
+        jButton.addActionListener(new bug6980209());
+        frame.pack();
+        frame.setVisible(true);
+        jButton.setFocusable(true);
+        jButton.requestFocus();
+        jButton.addKeyListener(new KeyListener() {
+            @Override
+            public void keyTyped(KeyEvent e) {
+            }
+
+            @Override
+            public void keyPressed(KeyEvent e) {
+                if (e.getKeyChar() == '1') dispatchedEvents++;
+            }
+
+            @Override
+            public void keyReleased(KeyEvent e) {
+                if (e.getKeyChar() == '1') dispatchedEvents++;
+            }
+        });
+    }
+
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        if (runInEDT) {
+            runSecondaryLoop();
+            return;
+        }
+        new Thread("Secondary loop run thread") {
+            @Override
+            public void run() {
+                runSecondaryLoop();
+            }
+        }.start();
+    }
+
+    private static void runSecondaryLoop() {
+        log.fine("\n---TEST START---");
+
+        final SecondaryLoop loop =
+                Toolkit.getDefaultToolkit().getSystemEventQueue()
+                        .createSecondaryLoop();
+
+        final Object LOCK = new Object(); //lock to start simultaneously
+        Thread exitThread = new Thread("Exit thread") {
+            @Override
+            public void run() {
+                synchronized (LOCK) {
+                    LOCK.notify();
+                }
+                Thread.yield();
+                exitReturn = loop.exit();
+                log.fine("exit() returns " + exitReturn);
+            }
+        };
+
+        synchronized (LOCK) {
+            try {
+                exitThread.start();
+                LOCK.wait();
+            } catch (InterruptedException e1) {
+                throw new RuntimeException("What?");
+            }
+        }
+
+        enterReturn = loop.enter();
+        log.fine("enter() returns " + enterReturn);
+
+        try {
+            exitThread.join();
+        } catch (InterruptedException e) {
+            throw new RuntimeException("What?");
+        }
+        synchronized (bug6980209.class) {
+            bug6980209.class.notifyAll();
+        }
+        log.fine("\n---TEST END---");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/FileDialog/8003399/bug8003399.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+   @bug 8003399
+   @summary JFileChooser gives wrong path to selected file when saving to Libraries folder on Windows 7
+   @author Semyon Sadetsky
+   @library /lib/testlibrary
+   @build jdk.testlibrary.OSInfo
+   @run main bug8003399
+  */
+
+import jdk.testlibrary.OSInfo;
+
+import javax.swing.filechooser.FileSystemView;
+import java.io.File;
+
+public class bug8003399 {
+
+    public static void main(String[] args) throws Exception {
+        if (OSInfo.getOSType() == OSInfo.OSType.WINDOWS &&
+                OSInfo.getWindowsVersion().compareTo(OSInfo.WINDOWS_VISTA) > 0 ) {
+            FileSystemView fsv = FileSystemView.getFileSystemView();
+            for (File file : fsv.getFiles(fsv.getHomeDirectory(), false)) {
+                if(file.isDirectory()) {
+                    for (File file1 : fsv.getFiles(file, false)) {
+                        if(file1.isDirectory())
+                        {
+                            String path = file1.getPath();
+                            if(path.startsWith("::{") &&
+                                    path.toLowerCase().endsWith(".library-ms")) {
+                                throw new RuntimeException("Unconverted library link found");
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        System.out.println("ok");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Frame/MaximizedToUnmaximized/MaximizedToUnmaximized.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.awt.Frame;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsEnvironment;
+import java.awt.Insets;
+import java.awt.Rectangle;
+import java.awt.Robot;
+import java.awt.Toolkit;
+
+/**
+ * @test
+ * @bug 8065739
+ * @summary [macosx] Frame warps to lower left of screen when displayed
+ * @author Alexandr Scherbatiy
+ */
+public class MaximizedToUnmaximized {
+
+    public static void main(String[] args) throws Exception {
+        testFrame(false);
+        testFrame(true);
+    }
+
+    static void testFrame(boolean isUndecorated) throws Exception {
+        Frame frame = new Frame();
+        try {
+            Robot robot = new Robot();
+            robot.setAutoDelay(100);
+
+            frame.setUndecorated(isUndecorated);
+            GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment()
+                    .getDefaultScreenDevice().getDefaultConfiguration();
+            Rectangle bounds = gc.getBounds();
+            Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc);
+            int x = bounds.x + insets.left;
+            int y = bounds.y + insets.top;
+            int width = bounds.width - insets.left - insets.right;
+            int height = bounds.height - insets.top - insets.bottom;
+            Rectangle rect = new Rectangle(x, y, width, height);
+            frame.pack();
+            frame.setBounds(rect);
+            frame.setVisible(true);
+            robot.waitForIdle();
+            robot.delay(500);
+
+            if (frame.getWidth() <= width / 2
+                    || frame.getHeight() <= height / 2) {
+                throw new RuntimeException("Frame size is small!");
+            }
+
+            if (!isUndecorated && frame.getExtendedState() != Frame.MAXIMIZED_BOTH) {
+                throw new RuntimeException("Frame state does not equal"
+                        + " MAXIMIZED_BOTH!");
+            }
+        } finally {
+            frame.dispose();
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Frame/SetMaximizedBounds/MaximizedMovedWindow.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.awt.*;
+
+/*
+ * @test
+ * @bug 8065739
+ * @summary Moved window is maximazed to new screen
+ * @author Alexandr Scherbatiy
+ *
+ * @run main MaximizedMovedWindow
+ */
+public class MaximizedMovedWindow {
+
+    public static void main(String[] args) throws Exception {
+
+        //Supported platforms are Windows and OS X.
+        String os = System.getProperty("os.name").toLowerCase();
+        if (!os.contains("os x")) {
+            return;
+        }
+
+        if (!Toolkit.getDefaultToolkit().
+                isFrameStateSupported(Frame.MAXIMIZED_BOTH)) {
+            return;
+        }
+
+        GraphicsEnvironment ge = GraphicsEnvironment.
+                getLocalGraphicsEnvironment();
+
+        if (ge.isHeadlessInstance()) {
+            return;
+        }
+
+        GraphicsDevice[] devices = ge.getScreenDevices();
+
+        if (devices.length < 2) {
+            return;
+        }
+
+        Frame frame = null;
+        try {
+
+            GraphicsConfiguration gc1 = devices[0].getDefaultConfiguration();
+            GraphicsConfiguration gc2 = devices[1].getDefaultConfiguration();
+
+            Robot robot = new Robot();
+            robot.setAutoDelay(50);
+
+            frame = new Frame();
+            Rectangle maxArea1 = getMaximizedScreenArea(gc1);
+            frame.setBounds(getSmallerRectangle(maxArea1));
+            frame.setVisible(true);
+            robot.waitForIdle();
+
+            frame.setExtendedState(Frame.MAXIMIZED_BOTH);
+            robot.waitForIdle();
+            robot.delay(1000);
+
+            Rectangle bounds = frame.getBounds();
+            if (!bounds.equals(maxArea1)) {
+                throw new RuntimeException("The bounds of the Frame do not equal"
+                        + " to screen 1 size");
+            }
+
+            frame.setExtendedState(Frame.NORMAL);
+            robot.waitForIdle();
+            robot.delay(1000);
+
+            Rectangle maxArea2 = getMaximizedScreenArea(gc2);
+            frame.setBounds(getSmallerRectangle(maxArea2));
+            robot.waitForIdle();
+            robot.delay(1000);
+
+            frame.setExtendedState(Frame.MAXIMIZED_BOTH);
+            robot.waitForIdle();
+            robot.delay(1000);
+
+            bounds = frame.getBounds();
+            if (!bounds.equals(maxArea2)) {
+                throw new RuntimeException("The bounds of the Frame do not equal"
+                        + " to screen 2 size");
+            }
+        } finally {
+            if (frame != null) {
+                frame.dispose();
+            }
+        }
+    }
+
+    static Rectangle getSmallerRectangle(Rectangle rect) {
+        return new Rectangle(
+                rect.x + rect.width / 6,
+                rect.y + rect.height / 6,
+                rect.width / 3,
+                rect.height / 3);
+    }
+    static Rectangle getMaximizedScreenArea(GraphicsConfiguration gc) {
+        Rectangle bounds = gc.getBounds();
+        Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc);
+        return new Rectangle(
+                bounds.x + insets.left,
+                bounds.y + insets.top,
+                bounds.width - insets.left - insets.right,
+                bounds.height - insets.top - insets.bottom);
+    }
+}
--- a/jdk/test/java/awt/Frame/SetMaximizedBounds/SetMaximizedBounds.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/java/awt/Frame/SetMaximizedBounds/SetMaximizedBounds.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,67 +22,108 @@
  */
 
 import java.awt.*;
-
 /*
  * @test
  * @summary When Frame.setExtendedState(Frame.MAXIMIZED_BOTH)
  *          is called for a Frame after been called setMaximizedBounds() with
  *          certain value, Frame bounds must equal to this value.
  *
- * @library ../../../../lib/testlibrary
- * @build ExtendedRobot
  * @run main SetMaximizedBounds
  */
 
 public class SetMaximizedBounds {
 
-    Frame frame;
-    Rectangle bound;
-    boolean supported;
-    ExtendedRobot robot;
-    static Rectangle max = new Rectangle(100,100,400,400);
+    public static void main(String[] args) throws Exception {
+
+        //Supported platforms are Windows and OS X.
+        String os = System.getProperty("os.name").toLowerCase();
+        if (!os.contains("windows") && !os.contains("os x")) {
+            return;
+        }
+
+        if (!Toolkit.getDefaultToolkit().
+                isFrameStateSupported(Frame.MAXIMIZED_BOTH)) {
+            return;
+        }
 
-    public void doTest() throws Exception {
-        robot = new ExtendedRobot();
+        GraphicsEnvironment ge = GraphicsEnvironment.
+                getLocalGraphicsEnvironment();
+
+        if (ge.isHeadlessInstance()) {
+            return;
+        }
+
+        for (GraphicsDevice gd : ge.getScreenDevices()) {
+            for (GraphicsConfiguration gc : gd.getConfigurations()) {
+                testMaximizedBounds(gc);
+            }
+        }
+    }
 
-        EventQueue.invokeAndWait( () -> {
-            frame = new Frame( "TestFrame ");
-            frame.setLayout(new FlowLayout());
+    static void testMaximizedBounds(GraphicsConfiguration gc) throws Exception {
+
+        Frame frame = null;
+        try {
+
+            Rectangle maxArea = getMaximizedScreenArea(gc);
+
+            Robot robot = new Robot();
+            robot.setAutoDelay(50);
 
-            if (Toolkit.getDefaultToolkit().isFrameStateSupported(Frame.MAXIMIZED_BOTH)) {
-                supported = true;
-                frame.setMaximizedBounds(max);
-            } else {
-                supported = false;
+            frame = new Frame();
+            Rectangle maximizedBounds = new Rectangle(
+                    maxArea.x + maxArea.width / 6,
+                    maxArea.y + maxArea.height / 6,
+                    maxArea.width / 3,
+                    maxArea.height / 3);
+            frame.setMaximizedBounds(maximizedBounds);
+            frame.setSize(maxArea.width / 8, maxArea.height / 8);
+            frame.setVisible(true);
+            robot.waitForIdle();
+
+            frame.setExtendedState(Frame.MAXIMIZED_BOTH);
+            robot.waitForIdle();
+            robot.delay(1000);
+
+            Rectangle bounds = frame.getBounds();
+            if (!bounds.equals(maximizedBounds)) {
+                throw new RuntimeException("The bounds of the Frame do not equal to what"
+                        + " is specified when the frame is in Frame.MAXIMIZED_BOTH state");
             }
 
-            frame.setSize(200, 200);
-            frame.setVisible(true);
-        });
+            frame.setExtendedState(Frame.NORMAL);
+            robot.waitForIdle();
+            robot.delay(1000);
 
-        robot.waitForIdle(2000);
-        if (supported) {
-            EventQueue.invokeAndWait( () -> {
-                frame.setExtendedState(Frame.MAXIMIZED_BOTH);
-            });
-            robot.waitForIdle(2000);
-            bound = frame.getBounds();
-            if(!bound.equals(max))
+            maximizedBounds = new Rectangle(
+                    maxArea.x + maxArea.width / 10,
+                    maxArea.y + maxArea.height / 10,
+                    maxArea.width / 5,
+                    maxArea.height / 5);
+            frame.setMaximizedBounds(maximizedBounds);
+            frame.setExtendedState(Frame.MAXIMIZED_BOTH);
+            robot.waitForIdle();
+            robot.delay(1000);
+
+            bounds = frame.getBounds();
+            if (!bounds.equals(maximizedBounds)) {
                 throw new RuntimeException("The bounds of the Frame do not equal to what"
-                    + " is specified when the frame is in Frame.MAXIMIZED_BOTH state");
-        } else {
-            System.out.println("Frame.MAXIMIZED_BOTH not supported");
+                        + " is specified when the frame is in Frame.MAXIMIZED_BOTH state");
+            }
+        } finally {
+            if (frame != null) {
+                frame.dispose();
+            }
         }
-
-        frame.dispose();
     }
 
-    public static void main(String[] args) throws Exception {
-        String os = System.getProperty("os.name").toLowerCase();
-        System.out.println(os);
-        if (os.contains("windows") || os.contains("os x"))
-            new SetMaximizedBounds().doTest();
-        else
-            System.out.println("Platform "+os+" is not supported. Supported platforms are Windows and OS X.");
+    static Rectangle getMaximizedScreenArea(GraphicsConfiguration gc) {
+        Rectangle bounds = gc.getBounds();
+        Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc);
+        return new Rectangle(
+                bounds.x + insets.left,
+                bounds.y + insets.top,
+                bounds.width - insets.left - insets.right,
+                bounds.height - insets.top - insets.bottom);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Mouse/MouseDragEvent/MouseDraggedTest.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+/*
+ * @test
+ * @bug 8080137
+ * @summary Dragged events for extra mouse buttons (4,5,6) are not generated
+ *            on JSplitPane
+ * @author alexandr.scherbatiy area=awt.event
+ * @run main MouseDraggedTest
+ */
+public class MouseDraggedTest {
+
+    private static JFrame frame;
+    private static Rectangle frameBounds;
+    private static volatile boolean mouseDragged;
+
+    public static void main(String[] args) throws Exception {
+        try {
+            Robot robot = new Robot();
+            robot.setAutoDelay(50);
+
+            SwingUtilities.invokeAndWait(MouseDraggedTest::createAndShowGUI);
+            robot.waitForIdle();
+
+            SwingUtilities.invokeAndWait(() -> frameBounds = frame.getBounds());
+            robot.waitForIdle();
+
+            for (int i = 1; i <= MouseInfo.getNumberOfButtons(); i++) {
+                testMouseDrag(i, robot);
+            }
+        } finally {
+            SwingUtilities.invokeLater(() -> {
+                if (frame != null) {
+                    frame.dispose();
+                }
+            });
+        }
+    }
+
+    private static void testMouseDrag(int button, Robot robot) {
+
+        mouseDragged = false;
+        int x1 = frameBounds.x + frameBounds.width / 4;
+        int y1 = frameBounds.y + frameBounds.height / 4;
+        int x2 = frameBounds.x + frameBounds.width / 2;
+        int y2 = frameBounds.y + frameBounds.height / 2;
+
+        robot.mouseMove(x1, y1);
+        robot.waitForIdle();
+
+        int buttonMask = InputEvent.getMaskForButton(button);
+        robot.mousePress(buttonMask);
+        robot.mouseMove(x2, y2);
+        robot.mouseRelease(buttonMask);
+        robot.waitForIdle();
+
+        if (!mouseDragged) {
+            throw new RuntimeException("Mouse button " + button
+                    + " is not dragged");
+        }
+    }
+
+    static void createAndShowGUI() {
+
+        frame = new JFrame();
+        frame.setSize(400, 400);
+        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        JPanel panel = new JPanel(new BorderLayout());
+        panel.addMouseMotionListener(new MouseAdapter() {
+
+            @Override
+            public void mouseDragged(MouseEvent e) {
+                mouseDragged = true;
+            }
+        });
+        frame.add(panel, BorderLayout.CENTER);
+        frame.setVisible(true);
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/MouseInfo/GetPointerInfoTest.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+  @test
+  @summary unit test for getPointerInfo() from MouseInfo class
+  @author dav@sparc.spb.su: area=
+  @bug 4009555
+  @run main GetPointerInfoTest
+*/
+
+import java.awt.*;
+
+/**
+ * Simply check the result on non-null and results are correct.
+ */
+public class GetPointerInfoTest {
+    private static final String successStage = "Test stage completed.Passed.";
+
+    public static void main(String[] args) throws Exception {
+        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+        GraphicsDevice[] gds = ge.getScreenDevices();
+        int gdslen = gds.length;
+        System.out.println("There are " + gdslen + " Graphics Devices");
+        if (gdslen == 0) {
+            System.out.println("Nothing to be done.");
+            return;
+        }
+        Robot robot = new Robot(gds[0]);
+        robot.setAutoDelay(0);
+        robot.setAutoWaitForIdle(true);
+        robot.delay(10);
+        robot.waitForIdle();
+        Point p = new Point(101, 99);
+        robot.mouseMove(p.x, p.y);
+
+        PointerInfo pi = MouseInfo.getPointerInfo();
+        if (pi == null) {
+            throw new RuntimeException("Test failed. getPointerInfo() returned null value.");
+        } else {
+            System.out.println(successStage);
+        }
+        Point piLocation = pi.getLocation();
+
+        if (piLocation.x != p.x || piLocation.y != p.y) {
+            throw new RuntimeException("Test failed.getPointerInfo() returned incorrect result.");
+        } else {
+            System.out.println(successStage);
+        }
+
+        System.out.println("Test PASSED.");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/MouseInfo/MultiscreenPointerInfo.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+  @test
+  @summary unit test for getPointerInfo() from MouseInfo class
+  @author prs@sparc.spb.su: area=
+  @bug 4009555
+  @run main MultiscreenPointerInfo
+*/
+
+import java.awt.*;
+
+/**
+ * Simply check the result on non-null and results are correct.
+ */
+public class MultiscreenPointerInfo
+{
+    private static final String successStage = "Test stage completed.Passed.";
+
+    public static void main(String[] args) throws Exception {
+        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+        GraphicsDevice[] gds = ge.getScreenDevices();
+        int gdslen = gds.length;
+        System.out.println("There are " + gdslen + " Graphics Devices");
+        if (gdslen < 2) {
+            System.out.println("Nothing to be done. PASSED automatically.");
+            return;
+        }
+        Rectangle rx = gds[1].getDefaultConfiguration().getBounds();
+        Robot robot;
+
+        if (rx.x == 0 && rx.y == 0) {
+            // Assuming independent graphics devices
+            robot = new Robot(gds[1]);
+        } else {
+            // Means we have a virtual device
+            robot = new Robot(gds[0]);
+        }
+        robot.setAutoDelay(0);
+        robot.setAutoWaitForIdle(true);
+        robot.delay(10);
+        robot.waitForIdle();
+        Point p = new Point(rx.x + 101, rx.y + 99);
+        robot.mouseMove(p.x, p.y);
+        PointerInfo pi = MouseInfo.getPointerInfo();
+        if (pi == null) {
+            throw new RuntimeException("Test failed. getPointerInfo() returned null value.");
+        } else {
+            System.out.println(successStage);
+        }
+
+        Point piLocation = pi.getLocation();
+
+        if (piLocation.x != p.x || piLocation.y != p.y) {
+            throw new RuntimeException("Test failed.getPointerInfo() returned incorrect location.");
+        } else {
+            System.out.println(successStage);
+        }
+
+        GraphicsDevice dev = pi.getDevice();
+
+        if (dev != gds[1]) {
+            throw new RuntimeException("Test failed.getPointerInfo() returned incorrect device.");
+        } else {
+            System.out.println(successStage);
+        }
+        System.out.println("Test PASSED.");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Robot/RobotWheelTest/RobotWheelTest.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.awt.Button;
+import java.awt.Frame;
+import java.awt.Rectangle;
+import java.awt.Robot;
+import jdk.testlibrary.OSInfo;
+
+/*
+ * @test 1.2 98/08/05
+ * @bug 4373478 8079255
+ * @summary Test mouse wheel functionality of Robot
+ * @author bchristi: area=Robot
+ * @library ../../../../lib/testlibrary
+ * @build jdk.testlibrary.OSInfo
+ * @run main RobotWheelTest
+ */
+public class RobotWheelTest {
+
+    private static final int NUMTESTS = 20;
+    private static volatile int wheelRotation;
+
+    public static void main(String[] args) throws Exception {
+
+        Frame frame = null;
+        try {
+            int wheelSign = OSInfo.getOSType().equals(OSInfo.OSType.MACOSX) ? -1 : 1;
+
+            frame = new Frame();
+            frame.setSize(200, 200);
+            Button button = new Button("WheelButton");
+            button.addMouseWheelListener(e -> wheelRotation = e.getWheelRotation());
+            frame.add(button);
+            frame.setVisible(true);
+
+            Robot robot = new Robot();
+            robot.setAutoDelay(100);
+            robot.waitForIdle();
+
+            Rectangle bounds = frame.getBounds();
+            int centerX = bounds.x + bounds.width / 2;
+            int centerY = bounds.y + bounds.height / 2;
+            robot.mouseMove(centerX, centerY);
+            robot.waitForIdle();
+
+            for (int i = -NUMTESTS; i <= NUMTESTS; i++) {
+                if (i == 0) {
+                    continue;
+                }
+                robot.mouseWheel(i);
+                robot.waitForIdle();
+                if (i != wheelSign * wheelRotation) {
+                    throw new RuntimeException("wheelRotation = " + wheelRotation
+                            + ", expected value = " + i);
+                }
+            }
+        } finally {
+            if (frame != null) {
+                frame.dispose();
+            }
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Scrollbar/ScrollbarMouseWheelTest/ScrollbarMouseWheelTest.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.awt.*;
+import java.awt.event.*;
+
+/**
+ * @test
+ * @bug 4449139
+ * @summary test MouseWheelEvent generation by Scrollbar component
+ */
+public final class ScrollbarMouseWheelTest
+        implements MouseWheelListener, WindowListener {
+
+    final static String tk = Toolkit.getDefaultToolkit().getClass().getName();
+    final static int REPS = 5;
+    // There is a bug on Windows: 4616935.
+    // Wheel events comes to every component in the hierarchy so we should
+    // check a platform.
+    // There are two scrollbars within one Panel and both accept 5 clicks, so
+    // Panel would accept 5*2 clicks on Windows.
+    final static int PANEL_REPS = tk.equals("sun.awt.windows.WToolkit")? REPS * 2: REPS;
+
+    Scrollbar sb1;
+    Scrollbar sb2;
+    Panel pnl;
+    class Sema {
+        boolean flag;
+        boolean getVal() { return flag;}
+        void setVal(boolean b) { flag = b;}
+    }
+    Sema sema = new Sema();
+
+    Robot robot;
+
+    int sb1upevents, sb2upevents, pnlupevents;
+    int sb1downevents, sb2downevents, pnldownevents;
+
+    public static void main(final String[] args) {
+        new ScrollbarMouseWheelTest().test();
+    }
+
+    public void test() {
+        // Move mouse to upper-right area
+        try {
+            robot = new Robot();
+        } catch (AWTException e) {
+            System.out.println("Problem creating Robot.  FAIL.");
+            throw new RuntimeException("Problem creating Robot.  FAIL.");
+
+        }
+
+        robot.setAutoDelay(500);
+        robot.setAutoWaitForIdle(true);
+
+        // Show test Frame
+        Frame frame = new Frame("ScrollbarMouseWheelTest");
+        frame.addWindowListener(this);
+        pnl = new Panel();
+        pnl.setLayout(new GridLayout(1, 2));
+        pnl.addMouseWheelListener(this);
+        sb1 = new Scrollbar();
+        sb1.addMouseWheelListener(this);
+        pnl.add(sb1);
+        sb2 = new Scrollbar();
+        pnl.add(sb2);
+        frame.add(pnl);
+        frame.setSize(200, 400);
+        frame.setLocationRelativeTo(null);
+        frame.setVisible(true);
+        frame.toFront();
+
+        // When Frame is active, start testing (handled in windowActivated())
+        while (true) {
+            synchronized (sema) {
+                if (sema.getVal()) {
+                    break;
+                }
+            }
+        }
+        // up on sb1
+        testComp(sb1, true);
+        // down on sb1
+        testComp(sb1, false);
+        // up on sb2
+        testComp(sb2, true);
+        // down on sb2
+        testComp(sb2, false);
+        frame.dispose();
+        System.out.println("Test done.");
+        if (sb1upevents == REPS &&
+                sb2upevents == 0 &&
+                pnlupevents == PANEL_REPS &&
+                sb1downevents == REPS &&
+                sb2downevents == 0 &&
+                pnldownevents == PANEL_REPS) {
+            System.out.println("PASSED.");
+        } else {
+            System.out.println("Test Failed:" +
+                                       "\n\tsb1upevents =" + sb1upevents +
+                                       "\n\tsb2upevents = " + sb2upevents +
+                                       "\n\tpnlupevents = " + pnlupevents +
+                                       "\n\tsb1downevents =" + sb1downevents +
+                                       "\n\tsb2downevents = " + sb2downevents +
+                                       "\n\tpnldownevents = " + pnldownevents);
+            throw new RuntimeException("Test FAILED.");
+        }
+    }
+
+    public void testComp(Component comp, boolean up) {
+        Point loc = comp.getLocationOnScreen();
+        robot.mouseMove(loc.x + comp.getWidth() / 2,
+                        loc.y + comp.getHeight() / 2);
+        for (int loop = 0; loop < REPS; loop++) {
+            System.out.println("Robot.mouseWheel() on " + comp.getName());
+            robot.mouseWheel(up ? -1 : 1);
+        }
+    }
+
+    public void mouseWheelMoved(MouseWheelEvent mwe) {
+        Component src = mwe.getComponent();
+        System.out.println("mouseWheelMoved() on " + src.getName());
+        if (mwe.getWheelRotation() == -1) {
+            if (src == sb1) {
+                sb1upevents++;
+            } else if (src == sb2) {
+                sb2upevents++;
+            } else if (src == pnl) {
+                pnlupevents++;
+            } else {
+                System.out.println("weird source component");
+            }
+        } else if (mwe.getWheelRotation() == 1) {
+            if (src == sb1) {
+                sb1downevents++;
+            } else if (src == sb2) {
+                sb2downevents++;
+            } else if (src == pnl) {
+                pnldownevents++;
+            } else {
+                System.out.println("weird source component");
+            }
+        } else {
+            System.out.println("weird wheel rotation");
+        }
+    }
+
+    public void windowActivated(WindowEvent we) {
+        synchronized (sema) {
+            sema.setVal(true);
+        }
+    }
+
+    public void windowClosed(WindowEvent we) {}
+    public void windowClosing(WindowEvent we) {}
+    public void windowDeactivated(WindowEvent we) {}
+    public void windowDeiconified(WindowEvent we) {}
+    public void windowIconified(WindowEvent we) {}
+    public void windowOpened(WindowEvent we) {}
+}// class ScrollbarMouseWheelTest
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/font/OpenType/OpticalBoundsTagTest.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+import java.awt.font.OpenType;
+import java.io.IOException;
+
+/**
+  * @test
+  * @bug 8077584
+  * @summary Test for TAG_OPBD tag. Should be unique and not same as TAG_MORT.
+  * @run main OpticalBoundsTagTest
+  */
+
+public class OpticalBoundsTagTest {
+
+    public static void main(String[] a) throws Exception {
+
+        int tag_opbd = java.awt.font.OpenType.TAG_OPBD;
+        if (tag_opbd == java.awt.font.OpenType.TAG_MORT) {
+            System.out.println("Test failed: TAG_OPBD:" + tag_opbd);
+            throw new RuntimeException("TAG_OPBD same as TAG_MORT");
+        } else {
+            System.out.println("Test passed: TAG_OPBD: " + tag_opbd);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/InputStream/ReadAllBytes.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Random;
+import jdk.testlibrary.RandomFactory;
+
+/*
+ * @test
+ * @bug 8080835
+ * @library /lib/testlibrary
+ * @build jdk.testlibrary.*
+ * @run main ReadAllBytes
+ * @summary Basic test for InputStream.readAllBytes
+ * @key randomness
+ */
+
+public class ReadAllBytes {
+
+    private static Random generator = RandomFactory.getRandom();
+
+    public static void main(String[] args) throws IOException {
+        test(new byte[]{});
+        test(new byte[]{1, 2, 3});
+        test(createRandomBytes(1024));
+        test(createRandomBytes((1 << 13) - 1));
+        test(createRandomBytes((1 << 13)));
+        test(createRandomBytes((1 << 13) + 1));
+        test(createRandomBytes((1 << 15) - 1));
+        test(createRandomBytes((1 << 15)));
+        test(createRandomBytes((1 << 15) + 1));
+        test(createRandomBytes((1 << 17) - 1));
+        test(createRandomBytes((1 << 17)));
+        test(createRandomBytes((1 << 17) + 1));
+    }
+
+    static void test(byte[] expectedBytes) throws IOException {
+        int expectedLength = expectedBytes.length;
+        WrapperInputStream in = new WrapperInputStream(new ByteArrayInputStream(expectedBytes));
+        byte[] readBytes = in.readAllBytes();
+
+        int x;
+        byte[] tmp = new byte[10];
+        check((x = in.read()) == -1,
+              "Expected end of stream from read(), got " + x);
+        check((x = in.read(tmp)) == -1,
+              "Expected end of stream from read(byte[]), got " + x);
+        check((x = in.read(tmp, 0, tmp.length)) == -1,
+              "Expected end of stream from read(byte[], int, int), got " + x);
+        check(in.readAllBytes().length == 0,
+              "Expected readAllBytes to return empty byte array");
+        check(expectedLength == readBytes.length,
+              "Expected length " + expectedLength + ", got " + readBytes.length);
+        check(Arrays.equals(expectedBytes, readBytes),
+              "Expected[" + expectedBytes + "], got:[" + readBytes + "]");
+        check(!in.isClosed(), "Stream unexpectedly closed");
+    }
+
+    static byte[] createRandomBytes(int size) {
+        byte[] bytes = new byte[size];
+        generator.nextBytes(bytes);
+        return bytes;
+    }
+
+    static void check(boolean cond, Object ... failedArgs) {
+        if (cond)
+            return;
+        StringBuilder sb = new StringBuilder();
+        for (Object o : failedArgs)
+            sb.append(o);
+        throw new RuntimeException(sb.toString());
+    }
+
+    static class WrapperInputStream extends FilterInputStream {
+        private boolean closed;
+        WrapperInputStream(InputStream in) { super(in); }
+        @Override public void close() throws IOException { closed = true; in.close(); }
+        boolean isClosed() { return closed; }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/InputStream/ReadNBytes.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Random;
+import jdk.testlibrary.RandomFactory;
+
+/*
+ * @test
+ * @bug 8080835
+ * @library /lib/testlibrary
+ * @build jdk.testlibrary.*
+ * @run main ReadNBytes
+ * @summary Basic test for InputStream.readNBytes
+ * @key randomness
+ */
+
+public class ReadNBytes {
+
+    private static Random generator = RandomFactory.getRandom();
+
+    public static void main(String[] args) throws IOException {
+        test(new byte[]{1, 2, 3});
+        test(createRandomBytes(1024));
+        test(createRandomBytes((1 << 13) - 1));
+        test(createRandomBytes((1 << 13)));
+        test(createRandomBytes((1 << 13) + 1));
+        test(createRandomBytes((1 << 15) - 1));
+        test(createRandomBytes((1 << 15)));
+        test(createRandomBytes((1 << 15) + 1));
+        test(createRandomBytes((1 << 17) - 1));
+        test(createRandomBytes((1 << 17)));
+        test(createRandomBytes((1 << 17) + 1));
+    }
+
+    static void test(byte[] inputBytes) throws IOException {
+        int length = inputBytes.length;
+        WrapperInputStream in = new WrapperInputStream(new ByteArrayInputStream(inputBytes));
+        byte[] readBytes = new byte[(length / 2) + 1];
+        int nread = in.readNBytes(readBytes, 0, readBytes.length);
+
+        int x;
+        byte[] tmp;
+        check(nread == readBytes.length,
+              "Expected number of bytes read: " + readBytes.length + ", got: " + nread);
+        check(Arrays.equals((tmp = Arrays.copyOf(inputBytes, nread)), readBytes),
+              "Expected[" + tmp + "], got:[" + readBytes + "]");
+        check(!in.isClosed(), "Stream unexpectedly closed");
+
+        // Read again
+        nread = in.readNBytes(readBytes, 0, readBytes.length);
+
+        check(nread == length - readBytes.length,
+              "Expected number of bytes read: " + (length - readBytes.length) + ", got: " + nread);
+        check(Arrays.equals((tmp = Arrays.copyOfRange(inputBytes, readBytes.length, length)),
+                            Arrays.copyOf(readBytes, nread)),
+              "Expected[" + tmp + "], got:[" + readBytes + "]");
+        // Expect end of stream
+        check((x = in.read()) == -1,
+              "Expected end of stream from read(), got " + x);
+        check((x = in.read(tmp)) == -1,
+              "Expected end of stream from read(byte[]), got " + x);
+        check((x = in.read(tmp, 0, tmp.length)) == -1,
+              "Expected end of stream from read(byte[], int, int), got " + x);
+        check((x = in.readNBytes(tmp, 0, tmp.length)) == 0,
+              "Expected end of stream, 0, from readNBytes(byte[], int, int), got " + x);
+        check(!in.isClosed(), "Stream unexpectedly closed");
+    }
+
+    static byte[] createRandomBytes(int size) {
+        byte[] bytes = new byte[size];
+        generator.nextBytes(bytes);
+        return bytes;
+    }
+
+    static void check(boolean cond, Object ... failedArgs) {
+        if (cond)
+            return;
+        StringBuilder sb = new StringBuilder();
+        for (Object o : failedArgs)
+            sb.append(o);
+        throw new RuntimeException(sb.toString());
+    }
+
+
+    static class WrapperInputStream extends FilterInputStream {
+        private boolean closed;
+        WrapperInputStream(InputStream in) { super(in); }
+        @Override public void close() throws IOException { closed = true; in.close(); }
+        boolean isClosed() { return closed; }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/Serializable/failureAtomicity/Bar.template	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package $package;
+
+import java.io.IOException;
+import java.io.Serializable;
+import failureAtomicity.SerialRef;
+
+public class Bar extends Foo implements Serializable {
+    static final long serialVersionUID = -0L;
+
+    public final long barPrim;
+    public final String barRef;
+
+    public final SerialRef ref;  // So we can retrieve a reference to check
+    public $zebra_type zebraBar;   // ordered alphabetically, must be last
+
+    public Bar(int fooPrim, String fooRef, $foo_zebra_type fooZebra,
+               long barPrim, String barRef, $zebra_type zebra) {
+        super(fooPrim, fooRef, fooZebra);
+        this.barPrim = barPrim;
+        this.barRef = barRef;
+        this.zebraBar = zebra;
+        this.ref = new SerialRef(this);
+    }
+
+    @Override
+    public String toString() {
+        return new StringBuilder()
+                .append("$package.Bar[")
+                .append("barPrim:").append(barPrim)
+                .append(", barRef:").append(barRef)
+                .append(", zebraBar:").append(zebraBar)
+                .append(", " + super.toString())
+                .toString();
+    }
+
+//$has_readObject    private void readObject(java.io.ObjectInputStream in)
+//$has_readObject        throws IOException, ClassNotFoundException
+//$has_readObject    {
+//$has_readObject        in.defaultReadObject();
+//$has_readObject    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/Serializable/failureAtomicity/FailureAtomicity.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,421 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8071474
+ * @summary Better failure atomicity for default read object.
+ * @library /lib/testlibrary
+ * @build jdk.testlibrary.FileUtils
+ * @compile FailureAtomicity.java SerialRef.java
+ * @run main failureAtomicity.FailureAtomicity
+ */
+
+package failureAtomicity;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamClass;
+import java.io.UncheckedIOException;
+import java.lang.reflect.Constructor;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.BiConsumer;
+import java.util.stream.Collectors;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.StandardLocation;
+import javax.tools.ToolProvider;
+import jdk.testlibrary.FileUtils;
+
+@SuppressWarnings("unchecked")
+public class FailureAtomicity {
+    static final Path TEST_SRC = Paths.get(System.getProperty("test.src", "."));
+    static final Path TEST_CLASSES = Paths.get(System.getProperty("test.classes", "."));
+    static final Path fooTemplate = TEST_SRC.resolve("Foo.template");
+    static final Path barTemplate = TEST_SRC.resolve("Bar.template");
+
+    static final String[] PKGS = { "a.b.c", "x.y.z" };
+
+    public static void main(String[] args) throws Exception {
+        test_Foo();
+        test_BadFoo();  // 'Bad' => incompatible type; cannot be "fully" deserialized
+        test_FooWithReadObject();
+        test_BadFooWithReadObject();
+
+        test_Foo_Bar();
+        test_Foo_BadBar();
+        test_BadFoo_Bar();
+        test_BadFoo_BadBar();
+        test_Foo_BarWithReadObject();
+        test_Foo_BadBarWithReadObject();
+        test_BadFoo_BarWithReadObject();
+        test_BadFoo_BadBarWithReadObject();
+        test_FooWithReadObject_Bar();
+        test_FooWithReadObject_BadBar();
+        test_BadFooWithReadObject_Bar();
+        test_BadFooWithReadObject_BadBar();
+    }
+
+    static final BiConsumer<Object,Object> FOO_FIELDS_EQUAL = (a,b) -> {
+        try {
+            int aPrim = a.getClass().getField("fooPrim").getInt(a);
+            int bPrim = b.getClass().getField("fooPrim").getInt(b);
+            if (aPrim != bPrim)
+                throw new AssertionError("Not equal: (" + aPrim + "!=" + bPrim
+                                         + "), in [" + a + "] [" + b + "]");
+            Object aRef = a.getClass().getField("fooRef").get(a);
+            Object bRef = b.getClass().getField("fooRef").get(b);
+            if (!aRef.equals(bRef))
+                throw new RuntimeException("Not equal: (" + aRef + "!=" + bRef
+                                           + "), in [" + a + "] [" + b + "]");
+        } catch (NoSuchFieldException | IllegalAccessException x) {
+            throw new InternalError(x);
+        }
+    };
+    static final BiConsumer<Object,Object> FOO_FIELDS_DEFAULT = (ignore,b) -> {
+        try {
+            int aPrim = b.getClass().getField("fooPrim").getInt(b);
+            if (aPrim != 0)
+                throw new AssertionError("Expected 0, got:" + aPrim
+                                         + ", in [" + b + "]");
+            Object aRef = b.getClass().getField("fooRef").get(b);
+            if (aRef != null)
+                throw new RuntimeException("Expected null, got:" + aRef
+                                           + ", in [" + b + "]");
+        } catch (NoSuchFieldException | IllegalAccessException x) {
+            throw new InternalError(x);
+        }
+    };
+    static final BiConsumer<Object,Object> BAR_FIELDS_EQUAL = (a,b) -> {
+        try {
+            long aPrim = a.getClass().getField("barPrim").getLong(a);
+            long bPrim = b.getClass().getField("barPrim").getLong(b);
+            if (aPrim != bPrim)
+                throw new AssertionError("Not equal: (" + aPrim + "!=" + bPrim
+                                         + "), in [" + a + "] [" + b + "]");
+            Object aRef = a.getClass().getField("barRef").get(a);
+            Object bRef = b.getClass().getField("barRef").get(b);
+            if (!aRef.equals(bRef))
+                throw new RuntimeException("Not equal: (" + aRef + "!=" + bRef
+                                           + "), in [" + a + "] [" + b + "]");
+        } catch (NoSuchFieldException | IllegalAccessException x) {
+            throw new InternalError(x);
+        }
+    };
+    static final BiConsumer<Object,Object> BAR_FIELDS_DEFAULT = (ignore,b) -> {
+        try {
+            long aPrim = b.getClass().getField("barPrim").getLong(b);
+            if (aPrim != 0L)
+                throw new AssertionError("Expected 0, got:" + aPrim
+                                         + ", in [" + b + "]");
+            Object aRef = b.getClass().getField("barRef").get(b);
+            if (aRef != null)
+                throw new RuntimeException("Expected null, got:" + aRef
+                                           + ", in [" + b + "]");
+        } catch (NoSuchFieldException | IllegalAccessException x) {
+            throw new InternalError(x);
+        }
+    };
+
+    static void test_Foo() {
+        testFoo("Foo", "String", false, false, FOO_FIELDS_EQUAL); }
+    static void test_BadFoo() {
+        testFoo("BadFoo", "byte[]", true, false, FOO_FIELDS_DEFAULT); }
+    static void test_FooWithReadObject() {
+        testFoo("FooWithReadObject", "String", false, true, FOO_FIELDS_EQUAL); }
+    static void test_BadFooWithReadObject() {
+        testFoo("BadFooWithReadObject", "byte[]", true, true, FOO_FIELDS_DEFAULT); }
+
+    static void testFoo(String testName, String xyzZebraType,
+                        boolean expectCCE, boolean withReadObject,
+                        BiConsumer<Object,Object>... resultCheckers) {
+        System.out.println("\nTesting " + testName);
+        try {
+            Path testRoot = testDir(testName);
+            Path srcRoot = Files.createDirectory(testRoot.resolve("src"));
+            List<Path> srcFiles = new ArrayList<>();
+            srcFiles.add(createSrc(PKGS[0], fooTemplate, srcRoot, "String", withReadObject));
+            srcFiles.add(createSrc(PKGS[1], fooTemplate, srcRoot, xyzZebraType, withReadObject));
+
+            Path build = Files.createDirectory(testRoot.resolve("build"));
+            javac(build, srcFiles);
+
+            URLClassLoader loader = new URLClassLoader(new URL[]{ build.toUri().toURL() },
+                                                       FailureAtomicity.class.getClassLoader());
+            Class<?> fooClass = Class.forName(PKGS[0] + ".Foo", true, loader);
+            Constructor<?> ctr = fooClass.getConstructor(
+                    new Class<?>[]{int.class, String.class, String.class});
+            Object abcFoo = ctr.newInstance(5, "chegar", "zebra");
+
+            try {
+                toOtherPkgInstance(abcFoo, loader);
+                if (expectCCE)
+                    throw new AssertionError("Expected CCE not thrown");
+            } catch (ClassCastException e) {
+                if (!expectCCE)
+                    throw new AssertionError("UnExpected CCE: " + e);
+            }
+
+            Object deserialInstance = failureAtomicity.SerialRef.obj;
+
+            System.out.println("abcFoo:           " + abcFoo);
+            System.out.println("deserialInstance: " + deserialInstance);
+
+            for (BiConsumer<Object, Object> rc : resultCheckers)
+                rc.accept(abcFoo, deserialInstance);
+        } catch (IOException x) {
+            throw new UncheckedIOException(x);
+        } catch (ReflectiveOperationException x) {
+            throw new InternalError(x);
+        }
+    }
+
+    static void test_Foo_Bar() {
+        testFooBar("Foo_Bar", "String", "String", false, false, false,
+                   FOO_FIELDS_EQUAL, BAR_FIELDS_EQUAL);
+    }
+    static void test_Foo_BadBar() {
+        testFooBar("Foo_BadBar", "String", "byte[]", true, false, false,
+                   FOO_FIELDS_DEFAULT, BAR_FIELDS_DEFAULT);
+    }
+    static void test_BadFoo_Bar() {
+        testFooBar("BadFoo_Bar", "byte[]", "String", true, false, false,
+                   FOO_FIELDS_DEFAULT, BAR_FIELDS_DEFAULT);
+    }
+    static void test_BadFoo_BadBar() {
+        testFooBar("BadFoo_BadBar", "byte[]", "byte[]", true, false, false,
+                   FOO_FIELDS_DEFAULT, BAR_FIELDS_DEFAULT);
+    }
+    static void test_Foo_BarWithReadObject() {
+        testFooBar("Foo_BarWithReadObject", "String", "String", false, false, true,
+                   FOO_FIELDS_EQUAL, BAR_FIELDS_EQUAL);
+    }
+    static void test_Foo_BadBarWithReadObject() {
+        testFooBar("Foo_BadBarWithReadObject", "String", "byte[]", true, false, true,
+                   FOO_FIELDS_EQUAL, BAR_FIELDS_DEFAULT);
+    }
+    static void test_BadFoo_BarWithReadObject() {
+        testFooBar("BadFoo_BarWithReadObject", "byte[]", "String", true, false, true,
+                   FOO_FIELDS_DEFAULT, BAR_FIELDS_DEFAULT);
+    }
+    static void test_BadFoo_BadBarWithReadObject() {
+        testFooBar("BadFoo_BadBarWithReadObject", "byte[]", "byte[]", true, false, true,
+                   FOO_FIELDS_DEFAULT, BAR_FIELDS_DEFAULT);
+    }
+
+    static void test_FooWithReadObject_Bar() {
+        testFooBar("FooWithReadObject_Bar", "String", "String", false, true, false,
+                   FOO_FIELDS_EQUAL, BAR_FIELDS_EQUAL);
+    }
+    static void test_FooWithReadObject_BadBar() {
+        testFooBar("FooWithReadObject_BadBar", "String", "byte[]", true, true, false,
+                   FOO_FIELDS_EQUAL, BAR_FIELDS_DEFAULT);
+    }
+    static void test_BadFooWithReadObject_Bar() {
+        testFooBar("BadFooWithReadObject_Bar", "byte[]", "String", true, true, false,
+                   FOO_FIELDS_DEFAULT, BAR_FIELDS_DEFAULT);
+    }
+    static void test_BadFooWithReadObject_BadBar() {
+        testFooBar("BadFooWithReadObject_BadBar", "byte[]", "byte[]", true, true, false,
+                   FOO_FIELDS_DEFAULT, BAR_FIELDS_DEFAULT);
+    }
+
+    static void testFooBar(String testName, String xyzFooZebraType,
+                           String xyzBarZebraType, boolean expectCCE,
+                           boolean fooWithReadObject, boolean barWithReadObject,
+                           BiConsumer<Object,Object>... resultCheckers) {
+        System.out.println("\nTesting " + testName);
+        try {
+            Path testRoot = testDir(testName);
+            Path srcRoot = Files.createDirectory(testRoot.resolve("src"));
+            List<Path> srcFiles = new ArrayList<>();
+            srcFiles.add(createSrc(PKGS[0], fooTemplate, srcRoot, "String",
+                                   fooWithReadObject, "String"));
+            srcFiles.add(createSrc(PKGS[1], fooTemplate, srcRoot, xyzFooZebraType,
+                                   fooWithReadObject, xyzFooZebraType));
+            srcFiles.add(createSrc(PKGS[0], barTemplate, srcRoot, "String",
+                                   barWithReadObject, "String"));
+            srcFiles.add(createSrc(PKGS[1], barTemplate, srcRoot, xyzBarZebraType,
+                                   barWithReadObject, xyzFooZebraType));
+
+            Path build = Files.createDirectory(testRoot.resolve("build"));
+            javac(build, srcFiles);
+
+            URLClassLoader loader = new URLClassLoader(new URL[]{ build.toUri().toURL() },
+                                                       FailureAtomicity.class.getClassLoader());
+            Class<?> fooClass = Class.forName(PKGS[0] + ".Bar", true, loader);
+            Constructor<?> ctr = fooClass.getConstructor(
+                    new Class<?>[]{int.class, String.class, String.class,
+                                   long.class, String.class, String.class});
+            Object abcBar = ctr.newInstance( 5, "chegar", "zebraFoo", 111L, "aBar", "zebraBar");
+
+            try {
+                toOtherPkgInstance(abcBar, loader);
+                if (expectCCE)
+                    throw new AssertionError("Expected CCE not thrown");
+            } catch (ClassCastException e) {
+                if (!expectCCE)
+                    throw new AssertionError("UnExpected CCE: " + e);
+            }
+
+            Object deserialInstance = failureAtomicity.SerialRef.obj;
+
+            System.out.println("abcBar:           " + abcBar);
+            System.out.println("deserialInstance: " + deserialInstance);
+
+            for (BiConsumer<Object, Object> rc : resultCheckers)
+                rc.accept(abcBar, deserialInstance);
+        } catch (IOException x) {
+            throw new UncheckedIOException(x);
+        } catch (ReflectiveOperationException x) {
+            throw new InternalError(x);
+        }
+    }
+
+    static Path testDir(String name) throws IOException {
+        Path testRoot = Paths.get("FailureAtomicity-" + name);
+        if (Files.exists(testRoot))
+            FileUtils.deleteFileTreeWithRetry(testRoot);
+        Files.createDirectory(testRoot);
+        return testRoot;
+    }
+
+    static String platformPath(String p) { return p.replace("/", File.separator); }
+    static String binaryName(String name) { return name.replace(".", "/"); }
+    static String condRemove(String line, String pattern, boolean hasReadObject) {
+        if (hasReadObject) { return line.replaceAll(pattern, ""); }
+        else { return line; }
+    }
+    static String condReplace(String line, String... zebraFooType) {
+        if (zebraFooType.length == 1) {
+            return line.replaceAll("\\$foo_zebra_type", zebraFooType[0]);
+        } else { return line; }
+    }
+    static String nameFromTemplate(Path template) {
+        return template.getFileName().toString().replaceAll(".template", "");
+    }
+
+    static Path createSrc(String pkg, Path srcTemplate, Path srcRoot,
+                          String zebraType, boolean hasReadObject,
+                          String... zebraFooType)
+        throws IOException
+    {
+        Path srcDst = srcRoot.resolve(platformPath(binaryName(pkg)));
+        Files.createDirectories(srcDst);
+        Path srcFile = srcDst.resolve(nameFromTemplate(srcTemplate) + ".java");
+
+        List<String> lines = Files.lines(srcTemplate)
+                .map(s -> s.replaceAll("\\$package", pkg))
+                .map(s -> s.replaceAll("\\$zebra_type", zebraType))
+                .map(s -> condReplace(s, zebraFooType))
+                .map(s -> condRemove(s, "//\\$has_readObject", hasReadObject))
+                .collect(Collectors.toList());
+        Files.write(srcFile, lines);
+        return srcFile;
+    }
+
+    static void javac(Path dest, List<Path> sourceFiles) throws IOException {
+        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+        try (StandardJavaFileManager fileManager =
+                     compiler.getStandardFileManager(null, null, null)) {
+            List<File> files = sourceFiles.stream()
+                                          .map(p -> p.toFile())
+                                          .collect(Collectors.toList());
+            Iterable<? extends JavaFileObject> compilationUnits =
+                    fileManager.getJavaFileObjectsFromFiles(files);
+            fileManager.setLocation(StandardLocation.CLASS_OUTPUT,
+                                    Arrays.asList(dest.toFile()));
+            fileManager.setLocation(StandardLocation.CLASS_PATH,
+                                    Arrays.asList(TEST_CLASSES.toFile()));
+            JavaCompiler.CompilationTask task = compiler
+                    .getTask(null, fileManager, null, null, null, compilationUnits);
+            boolean passed = task.call();
+            if (!passed)
+                throw new RuntimeException("Error compiling " + files);
+        }
+    }
+
+    static Object toOtherPkgInstance(Object obj, ClassLoader loader)
+        throws IOException, ClassNotFoundException
+    {
+        byte[] bytes = serialize(obj);
+        bytes = replacePkg(bytes);
+        return deserialize(bytes, loader);
+    }
+
+    @SuppressWarnings("deprecation")
+    static byte[] replacePkg(byte[] bytes) {
+        String str = new String(bytes, 0);
+        str = str.replaceAll(PKGS[0], PKGS[1]);
+        str.getBytes(0, bytes.length, bytes, 0);
+        return bytes;
+    }
+
+    static byte[] serialize(Object obj) throws IOException {
+        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
+             ObjectOutputStream out = new ObjectOutputStream(baos);) {
+            out.writeObject(obj);
+            return baos.toByteArray();
+        }
+    }
+
+    static Object deserialize(byte[] data, ClassLoader l)
+        throws IOException, ClassNotFoundException
+    {
+        return new WithLoaderObjectInputStream(new ByteArrayInputStream(data), l)
+                .readObject();
+    }
+
+    static class WithLoaderObjectInputStream extends ObjectInputStream {
+        final ClassLoader loader;
+        WithLoaderObjectInputStream(InputStream is, ClassLoader loader)
+            throws IOException
+        {
+            super(is);
+            this.loader = loader;
+        }
+        @Override
+        protected Class<?> resolveClass(ObjectStreamClass desc)
+            throws IOException, ClassNotFoundException {
+            try {
+                return super.resolveClass(desc);
+            } catch (ClassNotFoundException x) {
+                String name = desc.getName();
+                return Class.forName(name, false, loader);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/Serializable/failureAtomicity/Foo.template	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package $package;
+
+import java.io.IOException;
+import java.io.Serializable;
+import failureAtomicity.SerialRef;
+
+public class Foo implements Serializable {
+    static final long serialVersionUID = -0L;
+
+    public final int fooPrim;
+    public final String fooRef;
+
+    public final SerialRef ref;    // So we can retrieve a reference to check
+    public $zebra_type zebraFoo;   // ordered alphabetically, must be last
+
+    public Foo(int fooPrim, String fooRef, $zebra_type zebra) {
+        this.fooPrim = fooPrim;
+        this.fooRef = fooRef;
+        this.zebraFoo = zebra;
+        this.ref = new SerialRef(this);
+    }
+
+    @Override
+    public String toString() {
+        return new StringBuilder()
+                .append("$package.Foo[")
+                .append("fooPrim:").append(fooPrim)
+                .append(", fooRef:").append(fooRef)
+                .append(", zebraFoo:").append(zebraFoo).append("]")
+                .toString();
+    }
+
+//$has_readObject    private void readObject(java.io.ObjectInputStream in)
+//$has_readObject        throws IOException, ClassNotFoundException
+//$has_readObject    {
+//$has_readObject        in.defaultReadObject();
+//$has_readObject    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/Serializable/failureAtomicity/SerialRef.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package failureAtomicity;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+
+// For verification purposes only.
+
+public class SerialRef implements Serializable {
+    static final long serialVersionUID = -0L;
+    public static Object obj;
+
+    private final Object ref;
+
+    public SerialRef(Object ref) {
+        this.ref = ref;
+    }
+
+    private void readObject(ObjectInputStream in)
+            throws IOException, ClassNotFoundException {
+        in.defaultReadObject();
+        SerialRef.obj = ref;
+    }
+}
--- a/jdk/test/java/lang/Character/UnicodeBlock/NonOptimalMapSize.java	Thu Jun 04 18:50:30 2015 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-/**
- * @test
- * @bug 8080535
- * @summary Expected size of Character.UnicodeBlock.map is not optimal
- */
-
-import java.lang.reflect.Field;
-import java.util.HashMap;
-import java.util.Map;
-
-public class NonOptimalMapSize {
-    public static void main(String[] args) throws Throwable {
-        Class<?> ubCls = Character.UnicodeBlock.class;
-        Field mapField = ubCls.getDeclaredField("map");
-        mapField.setAccessible(true);
-        Map<?,?> map = (Map<?,?>)mapField.get(null);
-        if (!map.getClass().equals(HashMap.class)) {
-            throw new RuntimeException(
-                    "Character.UnicodeBlock.map is expected to be HashMap");
-        }
-        int mapSize = map.size();
-
-        Field sizeField = ubCls.getDeclaredField("INITIAL_CAPACITY");
-        sizeField.setAccessible(true);
-        int INITIAL_CAPACITY = sizeField.getInt(null);
-
-        // Construct a HashMap with specified initial capacity
-        HashMap<Object,Object> map1 = new HashMap<>(INITIAL_CAPACITY);
-        Class<?> hmCls = HashMap.class;
-        Field tableField = hmCls.getDeclaredField("table");
-        tableField.setAccessible(true);
-        // ... and fill it up
-        map1.put(new Object(), new Object());
-        final Object initialTable = tableField.get(map1);
-        while (map1.size() < map.size() &&
-                initialTable == tableField.get(map1)) {
-            map1.put(new Object(), new Object());
-        }
-
-        // Now check that internal storage didn't change
-        if (initialTable != tableField.get(map1)) {
-            throw new RuntimeException(
-                    "Initial capacity " + INITIAL_CAPACITY +
-                    " was only enough to hold " + (map1.size()-1) +
-                    " entries, but needed " + map.size());
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/Character/UnicodeBlock/OptimalMapSize.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8080535
+ * @summary Expected size of Character.UnicodeBlock.map is not optimal
+ * @library /lib/testlibrary
+ * @build jdk.testlibrary.OptimalCapacity
+ * @run main OptimalMapSize
+ */
+
+import jdk.testlibrary.OptimalCapacity;
+
+// What will be the number of the Unicode blocks in the future.
+//
+// According to http://www.unicode.org/versions/Unicode7.0.0/ ,
+// in Unicode 7 there will be added 32 new blocks (96 with aliases).
+// According to http://www.unicode.org/versions/beta-8.0.0.html ,
+// in Unicode 8 there will be added 10 more blocks (30 with aliases).
+//
+// After implementing support of Unicode 7 and 8 in Java, there will
+// be 510+96+30 = 636 entries in Character.UnicodeBlock.map.
+//
+// Initialization of the map and this test will have to be adjusted
+// accordingly then.
+
+public class OptimalMapSize {
+    public static void main(String[] args) throws Throwable {
+        // The initial size of Character.UnicodeBlock.map.
+        // See src/java.base/share/classes/java/lang/Character.java
+        int initialCapacity = (int)(510 / 0.75f + 1.0f);
+
+        OptimalCapacity.ofHashMap(Character.UnicodeBlock.class,
+                "map", initialCapacity);
+    }
+}
--- a/jdk/test/java/lang/ProcessBuilder/Basic.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/java/lang/ProcessBuilder/Basic.java	Wed Jul 05 20:37:09 2017 +0200
@@ -36,6 +36,7 @@
  */
 
 import java.lang.ProcessBuilder.Redirect;
+import java.lang.ProcessHandle;
 import static java.lang.ProcessBuilder.Redirect.*;
 
 import java.io.*;
@@ -47,7 +48,6 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.security.*;
-import sun.misc.Unsafe;
 import java.util.regex.Pattern;
 import java.util.regex.Matcher;
 import static java.lang.System.getenv;
@@ -309,6 +309,8 @@
             String action = args[0];
             if (action.equals("sleep")) {
                 Thread.sleep(10 * 60 * 1000L);
+            } else if (action.equals("pid")) {
+                System.out.println(ProcessHandle.current().getPid());
             } else if (action.equals("testIO")) {
                 String expected = "standard input";
                 char[] buf = new char[expected.length()+1];
@@ -1139,49 +1141,29 @@
     }
 
     static void checkProcessPid() {
-        long actualPid = 0;
-        long expectedPid = -1;
-        if (Windows.is()) {
-            String[] argsTasklist = {"tasklist.exe",  "/NH", "/FI",  "\"IMAGENAME eq tasklist.exe\""};
-            ProcessBuilder pb = new ProcessBuilder(argsTasklist);
-            try {
-                Process proc = pb.start();
-                expectedPid = proc.getPid();
-
-                String output = commandOutput(proc);
-                String[] splits = output.split("\\s+");
-                actualPid = Integer.valueOf(splits[2]);
-            } catch (Throwable t) {
-                unexpected(t);
-            }
-        } else if (Unix.is() || MacOSX.is()) {
-            String[]  shArgs = {"sh", "-c", "echo $$"};
-            ProcessBuilder pb = new ProcessBuilder(shArgs);
-            try {
-                Process proc = pb.start();
-                expectedPid = proc.getPid();
-
-                String output = commandOutput(proc);
-                String[] splits = output.split("\\s+");
-                actualPid = Integer.valueOf(splits[0]);
-            } catch (Throwable t) {
-                unexpected(t);
-            }
-        } else {
-            fail("No test for checkProcessPid on platform: " + System.getProperty("os.name"));
-            return;
+        ProcessBuilder pb = new ProcessBuilder();
+        List<String> list = new ArrayList<String>(javaChildArgs);
+        list.add("pid");
+        pb.command(list);
+        try {
+            Process p = pb.start();
+            String s = commandOutput(p);
+            long actualPid = Long.valueOf(s.trim());
+            long expectedPid = p.getPid();
+            equal(actualPid, expectedPid);
+        } catch (Throwable t) {
+            unexpected(t);
         }
 
-        equal(actualPid, expectedPid);
 
         // Test the default implementation of Process.getPid
-        try {
-            DelegatingProcess p = new DelegatingProcess(null);
-            p.getPid();
-            fail("non-overridden Process.getPid method should throw UOE");
-        } catch (UnsupportedOperationException uoe) {
-            // correct
-        }
+        DelegatingProcess p = new DelegatingProcess(null);
+        THROWS(UnsupportedOperationException.class,
+                () -> p.getPid(),
+                () -> p.toHandle(),
+                () -> p.supportsNormalTermination(),
+                () -> p.children(),
+                () -> p.allChildren());
 
     }
 
@@ -2604,7 +2586,7 @@
     static volatile int passed = 0, failed = 0;
     static void pass() {passed++;}
     static void fail() {failed++; Thread.dumpStack();}
-    static void fail(String msg) {System.out.println(msg); fail();}
+    static void fail(String msg) {System.err.println(msg); fail();}
     static void unexpected(Throwable t) {failed++; t.printStackTrace();}
     static void check(boolean cond) {if (cond) pass(); else fail();}
     static void check(boolean cond, String m) {if (cond) pass(); else fail(m);}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/ProcessHandle/Basic.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import 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.io.IOException;
+import java.util.Optional;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.testng.TestNG;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @summary Basic tests for ProcessHandler
+ * @author Roger Riggs
+ */
+public class Basic {
+    /**
+     * Tests of ProcessHandle.current.
+     */
+    @Test
+    public static void test1() {
+        try {
+            ProcessHandle self = ProcessHandle.current();
+            ProcessHandle self1 = ProcessHandle.current();
+            assertEquals(self, self1); //, "get pid twice should be same %d: %d");
+        } finally {
+            // Cleanup any left over processes
+            ProcessHandle.current().children().forEach(ProcessHandle::destroy);
+        }
+    }
+
+    /**
+     * Tests of ProcessHandle.get.
+     */
+    @Test
+    public static void test2() {
+        try {
+            ProcessHandle self = ProcessHandle.current();
+            long pid = self.getPid();       // known native process id
+            Optional<ProcessHandle> self1 = ProcessHandle.of(pid);
+            assertEquals(self1.get(), self,
+                    "ProcessHandle.of(x.getPid()) should be equal getPid() %d: %d");
+
+            Optional<ProcessHandle> ph = ProcessHandle.of(pid);
+            assertEquals(pid, ph.get().getPid());
+        } finally {
+            // Cleanup any left over processes
+            ProcessHandle.current().children().forEach(ProcessHandle::destroy);
+        }
+    }
+
+    @Test
+    public static void test3() {
+        // Test can get parent of current
+        ProcessHandle ph = ProcessHandle.current();
+        try {
+            Optional<ProcessHandle> pph = ph.parent();
+            assertTrue(pph.isPresent(), "Current has a Parent");
+        } finally {
+            // Cleanup any left over processes
+            ProcessHandle.current().children().forEach(ProcessHandle::destroy);
+        }
+    }
+
+    @Test
+    public static void test4() {
+        try {
+            Process p = new ProcessBuilder("sleep", "0").start();
+            p.waitFor();
+
+            long deadPid = p.getPid();
+            p = null;               // Forget the process
+
+            Optional<ProcessHandle> t = ProcessHandle.of(deadPid);
+            assertFalse(t.isPresent(), "Handle created for invalid pid:" + t);
+        } catch (IOException | InterruptedException ex) {
+            fail("Unexpected exception", ex);
+        } finally {
+            // Cleanup any left over processes
+            ProcessHandle.current().children().forEach(ProcessHandle::destroy);
+        }
+    }
+
+    @Test
+    public static void test5() {
+        // Always contains itself.
+        ProcessHandle current = ProcessHandle.current();
+        List<ProcessHandle> list = ProcessHandle.allProcesses().collect(Collectors.toList());
+        if (!list.stream()
+                .anyMatch(ph -> ph.equals(ProcessHandle.current()))) {
+            System.out.printf("current: %s%n", current);
+            System.out.printf("all processes.size: %d%n", list.size());
+            list.forEach(p -> ProcessUtil.printProcess(p, "   allProcesses: "));
+            fail("current process not found in all processes");
+        }
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public static void test6() {
+        ProcessHandle.current().onExit();
+    }
+
+    @Test(expectedExceptions = IllegalStateException.class)
+    public static void test7() {
+        ProcessHandle.current().destroyForcibly();
+    }
+
+    // Main can be used to run the tests from the command line with only testng.jar.
+    @SuppressWarnings("raw_types")
+    public static void main(String[] args) {
+        Class<?>[] testclass = {TreeTest.class};
+        TestNG testng = new TestNG();
+        testng.setTestClasses(testclass);
+        testng.run();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/ProcessHandle/InfoTest.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,356 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.File;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.lang.ProcessBuilder;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.UserPrincipal;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Random;
+import java.util.Scanner;
+import java.util.StringTokenizer;
+import java.util.concurrent.TimeUnit;
+
+import jdk.testlibrary.Platform;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+import org.testng.TestNG;
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary Functions of ProcessHandle.Info
+ * @author Roger Riggs
+ */
+
+public class InfoTest {
+
+    static String whoami;
+
+    static {
+        try {
+            // Create a file and take the username from the file
+            Path p = Paths.get("OwnerName.tmp");
+            Files.createFile(p);
+            UserPrincipal owner = Files.getOwner(p);
+            whoami = owner.getName();
+            Files.delete(p);
+        } catch (IOException ex) {
+            ex.printStackTrace();
+            throw new UncheckedIOException("tmp file", ex);
+        }
+    }
+
+    // Main can be used to run the tests from the command line with only testng.jar.
+    @SuppressWarnings("raw_types")
+    public static void main(String[] args) {
+        Class<?>[] testclass = {InfoTest.class};
+        TestNG testng = new TestNG();
+        testng.setTestClasses(testclass);
+        testng.run();
+    }
+
+    /**
+     * Test that cputime used shows up in ProcessHandle.info
+     */
+    @Test
+    public static void test1() {
+        System.out.println("Note: when run in samevm mode the cputime of the " +
+                "test runner is included.");
+        ProcessHandle self = ProcessHandle.current();
+
+        Duration somecpu = Duration.ofMillis(200L);
+        Instant end = Instant.now().plus(somecpu);
+        while (Instant.now().isBefore(end)) {
+            // waste the cpu
+        }
+        ProcessHandle.Info info = self.info();
+        System.out.printf(" info: %s%n", info);
+        Optional<Duration> totalCpu = info.totalCpuDuration();
+        if (totalCpu.isPresent() && (totalCpu.get().compareTo(somecpu) < 0)) {
+            Assert.fail("reported cputime less than expected: " + somecpu + ", " +
+                    "actual: " + info.totalCpuDuration());
+        }
+    }
+
+    /**
+     * Spawn a child with arguments and check they are visible via the ProcessHandle.
+     */
+    @Test
+    public static void test2() {
+        try {
+            long cpulooptime = 1 << 8;
+            String[] extraArgs = {"pid", "parent", "stdin"};
+            Instant beforeStart = Instant.now().truncatedTo(ChronoUnit.SECONDS);
+            JavaChild p1 = JavaChild.spawnJavaChild((Object[])extraArgs);
+            Instant afterStart = Instant.now();
+
+            try (BufferedReader lines = p1.outputReader()) {
+                Duration lastCpu = Duration.ofMillis(0L);
+                for (int j = 0; j < 20; j++) {
+
+                    p1.sendAction("cpuloop", cpulooptime);
+                    p1.sendAction("cputime", "");
+
+                    // Read cputime from child
+                    Duration childCpuTime = null;
+                    // Read lines from the child until the result from cputime is returned
+                    String s;
+                    while ((s = lines.readLine()) != null) {
+                        String[] split = s.trim().split(" ");
+                        if (split.length == 3 && split[1].equals("cputime")) {
+                            long nanos = Long.valueOf(split[2]);
+                            childCpuTime = Duration.ofNanos(nanos);
+                            break;      // found the result we're looking for
+                        }
+                    }
+
+
+                    ProcessHandle.Info info = p1.info();
+                    System.out.printf(" info: %s%n", info);
+
+                    if (info.user().isPresent()) {
+                        String user = info.user().get();
+                        Assert.assertNotNull(user, "User name");
+                        Assert.assertEquals(user, whoami, "User name");
+                    }
+
+                    Optional<String> command = info.command();
+                    if (command.isPresent()) {
+                        String javaExe = System.getProperty("test.jdk") +
+                                File.separator + "bin" + File.separator + "java";
+                        String expected = Platform.isWindows() ? javaExe + ".exe" : javaExe;
+                        Path expectedPath = Paths.get(expected);
+                        Path actualPath = Paths.get(command.get());
+                        Assert.assertTrue(Files.isSameFile(expectedPath, actualPath),
+                                "Command: expected: " + javaExe + ", actual: " + command.get());
+                    }
+
+                    if (info.arguments().isPresent()) {
+                        String[] args = info.arguments().get();
+
+                        if (Platform.isLinux() || Platform.isOSX()) {
+                            int offset = args.length - extraArgs.length;
+                            for (int i = 0; i < extraArgs.length; i++) {
+                                Assert.assertEquals(args[offset + i], extraArgs[i],
+                                        "Actual argument mismatch, index: " + i);
+                            }
+                        } else if (Platform.isSolaris()) {
+                            Assert.assertEquals(args.length, 1,
+                                    "Expected argument list length: 1");
+                            Assert.assertNotNull(args[0],
+                                    "Expected an argument");
+                        } else {
+                            System.out.printf("No argument test for OS: %s%n", Platform.getOsName());
+                        }
+
+                        // Now check that the first argument is not the same as the executed command
+                        if (args.length > 0) {
+                            Assert.assertNotEquals(args[0], command,
+                                    "First argument should not be the executable: args[0]: "
+                                            + args[0] + ", command: " + command);
+                        }
+                    }
+
+                    if (info.totalCpuDuration().isPresent()) {
+                        Duration totalCPU = info.totalCpuDuration().get();
+                        Duration epsilon = Duration.ofMillis(200L);
+                        Assert.assertTrue(totalCPU.toNanos() > 0L,
+                                "total cpu time expected > 0ms, actual: " + totalCPU);
+                        Assert.assertTrue(totalCPU.toNanos() < lastCpu.toNanos() + 10_000_000_000L,
+                                "total cpu time expected < 10s more than previous iteration, actual: " + totalCPU);
+                        if (childCpuTime != null) {
+                            System.out.printf(" info.totalCPU: %s, childCpuTime: %s, diff: %s%n",
+                                    totalCPU.toNanos(), childCpuTime.toNanos(), childCpuTime.toNanos() - totalCPU.toNanos());
+                            Assert.assertTrue(checkEpsilon(childCpuTime, totalCPU, epsilon),
+                                    childCpuTime + " should be within " +
+                                            epsilon + " of " + totalCPU);
+                        }
+                        lastCpu = totalCPU;
+                    }
+
+                    if (info.startInstant().isPresent()) {
+                        Instant startTime = info.startInstant().get();
+                        Assert.assertTrue(startTime.isBefore(afterStart),
+                                "startTime after process spawn completed"
+                                        + startTime + " + > " + afterStart);
+                    }
+                }
+            }
+            p1.waitFor(5, TimeUnit.SECONDS);
+        } catch (IOException | InterruptedException ie) {
+            ie.printStackTrace(System.out);
+            Assert.fail("unexpected exception", ie);
+        }
+    }
+
+    /**
+     * Spawn a child with arguments and check they are visible via the ProcessHandle.
+     */
+    @Test
+    public static void test3() {
+        try {
+            for (int sleepTime : Arrays.asList(1, 2)) {
+                Process p = spawn("sleep", String.valueOf(sleepTime));
+                ProcessHandle.Info info = p.info();
+                System.out.printf(" info: %s%n", info);
+
+                if (info.user().isPresent()) {
+                    String user = info.user().get();
+                    Assert.assertNotNull(user);
+                    Assert.assertEquals(user, whoami);
+                }
+                if (info.command().isPresent()) {
+                    String command = info.command().get();
+                    String expected = Platform.isWindows() ? "sleep.exe" : "sleep";
+                    Assert.assertTrue(command.endsWith(expected), "Command: expected: \'" +
+                            expected + "\', actual: " + command);
+
+                    // Verify the command exists and is executable
+                    File exe = new File(command);
+                    Assert.assertTrue(exe.exists(), "command must exist: " + exe);
+                    Assert.assertTrue(exe.canExecute(), "command must be executable: " + exe);
+                }
+                if (info.arguments().isPresent()) {
+                    String[] args = info.arguments().get();
+                    if (args.length > 0) {
+                        Assert.assertEquals(args[0], String.valueOf(sleepTime));
+                    }
+                }
+                Assert.assertTrue(p.waitFor(15, TimeUnit.SECONDS));
+            }
+        } catch (IOException | InterruptedException ex) {
+            ex.printStackTrace(System.out);;
+        } finally {
+            // Destroy any children that still exist
+            ProcessUtil.destroyProcessTree(ProcessHandle.current());
+        }
+    }
+
+    /**
+     * Cross check the cputime reported from java.management with that for the current process.
+     */
+    @Test
+    public static void test4() {
+        Duration myCputime1 = ProcessUtil.MXBeanCpuTime();
+
+        Optional<Duration> dur1 = ProcessHandle.current().info().totalCpuDuration();
+
+        Duration myCputime2 = ProcessUtil.MXBeanCpuTime();
+
+        Optional<Duration> dur2 = ProcessHandle.current().info().totalCpuDuration();
+
+        if (dur1.isPresent() && dur2.isPresent()) {
+            Duration total1 = dur1.get();
+            Duration total2 = dur2.get();       ;
+            System.out.printf(" total1 vs. mbean: %s, getProcessCpuTime: %s, diff: %s%n",
+                    Objects.toString(total1), myCputime1, myCputime1.minus(total1));
+            System.out.printf(" total2 vs. mbean: %s, getProcessCpuTime: %s, diff: %s%n",
+                    Objects.toString(total2), myCputime2, myCputime2.minus(total2));
+
+            Duration epsilon = Duration.ofMillis(200L);      // Epsilon is 200ms.
+            Assert.assertTrue(checkEpsilon(myCputime1, myCputime2, epsilon),
+                    myCputime1.toNanos() + " should be within " + epsilon
+                            + " of " + myCputime2.toNanos());
+            Assert.assertTrue(checkEpsilon(total1, total2, epsilon),
+                    total1.toNanos() + " should be within " + epsilon
+                            + " of " + total2.toNanos());
+            Assert.assertTrue(checkEpsilon(myCputime1, total1, epsilon),
+                    myCputime1.toNanos() + " should be within " + epsilon
+                            + " of " + total1.toNanos());
+            Assert.assertTrue(checkEpsilon(total1, myCputime2, epsilon),
+                    total1.toNanos() + " should be within " + epsilon
+                            + " of " + myCputime2.toNanos());
+            Assert.assertTrue(checkEpsilon(myCputime2, total2, epsilon),
+                    myCputime2.toNanos() + " should be within " + epsilon
+                            + " of " + total2.toNanos());
+        }
+    }
+
+    @Test
+    public static void test5() {
+        ProcessHandle self = ProcessHandle.current();
+        Random r = new Random();
+        for (int i = 0; i < 30; i++) {
+            Instant end = Instant.now().plusMillis(500L);
+            while (end.isBefore(Instant.now())) {
+                // burn the cpu time checking the time
+                long x = r.nextLong();
+            }
+            if (self.info().totalCpuDuration().isPresent()) {
+                Duration totalCpu = self.info().totalCpuDuration().get();
+                long infoTotalCputime = totalCpu.toNanos();
+                long beanCputime = ProcessUtil.MXBeanCpuTime().toNanos();
+                System.out.printf(" infoTotal: %12d, beanCpu: %12d, diff: %12d%n",
+                        infoTotalCputime, beanCputime, beanCputime - infoTotalCputime);
+            } else {
+                break;  // nothing to compare; continue
+            }
+        }
+    }
+    /**
+     * Check two Durations, the second should be greater than the first or
+     * within the supplied Epsilon.
+     * @param d1 a Duration - presumed to be shorter
+     * @param d2 a 2nd Duration - presumed to be greater (or within Epsilon)
+     * @param epsilon Epsilon the amount of overlap allowed
+     * @return
+     */
+    static boolean checkEpsilon(Duration d1, Duration d2, Duration epsilon) {
+        if (d1.toNanos() <= d2.toNanos()) {
+            return true;
+        }
+        Duration diff = d1.minus(d2).abs();
+        return diff.compareTo(epsilon) <= 0;
+    }
+
+    /**
+     * Spawn a native process with the provided arguments.
+     * @param command the executable of native process
+     * @args
+     * @return the Process that was started
+     * @throws IOException thrown by ProcessBuilder.start
+     */
+    static Process spawn(String command, String... args) throws IOException {
+        ProcessBuilder pb = new ProcessBuilder();
+        pb.inheritIO();
+        List<String> list = new ArrayList<>();
+        list.add(command);
+        for (String arg : args)
+            list.add(arg);
+        pb.command(list);
+        return pb.start();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/ProcessHandle/JavaChild.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,524 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import com.sun.management.OperatingSystemMXBean;
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.InputStreamReader;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.Reader;
+import java.io.PrintWriter;
+import java.lang.InterruptedException;
+import java.lang.Override;
+import java.lang.management.ManagementFactory;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.concurrent.CompletableFuture;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.function.Consumer;
+
+
+/**
+ * Command driven subprocess with useful child functions.
+ */
+public class JavaChild extends Process {
+
+private static volatile int commandSeq = 0;         // Command sequence number
+    private static final ProcessHandle self = ProcessHandle.current();
+    private static int finalStatus = 0;
+    private static final List<JavaChild> children = new ArrayList<>();
+    private static final Set<JavaChild> completedChildren =
+            Collections.synchronizedSet(new HashSet<>());
+
+    private final Process delegate;
+    private final PrintWriter inputWriter;
+    private final BufferedReader outputReader;
+
+
+    /**
+     * Create a JavaChild control instance that delegates to the spawned process.
+     * {@link #sendAction} is used to send commands via the processes stdin.
+     * {@link #forEachOutputLine} can be used to process output from the child
+     * @param delegate the process to delegate and send commands to and get responses from
+     */
+    private JavaChild(Process delegate) {
+        this.delegate = delegate;
+        // Initialize PrintWriter with autoflush (on println)
+        inputWriter = new PrintWriter(delegate.getOutputStream(), true);
+        outputReader = new BufferedReader(new InputStreamReader(delegate.getInputStream()));
+    }
+
+    @Override
+    public void destroy() {
+        delegate.destroy();
+    }
+
+    @Override
+    public int exitValue() {
+        return delegate.exitValue();
+    }
+
+    @Override
+    public int waitFor() throws InterruptedException {
+        return delegate.waitFor();
+    }
+
+    @Override
+    public OutputStream getOutputStream() {
+        return delegate.getOutputStream();
+    }
+
+    @Override
+    public InputStream getInputStream() {
+        return delegate.getInputStream();
+    }
+
+    @Override
+    public InputStream getErrorStream() {
+        return delegate.getErrorStream();
+    }
+
+    @Override
+    public ProcessHandle toHandle() {
+        return delegate.toHandle();
+    }
+
+    @Override
+    public CompletableFuture<Process> onExit() {
+        return delegate.onExit();
+    }
+    @Override
+    public String toString() {
+        return "delegate: " + delegate.toString();
+    }
+
+    public CompletableFuture<JavaChild> onJavaChildExit() {
+        return onExit().thenApply(ph -> this);
+    }
+
+    /**
+     * Send an action and arguments to the child via stdin.
+     * @param action the action
+     * @param args additional arguments
+     * @throws IOException if something goes wrong writing to the child
+     */
+    void sendAction(String action, Object... args) throws IOException {
+        StringBuilder sb = new StringBuilder();
+        sb.append(action);
+        for (Object arg :args) {
+            sb.append(" ");
+            sb.append(arg);
+        }
+        String cmd = sb.toString();
+        synchronized (this) {
+            inputWriter.println(cmd);
+        }
+    }
+
+    public BufferedReader outputReader() {
+        return outputReader;
+    }
+
+    /**
+     * Asynchronously evaluate each line of output received back from the child process.
+     * @param consumer a Consumer of each line read from the child
+     * @return a CompletableFuture that is completed when the child closes System.out.
+     */
+    CompletableFuture<String> forEachOutputLine(Consumer<String> consumer) {
+        final CompletableFuture<String> future = new CompletableFuture<>();
+        String name = "OutputLineReader-" + getPid();
+        Thread t = new Thread(() -> {
+            try (BufferedReader reader = outputReader()) {
+                String line;
+                while ((line = reader.readLine()) != null) {
+                    consumer.accept(line);
+                }
+            } catch (IOException | RuntimeException ex) {
+                consumer.accept("IOE (" + getPid() + "):" + ex.getMessage());
+                future.completeExceptionally(ex);
+            }
+            future.complete("success");
+        }, name);
+        t.start();
+        return future;
+    }
+
+    /**
+     * Spawn a JavaChild with the provided arguments.
+     * Commands can be send to the child with {@link #sendAction}.
+     * Output lines from the child can be processed with {@link #forEachOutputLine}.
+     * System.err is set to inherit and is the unstructured async logging
+     * output for all subprocesses.
+     * @param args the command line arguments to JavaChild
+     * @return the JavaChild that was started
+     * @throws IOException thrown by ProcessBuilder.start
+     */
+    static JavaChild spawnJavaChild(Object... args) throws IOException {
+        String[] stringArgs = new String[args.length];
+        for (int i = 0; i < args.length; i++) {
+            stringArgs[i] = args[i].toString();
+        }
+        ProcessBuilder pb = build(stringArgs);
+        pb.redirectError(ProcessBuilder.Redirect.INHERIT);
+        return new JavaChild(pb.start());
+    }
+
+    /**
+     * Spawn a JavaChild with the provided arguments.
+     * Sets the process to inherit the I/O channels.
+     * @param args the command line arguments to JavaChild
+     * @return the Process that was started
+     * @throws IOException thrown by ProcessBuilder.start
+     */
+    static Process spawn(String... args) throws IOException {
+        ProcessBuilder pb = build(args);
+        pb.inheritIO();
+        return pb.start();
+    }
+
+    /**
+     * Return a ProcessBuilder with the javaChildArgs and
+     * any additional supplied args.
+     *
+     * @param args the command line arguments to JavaChild
+     * @return the ProcessBuilder
+     */
+    static ProcessBuilder build(String ... args) {
+        ProcessBuilder pb = new ProcessBuilder();
+        List<String> list = new ArrayList<>(javaChildArgs);
+        for (String arg : args)
+            list.add(arg);
+        pb.command(list);
+        return pb;
+    }
+
+    static final String javaHome = (System.getProperty("test.jdk") != null)
+            ? System.getProperty("test.jdk")
+            : System.getProperty("java.home");
+
+    static final String javaExe =
+            javaHome + File.separator + "bin" + File.separator + "java";
+
+    static final String classpath =
+            System.getProperty("java.class.path");
+
+    static final List<String> javaChildArgs =
+            Arrays.asList(javaExe,
+                    "-XX:+DisplayVMOutputToStderr",
+                    "-Dtest.jdk=" + javaHome,
+                    "-classpath", absolutifyPath(classpath),
+                    "JavaChild");
+
+    private static String absolutifyPath(String path) {
+        StringBuilder sb = new StringBuilder();
+        for (String file : path.split(File.pathSeparator)) {
+            if (sb.length() != 0)
+                sb.append(File.pathSeparator);
+            sb.append(new File(file).getAbsolutePath());
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Main program that interprets commands from the command line args or stdin.
+     * Each command produces output to stdout confirming the command and
+     * providing results.
+     * System.err is used for unstructured information.
+     * @param args an array of strings to be interpreted as commands;
+     *             each command uses additional arguments as needed
+     */
+    public static void main(String[] args) {
+        System.out.printf("args: %s %s%n", ProcessHandle.current(), Arrays.toString(args));
+        interpretCommands(args);
+        System.exit(finalStatus);
+    }
+
+    /**
+     * Interpret an array of strings as a command line.
+     * @param args an array of strings to be interpreted as commands;
+     *             each command uses additional arguments as needed
+     */
+    private static void interpretCommands(String[] args) {
+        try {
+            int nextArg = 0;
+            while (nextArg < args.length) {
+                String action = args[nextArg++];
+                switch (action) {
+                    case "help":
+                        sendResult(action, "");
+                        help();
+                        break;
+                    case "sleep":
+                        int millis = Integer.valueOf(args[nextArg++]);
+                        Thread.sleep(millis);
+                        sendResult(action, Integer.toString(millis));
+                        break;
+                    case "cpuloop":
+                        long times = Long.valueOf(args[nextArg++]);
+                        Instant end = Instant.now().plusMillis(times);
+                        while (Instant.now().isBefore(end)) {
+                            // burn the cpu til the time is up
+                        }
+                        sendResult(action, times);
+                        break;
+                    case "cputime":
+                        sendResult(action, getCpuTime());
+                        break;
+                    case "out":
+                    case "err":
+                        String value = args[nextArg++];
+                        sendResult(action, value);
+                        if (action.equals("err")) {
+                            System.err.println(value);
+                        }
+                        break;
+                    case "stdin":
+                        // Read commands from stdin;  at eof, close stdin of
+                        // children and wait for each to exit
+                        sendResult(action, "start");
+                        try (Reader reader = new InputStreamReader(System.in);
+                             BufferedReader input = new BufferedReader(reader)) {
+                            String line;
+                            while ((line = input.readLine()) != null) {
+                                line = line.trim();
+                                if (!line.isEmpty()) {
+                                    String[] split = line.split("\\s");
+                                    interpretCommands(split);
+                                }
+                            }
+                            // EOF on stdin, close stdin on all spawned processes
+                            for (JavaChild p : children) {
+                                try {
+                                    p.getOutputStream().close();
+                                } catch (IOException ie) {
+                                    sendResult("stdin_closing", p.getPid(),
+                                            "exception", ie.getMessage());
+                                }
+                            }
+
+                            for (JavaChild p : children) {
+                                do {
+                                    try {
+                                        p.waitFor();
+                                        break;
+                                    } catch (InterruptedException e) {
+                                        // retry
+                                    }
+                                } while (true);
+                            }
+                            // Wait for all children to be gone
+                            Instant timeOut = Instant.now().plusSeconds(10L);
+                            while (!completedChildren.containsAll(children)) {
+                                if (Instant.now().isBefore(timeOut)) {
+                                    Thread.sleep(100L);
+                                } else {
+                                    System.err.printf("Timeout waiting for " +
+                                            "children to terminate%n");
+                                    children.removeAll(completedChildren);
+                                    for (JavaChild c : children) {
+                                        sendResult("stdin_noterm", c.getPid());
+                                        System.err.printf("  Process not terminated: " +
+                                                "pid: %d%n", c.getPid());
+                                    }
+                                    System.exit(2);
+                                }
+                            }
+                        }
+                        sendResult(action, "done");
+                        return;                 // normal exit from JavaChild Process
+                    case "parent":
+                        sendResult(action, self.parent().toString());
+                        break;
+                    case "pid":
+                        sendResult(action, self.toString());
+                        break;
+                    case "exit":
+                        int exitValue = (nextArg < args.length)
+                                ?  Integer.valueOf(args[nextArg]) : 0;
+                        sendResult(action, exitValue);
+                        System.exit(exitValue);
+                        break;
+                    case "spawn": {
+                        if (args.length - nextArg < 2) {
+                            throw new RuntimeException("not enough args for respawn: " +
+                                    (args.length - 2));
+                        }
+                        // Spawn as many children as requested and
+                        // pass on rest of the arguments
+                        int ncount = Integer.valueOf(args[nextArg++]);
+                        Object[] subargs = new String[args.length - nextArg];
+                        System.arraycopy(args, nextArg, subargs, 0, subargs.length);
+                        for (int i = 0; i < ncount; i++) {
+                            JavaChild p = spawnJavaChild(subargs);
+                            sendResult(action, p.getPid());
+                            p.forEachOutputLine(JavaChild::sendRaw);
+                            p.onJavaChildExit().thenAccept((p1) -> {
+                                int excode = p1.exitValue();
+                                sendResult("child_exit", p1.getPid(), excode);
+                                completedChildren.add(p1);
+                            });
+                            children.add(p);        // Add child to spawned list
+                        }
+                        nextArg = args.length;
+                        break;
+                    }
+                    case "child": {
+                        // Send the command to all the live children;
+                        // ignoring those that are not alive
+                        int sentCount = 0;
+                        Object[] result =
+                                Arrays.copyOfRange(args, nextArg - 1, args.length);
+                        Object[] subargs =
+                                Arrays.copyOfRange(args, nextArg + 1, args.length);
+                        for (JavaChild p : children) {
+                            if (p.isAlive()) {
+                                sentCount++;
+                                // overwrite with current pid
+                                result[0] = Long.toString(p.getPid());
+                                sendResult(action, result);
+                                p.sendAction(args[nextArg], subargs);
+                            }
+                        }
+                        if (sentCount == 0) {
+                            sendResult(action, "n/a");
+                        }
+                        nextArg = args.length;
+                        break;
+                    }
+                    case "child_eof" :
+                        // Close the InputStream of all the live children;
+                        // ignoring those that are not alive
+                        for (JavaChild p : children) {
+                            if (p.isAlive()) {
+                                sendResult(action, p.getPid());
+                                p.getOutputStream().close();
+                            }
+                        }
+                        break;
+                    case "property":
+                        String name = args[nextArg++];
+                        sendResult(action, name, System.getProperty(name));
+                        break;
+                    case "threaddump":
+                        Thread.dumpStack();
+                        break;
+                    default:
+                        throw new Error("JavaChild action unknown: " + action);
+                }
+            }
+        } catch (Throwable t) {
+            t.printStackTrace(System.err);
+            System.exit(1);
+        }
+    }
+
+    static synchronized void sendRaw(String s) {
+        System.out.println(s);
+        System.out.flush();
+    }
+    static void sendResult(String action, Object... results) {
+        sendRaw(new Event(action, results).toString());
+    }
+
+    static long getCpuTime() {
+        OperatingSystemMXBean osMbean =
+                (OperatingSystemMXBean)ManagementFactory.getOperatingSystemMXBean();
+        return osMbean.getProcessCpuTime();
+    }
+
+    /**
+     * Print command usage to stderr.
+     */
+    private static void help() {
+        System.err.println("Commands:");
+        System.err.println("  help");
+        System.err.println("  pid");
+        System.err.println("  parent");
+        System.err.println("  cpuloop <loopcount>");
+        System.err.println("  cputime");
+        System.err.println("  stdin - read commands from stdin");
+        System.err.println("  sleep <millis>");
+        System.err.println("  spawn <n> command... - spawn n new children and send command");
+        System.err.println("  child command... - send command to all live children");
+        System.err.println("  child_eof - send eof to all live children");
+        System.err.println("  exit <exitcode>");
+        System.err.println("  out arg...");
+        System.err.println("  err arg...");
+    }
+
+    static class Event {
+        long pid;
+        long seq;
+        String command;
+        Object[] results;
+        Event(String command, Object... results) {
+            this(self.getPid(), ++commandSeq, command, results);
+        }
+        Event(long pid, int seq, String command, Object... results) {
+            this.pid = pid;
+            this.seq = seq;
+            this.command = command;
+            this.results = results;
+        }
+
+        /**
+         * Create a String encoding the pid, seq, command, and results.
+         *
+         * @return a String formatted  to send to the stream.
+         */
+        String format() {
+            StringBuilder sb = new StringBuilder();
+            sb.append(pid);
+            sb.append(":");
+            sb.append(seq);
+            sb.append(" ");
+            sb.append(command);
+            for (int i = 0; i < results.length; i++) {
+                sb.append(" ");
+                sb.append(results[i]);
+            }
+            return sb.toString();
+        }
+
+        Event(String encoded) {
+            String[] split = encoded.split("\\s");
+            String[] pidSeq = split[0].split(":");
+            pid = Long.valueOf(pidSeq[0]);
+            seq = Integer.valueOf(pidSeq[1]);
+            command = split[1];
+            Arrays.copyOfRange(split, 1, split.length);
+        }
+
+        public String toString() {
+            return format();
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/ProcessHandle/OnExitTest.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.IOException;
+import java.lang.InterruptedException;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.stream.Collectors;
+import jdk.testlibrary.Platform;
+import org.testng.annotations.Test;
+import org.testng.Assert;
+import org.testng.TestNG;
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * @summary Functions of Process.onExit and ProcessHandle.onExit
+ * @author Roger Riggs
+ */
+
+public class OnExitTest extends ProcessUtil {
+
+    @SuppressWarnings("raw_types")
+    public static void main(String[] args) {
+        Class<?>[] testclass = { OnExitTest.class};
+        TestNG testng = new TestNG();
+        testng.setTestClasses(testclass);
+        testng.run();
+    }
+
+    /**
+     * Basic test of exitValue and onExit.
+     */
+    @Test
+    public static void test1() {
+        try {
+            int[] exitValues = {0, 1, 10};
+            for (int value : exitValues) {
+                Process p = JavaChild.spawn("exit", Integer.toString(value));
+                CompletableFuture<Process> future = p.onExit();
+                future.thenAccept( (ph) -> {
+                    int actualExitValue = ph.exitValue();
+                    printf(" javaChild done: %s, exitStatus: %d%n",
+                            ph, actualExitValue);
+                    Assert.assertEquals(actualExitValue, value, "actualExitValue incorrect");
+                    Assert.assertEquals(ph, p, "Different Process passed to thenAccept");
+                });
+
+                Process h = future.get();
+                Assert.assertEquals(h, p);
+                Assert.assertEquals(p.exitValue(), value);
+                Assert.assertFalse(p.isAlive(), "Process should not be alive");
+                p.waitFor();
+            }
+        } catch (IOException | InterruptedException | ExecutionException ex) {
+            Assert.fail(ex.getMessage(), ex);
+        } finally {
+            destroyProcessTree(ProcessHandle.current());
+        }
+    }
+
+    /**
+     * Test of Completion handler when parent is killed.
+     * Spawn 1 child to spawn 3 children each with 2 children.
+     */
+    @Test
+    public static void test2() {
+        try {
+            ConcurrentHashMap<ProcessHandle, ProcessHandle> processes = new ConcurrentHashMap<>();
+            List<ProcessHandle> children = getChildren(ProcessHandle.current());
+            children.forEach(ProcessUtil::printProcess);
+            Assert.assertEquals(children.size(), 0,
+                    "Expected to start with zero children; " + children);
+
+            JavaChild proc = JavaChild.spawnJavaChild("stdin");
+            ProcessHandle procHandle = proc.toHandle();
+            printf(" spawned: %d%n", proc.getPid());
+
+            proc.forEachOutputLine((s) -> {
+                String[] split = s.trim().split(" ");
+                if (split.length == 3 && split[1].equals("spawn")) {
+                    Long child = Long.valueOf(split[2]);
+                    Long parent = Long.valueOf(split[0].split(":")[0]);
+                    processes.put(ProcessHandle.of(child).get(), ProcessHandle.of(parent).get());
+                }
+            });
+
+            proc.sendAction("spawn", "3", "stdin");
+
+            proc.sendAction("child", "spawn", "2", "stdin");
+
+            // Poll until all 9 child processes exist or the timeout is reached
+            int expected = 9;
+            Instant endTimeout = Instant.now().plusSeconds(10L);
+            do {
+                Thread.sleep(200L);
+                printf(" subprocess count: %d, waiting for %d%n", processes.size(), expected);
+            } while (processes.size() < expected &&
+                    Instant.now().isBefore(endTimeout));
+
+            children = getAllChildren(procHandle);
+
+            ArrayBlockingQueue<ProcessHandle> completions = new ArrayBlockingQueue<>(expected + 1);
+            Instant startTime = Instant.now();
+            // Create a future for each of the 9 children
+            processes.forEach( (p, parent) -> {
+                        p.onExit().whenComplete((ph, ex) -> {
+                            Duration elapsed = Duration.between(startTime, Instant.now());
+                            completions.add(ph);
+                            printf("whenComplete: pid: %s, exception: %s, thread: %s, elapsed: %s%n",
+                                    ph, ex, Thread.currentThread(), elapsed);
+                        });
+                    });
+
+            // Check that each of the spawned processes is included in the children
+            List<ProcessHandle> remaining = new ArrayList<>(children);
+            processes.forEach((p, parent) -> {
+                Assert.assertTrue(remaining.remove(p), "spawned process should have been in children");
+            });
+
+            // Remove Win32 system spawned conhost.exe processes
+            remaining.removeIf(ProcessUtil::isWindowsConsole);
+
+            remaining.forEach(p -> printProcess(p, "unexpected: "));
+            if (remaining.size() > 0) {
+                // Show full list for debugging
+                ProcessUtil.logTaskList();
+            }
+
+            proc.destroy();  // kill off the parent
+            proc.waitFor();
+
+            // Wait for all the processes to be completed
+            processes.forEach((p, parent) -> {
+                try {
+                    p.onExit().get();
+                } catch (InterruptedException | ExecutionException ex) {
+                    // ignore
+                }
+            });
+
+            // Verify that all 9 exit handlers were called
+            processes.forEach((p, parent) ->
+                Assert.assertTrue(completions.contains(p), "Child onExit not called: " + p
+                        + ", parent: " + parent
+                        + ": " + p.info()));
+
+            // Show the status of the original children
+            children.forEach(p -> printProcess(p, "after onExit:"));
+
+            Assert.assertEquals(proc.isAlive(), false, "destroyed process is alive:: %s%n" + proc);
+
+            List<ProcessHandle> children2 = getAllChildren(procHandle);
+            printf(" children2: %s%n", children2.toString());
+            Assert.assertEquals(children2.size(), 0, "After onExit, expected no children");
+
+            Assert.assertEquals(remaining.size(), 0, "Unaccounted for children");
+
+        } catch (IOException | InterruptedException ex) {
+            Assert.fail(ex.getMessage());
+        } finally {
+            destroyProcessTree(ProcessHandle.current());
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/ProcessHandle/PermissionTest.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.FilePermission;
+import java.io.IOException;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Permissions;
+import java.security.Policy;
+import java.security.ProtectionDomain;
+import java.security.SecurityPermission;
+import java.util.Arrays;
+import java.util.Optional;
+import java.util.PropertyPermission;
+
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeGroups;
+import org.testng.annotations.Test;
+
+public class PermissionTest {
+    /**
+     * Backing up policy.
+     */
+    protected static Policy policy;
+
+    /**
+     * Backing up security manager.
+     */
+    private static SecurityManager sm;
+
+    /**
+     * Current process handle.
+     */
+    private final ProcessHandle currentHndl;
+
+    PermissionTest() {
+        policy = Policy.getPolicy();
+        sm = System.getSecurityManager();
+        currentHndl = ProcessHandle.current();
+    }
+
+    @Test
+    public void allChildrenWithPermission() {
+        Policy.setPolicy(new TestPolicy(new RuntimePermission("manageProcess")));
+        currentHndl.allChildren();
+    }
+
+    @Test
+    public void allProcessesWithPermission() {
+        Policy.setPolicy(new TestPolicy(new RuntimePermission("manageProcess")));
+        ProcessHandle.allProcesses();
+    }
+
+    @Test
+    public void childrenWithPermission() {
+        Policy.setPolicy(new TestPolicy(new RuntimePermission("manageProcess")));
+        currentHndl.children();
+    }
+
+    @Test
+    public void currentWithPermission() {
+        Policy.setPolicy(new TestPolicy(new RuntimePermission("manageProcess")));
+        ProcessHandle.current();
+    }
+
+    @Test
+    public void ofWithPermission() {
+        Policy.setPolicy(new TestPolicy(new RuntimePermission("manageProcess")));
+        ProcessHandle.of(0);
+    }
+
+    @Test
+    public void parentWithPermission() {
+        Policy.setPolicy(new TestPolicy(new RuntimePermission("manageProcess")));
+        currentHndl.parent();
+    }
+
+    @Test
+    public void processToHandleWithPermission() throws IOException {
+        Policy.setPolicy(new TestPolicy(new RuntimePermission("manageProcess")));
+        Process p = null;
+        try {
+            ProcessBuilder pb = new ProcessBuilder("sleep", "30");
+            p = pb.start();
+            ProcessHandle ph = p.toHandle();
+            Assert.assertNotNull(ph, "ProcessHandle expected from Process");
+        } finally {
+            if (p != null) {
+                p.destroy();
+            }
+        }
+    }
+
+    @BeforeGroups (groups = {"NoManageProcessPermission"})
+    public void noPermissionsSetup(){
+        Policy.setPolicy(new TestPolicy());
+        SecurityManager sm = new SecurityManager();
+        System.setSecurityManager(sm);
+    }
+
+    @Test(groups = { "NoManageProcessPermission" }, expectedExceptions = SecurityException.class)
+    public void noPermissionAllChildren() {
+        currentHndl.allChildren();
+    }
+
+    @Test(groups = { "NoManageProcessPermission" }, expectedExceptions = SecurityException.class)
+    public void noPermissionAllProcesses() {
+        ProcessHandle.allProcesses();
+    }
+
+    @Test(groups = { "NoManageProcessPermission" }, expectedExceptions = SecurityException.class)
+    public void noPermissionChildren() {
+        currentHndl.children();
+    }
+
+    @Test(groups = { "NoManageProcessPermission" }, expectedExceptions = SecurityException.class)
+    public void noPermissionCurrent() {
+        ProcessHandle.current();
+    }
+
+    @Test(groups = { "NoManageProcessPermission" }, expectedExceptions = SecurityException.class)
+    public void noPermissionOf() {
+        ProcessHandle.of(0);
+    }
+
+    @Test(groups = { "NoManageProcessPermission" }, expectedExceptions = SecurityException.class)
+    public void noPermissionParent() {
+        currentHndl.parent();
+    }
+
+    @Test(groups = { "NoManageProcessPermission" }, expectedExceptions = SecurityException.class)
+    public void noPermissionProcessToHandle() throws IOException {
+        Process p = null;
+        try {
+            ProcessBuilder pb = new ProcessBuilder("sleep", "30");
+            p = pb.start();
+            ProcessHandle ph = p.toHandle();
+            Assert.assertNotNull(ph, "ProcessHandle expected from Process");
+        } finally {
+            if (p != null) {
+                p.destroy();
+            }
+        }
+    }
+
+    @AfterClass
+    public void tearDownClass() throws Exception {
+        System.setSecurityManager(sm);
+        Policy.setPolicy(policy);
+    }
+}
+
+class TestPolicy extends Policy {
+    private final PermissionCollection permissions = new Permissions();
+
+    public TestPolicy() {
+        setBasicPermissions();
+    }
+
+    /*
+     * Defines the minimal permissions required by testNG and set security
+     * manager permission when running these tests.
+     */
+    public void setBasicPermissions() {
+        permissions.add(new SecurityPermission("getPolicy"));
+        permissions.add(new SecurityPermission("setPolicy"));
+        permissions.add(new RuntimePermission("getClassLoader"));
+        permissions.add(new RuntimePermission("setSecurityManager"));
+        permissions.add(new RuntimePermission("createSecurityManager"));
+        permissions.add(new PropertyPermission("testng.show.stack.frames",
+                "read"));
+        permissions.add(new PropertyPermission("user.dir", "read"));
+        permissions.add(new PropertyPermission("test.src", "read"));
+        permissions.add(new PropertyPermission("file.separator", "read"));
+        permissions.add(new PropertyPermission("line.separator", "read"));
+        permissions.add(new PropertyPermission("fileStringBuffer", "read"));
+        permissions.add(new PropertyPermission("dataproviderthreadcount", "read"));
+        permissions.add(new FilePermission("<<ALL FILES>>", "execute"));
+    }
+
+    public TestPolicy(Permission... ps) {
+        setBasicPermissions();
+        Arrays.stream(ps).forEach(p -> permissions.add(p));
+    }
+
+    @Override
+    public PermissionCollection getPermissions(ProtectionDomain domain) {
+        return permissions;
+    }
+
+    @Override
+    public PermissionCollection getPermissions(CodeSource codesource) {
+        return permissions;
+    }
+
+    @Override
+    public boolean implies(ProtectionDomain domain, Permission perm) {
+        return permissions.implies(perm);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/ProcessHandle/ProcessUtil.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.lang.ProcessBuilder;
+import java.time.Duration;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import com.sun.management.OperatingSystemMXBean;
+
+import jdk.testlibrary.Platform;
+
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * Useful utilities for testing Process and ProcessHandle.
+ */
+public abstract class ProcessUtil {
+    /**
+     * Constructor
+     */
+    public ProcessUtil() {}
+
+    /**
+     * Returns the list of direct children.
+     * WIndows conhost.exe children are filtered out.
+     * @param ph the Process to get children of
+     * @return a list of child ProcessHandles
+     */
+    public static List<ProcessHandle> getChildren(ProcessHandle ph) {
+        return ph.children()
+                .filter(ProcessUtil::isNotWindowsConsole)
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * Returns the list of all direct and indirect children.
+     * WIndows conhost.exe children are filtered out.
+     * @param ph the Process to get children of
+     * @return a list of child ProcessHandles
+     */
+    public static List<ProcessHandle> getAllChildren(ProcessHandle ph) {
+        return ph.allChildren()
+                .filter(ProcessUtil::isNotWindowsConsole)
+                .collect(Collectors.toList());
+    }
+
+    /**
+     * Waits for and returns the direct expected Children of a ProcessHandle.
+     * For Windows, the conhost.exe children are filtered out.
+     *
+     * @param ph the process to get the children of
+     * @param nchildren the minimum number of children to expect
+     * @return a list of ProcessHandles of the children.
+     */
+    public static List<ProcessHandle> waitForChildren(ProcessHandle ph, long nchildren) {
+        List<ProcessHandle> subprocesses = null;
+        long count = 0;
+        do {
+            if (subprocesses != null) {
+                // Only wait if this is not the first time looking
+                try {
+                    Thread.sleep(500L);     // It will happen but don't burn the cpu
+                } catch (InterruptedException ie) {
+                    // ignore
+                }
+            }
+            subprocesses = getChildren(ph);
+            count = subprocesses.size();
+            System.out.printf(" waiting for subprocesses of %s to start," +
+                    " expected: %d, current: %d%n", ph, nchildren, count);
+        } while (count < nchildren);
+        return subprocesses;
+    }
+
+    /**
+     * Waits for and returns all expected Children of a ProcessHandle.
+     * For Windows, the conhost.exe children are filtered out.
+     *
+     * @param ph the process to get the children of
+     * @param nchildren the minimum number of children to expect
+     * @return a list of ProcessHandles of the children.
+     */
+    public static List<ProcessHandle> waitForAllChildren(ProcessHandle ph, long nchildren) {
+        List<ProcessHandle> subprocesses = null;
+        long count = 0;
+        do {
+            if (subprocesses != null) {
+                // Only wait if this is not the first time looking
+                try {
+                    Thread.sleep(500L);     // It will happen but don't burn the cpu
+                } catch (InterruptedException ie) {
+                    // ignore
+                }
+            }
+            subprocesses = getAllChildren(ph);
+            count = subprocesses.size();
+            System.out.printf(" waiting for subprocesses of %s to start," +
+                    " expected: %d, current: %d%n", ph, nchildren, count);
+        } while (count < nchildren);
+        return subprocesses;
+    }
+
+    /**
+     * Destroy all children of the ProcessHandle.
+     * (Except the conhost.exe on Windows)
+     *
+     * @param p a ProcessHandle
+     * @return the ProcessHandle
+     */
+    public static ProcessHandle destroyProcessTree(ProcessHandle p) {
+        Stream<ProcessHandle> children = p.allChildren().filter(ProcessUtil::isNotWindowsConsole);
+        children.forEach(ph -> {
+            System.out.printf("destroyProcessTree destroyForcibly%n");
+            printProcess(ph);
+            ph.destroyForcibly();
+        });
+        return p;
+    }
+
+    /**
+     * The OSMXBean for this process.
+     */
+    public static final OperatingSystemMXBean osMbean =
+            (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
+
+    /**
+     * Return the CPU time of the current process according to the OperatingSystemMXBean.
+     *
+     * @return the CPU time of the current process
+     */
+    public static Duration MXBeanCpuTime() {
+        return Duration.ofNanos(osMbean.getProcessCpuTime());
+    }
+
+    /**
+     * Return true if the ProcessHandle is a Windows i586 conhost.exe process.
+     *
+     * @param p the processHandle of the Process
+     * @return Return true if the ProcessHandle is for a Windows i586 conhost.exe process
+     */
+    static boolean isWindowsConsole(ProcessHandle p) {
+        return Platform.isWindows() && p.info().command().orElse("").endsWith("C:\\Windows\\System32\\conhost.exe");
+    }
+
+    /**
+     * Return true if the ProcessHandle is NOT  a Windows i586 conhost.exe process.
+     *
+     * @param p the processHandle of the Process
+     * @return Return true if the ProcessHandle is NOT for a Windows i586 conhost.exe process
+     */
+    static boolean isNotWindowsConsole(ProcessHandle p) {
+        return !isWindowsConsole(p);
+    }
+
+    /**
+     * Print a formatted string to System.out.
+     * @param format the format
+     * @param args the argument array
+     */
+    static void printf(String format, Object... args) {
+        String s = String.format(format, args);
+        System.out.print(s);
+    }
+
+    /**
+     * Print information about a process.
+     * Prints the pid, if it is alive, and information about the process.
+     * @param ph the processHandle at the top
+     */
+    static void printProcess(ProcessHandle ph) {
+        printProcess(ph, "");
+    }
+
+    /**
+     * Print information about a process.
+     * Prints the pid, if it is alive, and information about the process.
+     * @param ph the processHandle at the top
+     * @param prefix the String to prefix the output with
+     */
+    static void printProcess(ProcessHandle ph, String prefix) {
+        printf("%spid %s, alive: %s; parent: %s, %s%n", prefix,
+                ph.getPid(), ph.isAlive(), ph.parent(), ph.info());
+    }
+
+    /**
+     * Print the process hierarchy as visible via ProcessHandle.
+     * Prints the pid, if it is alive, and information about the process.
+     * @param ph the processHandle at the top
+     * @param prefix the String to prefix the output with
+     */
+    static void printDeep(ProcessHandle ph, String prefix) {
+        printProcess(ph, prefix);
+        ph.children().forEach(p -> printDeep(p, prefix + "   "));
+    }
+
+    /**
+     * Use the native command to list the active processes.
+     */
+    static void logTaskList() {
+        String[] windowsArglist = {"tasklist.exe", "/v"};
+        String[] unixArglist = {"ps", "-ef"};
+
+        String[] argList = null;
+        if (Platform.isWindows()) {
+            argList = windowsArglist;
+        } else if (Platform.isLinux() || Platform.isOSX()) {
+            argList = unixArglist;
+        } else {
+            return;
+        }
+
+        ProcessBuilder pb = new ProcessBuilder(argList);
+        pb.inheritIO();
+        try {
+            Process proc = pb.start();
+            proc.waitFor();
+        } catch (IOException | InterruptedException ex) {
+            ex.printStackTrace();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/ProcessHandle/TEST.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,4 @@
+# ProcessHandle tests use TestNG
+TestNG.dirs = .
+lib.dirs = /lib/testlibrary
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/ProcessHandle/TreeTest.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,358 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.concurrent.ExecutionException;
+import org.testng.Assert;
+import org.testng.TestNG;
+import org.testng.annotations.Test;
+
+/*
+ * @test
+ * @library /lib/testlibrary
+ * Test counting and JavaChild.spawning and counting of Processes.
+ * @run testng/othervm InfoTest
+ * @author Roger Riggs
+ */
+public class TreeTest extends ProcessUtil {
+    // Main can be used to run the tests from the command line with only testng.jar.
+    @SuppressWarnings("raw_types")
+    public static void main(String[] args) {
+        Class<?>[] testclass = {TreeTest.class};
+        TestNG testng = new TestNG();
+        testng.setTestClasses(testclass);
+        testng.run();
+    }
+
+    /**
+     * Test counting and spawning and counting of Processes.
+     */
+    @Test
+    public static void test1() {
+        final int MAXCHILDREN = 2;
+        List<JavaChild> spawned = new ArrayList<>();
+
+        try {
+            ProcessHandle self = ProcessHandle.current();
+
+            printf("self pid: %d%n", self.getPid());
+            printDeep(self, "");
+            long count = getChildren(self).size();
+            Assert.assertEquals(count, 0, "Start with zero children");
+
+            for (int i = 0; i < MAXCHILDREN; i++) {
+                // spawn and wait for instructions
+                spawned.add(JavaChild.spawnJavaChild("pid", "stdin"));
+            }
+
+            List<ProcessHandle> subprocesses = getChildren(self);
+            subprocesses.forEach(ProcessUtil::printProcess);
+            count = subprocesses.size();
+            Assert.assertEquals(count, MAXCHILDREN, "Wrong number of spawned children");
+
+            // Send exit command to each spawned Process
+            spawned.forEach(p -> {
+                    try {
+                        p.sendAction("exit", "");
+                    } catch (IOException ex) {
+                        Assert.fail("IOException in sendAction", ex);
+                    }
+                });
+
+            // Wait for each Process to exit
+            spawned.forEach(p -> {
+                    do {
+                        try {
+                            Assert.assertEquals(p.waitFor(), 0, "exit status incorrect");
+                            break;
+                        } catch (InterruptedException  ex) {
+                            continue; // Retry
+                        }
+                    } while (true);
+                });
+
+            // Verify that ProcessHandle.isAlive sees each of them as not alive
+            for (ProcessHandle ph : subprocesses) {
+                Assert.assertFalse(ph.isAlive(),
+                        "ProcessHandle.isAlive for exited process: " + ph);
+            }
+
+            // Verify no current children are visible
+            count = getChildren(self).size();
+            Assert.assertEquals(count, 0, "Children destroyed, should be zero");
+
+        } catch (IOException ioe) {
+            Assert.fail("unable to spawn process", ioe);
+        } finally {
+            // Cleanup any left over processes
+            spawned.stream().map(Process::toHandle)
+                    .filter(ProcessHandle::isAlive)
+                    .forEach(ph -> printDeep(ph, "test1 cleanup: "));
+            destroyProcessTree(ProcessHandle.current());
+        }
+    }
+
+    /**
+     * Test counting and spawning and counting of Processes.
+     */
+    @Test
+    public static void test2() {
+        ProcessHandle p1Handle = null;
+        try {
+            ProcessHandle self = ProcessHandle.current();
+            List<ProcessHandle> initialChildren = getChildren(self);
+            long count = initialChildren.size();
+            if (count > 0) {
+                initialChildren.forEach(p -> printDeep(p, "test2 initial unexpected: "));
+                Assert.assertEquals(count, 0, "Start with zero children (except Windows conhost.exe)");
+            }
+
+            JavaChild p1 = JavaChild.spawnJavaChild("stdin");
+            p1Handle = p1.toHandle();
+            printf("  p1 pid: %d%n", p1.getPid());
+
+            int spawnNew = 3;
+            p1.sendAction("spawn", spawnNew, "stdin");
+
+            // Wait for direct children to be created and save the list
+            List<ProcessHandle> subprocesses = waitForAllChildren(p1Handle, spawnNew);
+            for (ProcessHandle ph : subprocesses) {
+                Assert.assertTrue(ph.isAlive(), "Child should be alive: " + ph);
+            }
+
+            // Each child spawns two processes and waits for commands
+            int spawnNewSub = 2;
+            p1.sendAction("child", "spawn", spawnNewSub, "stdin");
+
+            // For each spawned child, wait for its children
+            for (ProcessHandle p : subprocesses) {
+                List<ProcessHandle> grandChildren = waitForChildren(p, spawnNewSub);
+            }
+
+            List<ProcessHandle> allChildren = getAllChildren(p1Handle);
+            printf(" allChildren:  %s%n",
+                    allChildren.stream().map(p -> p.getPid())
+                            .collect(Collectors.toList()));
+            for (ProcessHandle ph : allChildren) {
+                Assert.assertEquals(ph.isAlive(), true, "Child should be alive: " + ph);
+            }
+
+            // Closing JavaChild's InputStream will cause all children to exit
+            p1.getOutputStream().close();
+
+            for (ProcessHandle p : allChildren) {
+                try {
+                    p.onExit().get();       // wait for the child to exit
+                } catch (ExecutionException e) {
+                    Assert.fail("waiting for process to exit", e);
+                }
+            }
+            p1.waitFor();           // wait for spawned process to exit
+
+            List<ProcessHandle> remaining = getChildren(self);
+            remaining.forEach(ph -> Assert.assertFalse(ph.isAlive(),
+                            "process should not be alive: " + ph));
+        } catch (IOException | InterruptedException t) {
+            t.printStackTrace();
+            throw new RuntimeException(t);
+        } finally {
+            // Cleanup any left over processes
+            if (p1Handle.isAlive()) {
+                printDeep(p1Handle, "test2 cleanup: ");
+            }
+            destroyProcessTree(ProcessHandle.current());
+        }
+    }
+
+    /**
+     * Test destroy of processes.
+     */
+    @Test
+    public static void test3() {
+        try {
+            ProcessHandle self = ProcessHandle.current();
+
+            JavaChild p1 = JavaChild.spawnJavaChild("stdin");
+            ProcessHandle p1Handle = p1.toHandle();
+            printf(" p1: %s%n", p1.getPid());
+            long count = getChildren(self).size();
+            Assert.assertEquals(count, 1, "Wrong number of spawned children");
+
+            int newChildren = 3;
+            // Spawn children and have them wait
+            p1.sendAction("spawn", newChildren, "stdin");
+
+            // Wait for the new processes and save the list
+            List<ProcessHandle> subprocesses = waitForAllChildren(p1Handle, newChildren);
+            printDeep(p1Handle, "allChildren");
+
+            Assert.assertEquals(subprocesses.size(), newChildren, "Wrong number of children");
+
+            p1.children().filter(TreeTest::isNotWindowsConsole)
+                    .forEach(ProcessHandle::destroyForcibly);
+
+            self.children().filter(TreeTest::isNotWindowsConsole)
+                    .forEach(ProcessHandle::destroyForcibly);
+
+            do {
+                Thread.sleep(500L);      // It will happen but don't burn the cpu
+                Object[] children = self.allChildren()
+                        .filter(TreeTest::isNotWindowsConsole)
+                        .toArray();
+                count = children.length;
+                printf(" waiting for subprocesses of %s to terminate," +
+                                " expected: 0, current: %d, children: %s%n", self, count,
+                        Arrays.toString(children));
+                printDeep(self, "");
+            } while (count > 0);
+
+            boolean ex1 = p1.waitFor(5, TimeUnit.SECONDS);
+            Assert.assertTrue(ex1, "Subprocess should have exited: " + p1);
+
+            for (ProcessHandle p : subprocesses) {
+                Assert.assertFalse(p.isAlive(), "Destroyed process.isAlive: " + p +
+                        ", parent: " + p.parent() +
+                        ", info: " + p.info().toString());
+            }
+
+        } catch (IOException ioe) {
+            Assert.fail("Spawn of subprocess failed", ioe);
+        } catch (InterruptedException inte) {
+            Assert.fail("InterruptedException", inte);
+        }
+    }
+
+    /**
+     * Test (Not really a test) that dumps the list of all Processes.
+     */
+    @Test
+    public static void test4() {
+        printf("    Parent     Child  Info%n");
+        Stream<ProcessHandle> s = ProcessHandle.allProcesses();
+        ProcessHandle[] processes = s.toArray(ProcessHandle[]::new);
+        int len = processes.length;
+        ProcessHandle[] parent = new ProcessHandle[len];
+        Set<ProcessHandle> processesSet =
+                Arrays.stream(processes).collect(Collectors.toSet());
+        Integer[] sortindex = new Integer[len];
+        for (int i = 0; i < len; i++) {
+            sortindex[i] = i;
+         }
+        for (int i = 0; i < len; i++) {
+            parent[sortindex[i]] = processes[sortindex[i]].parent().orElse(null);
+        }
+        Arrays.sort(sortindex, (i1, i2) -> {
+            int cmp = Long.compare((parent[i1] == null ? 0L : parent[i1].getPid()),
+                    (parent[i2] == null ? 0L : parent[i2].getPid()));
+            if (cmp == 0) {
+                cmp = Long.compare((processes[i1] == null ? 0L : processes[i1].getPid()),
+                        (processes[i2] == null ? 0L : processes[i2].getPid()));
+            }
+            return cmp;
+        });
+        boolean fail = false;
+        for (int i = 0; i < len; i++) {
+            ProcessHandle p = processes[sortindex[i]];
+            ProcessHandle p_parent = parent[sortindex[i]];
+            ProcessHandle.Info info = p.info();
+            String indent = "    ";
+            if (p_parent != null) {
+                if (!processesSet.contains(p_parent)) {
+                    fail = true;
+                    indent = "*** ";
+                }
+            }
+            printf("%s %7s, %7s, %s%n", indent, p_parent, p, info);
+        }
+        Assert.assertFalse(fail, "Parents missing from all Processes");
+
+    }
+
+    /**
+     * A test for scale; launch a large number (39) of subprocesses.
+     */
+    @Test
+    public static void test5() {
+        int factor = 2;
+        ProcessHandle p1Handle = null;
+        Instant start = Instant.now();
+        try {
+            JavaChild p1 = JavaChild.spawnJavaChild("stdin");
+            p1Handle = p1.toHandle();
+
+            printf("Spawning %d x %d x %d processes, pid: %d%n",
+                    factor, factor, factor, p1.getPid());
+
+            // Start the first tier of subprocesses
+            p1.sendAction("spawn", factor, "stdin");
+
+            // Start the second tier of subprocesses
+            p1.sendAction("child", "spawn", factor, "stdin");
+
+            // Start the third tier of subprocesses
+            p1.sendAction("child", "child", "spawn", factor, "stdin");
+
+            int newChildren = factor * (1 + factor * (1 + factor));
+            List<ProcessHandle> children = ProcessUtil.waitForAllChildren(p1Handle, newChildren);
+
+            Assert.assertEquals(p1.children()
+                    .filter(ProcessUtil::isNotWindowsConsole)
+                    .count(), factor, "expected direct children");
+            Assert.assertEquals(p1.allChildren()
+                    .filter(ProcessUtil::isNotWindowsConsole)
+                    .count(),
+                    factor * factor * factor + factor * factor + factor,
+                    "expected all children");
+
+            List<ProcessHandle> subprocesses = p1.allChildren()
+                    .filter(ProcessUtil::isNotWindowsConsole)
+                    .collect(Collectors.toList());
+            printf(" allChildren:  %s%n",
+                    subprocesses.stream().map(p -> p.getPid())
+                    .collect(Collectors.toList()));
+
+            p1.getOutputStream().close();  // Close stdin for the controlling p1
+            p1.waitFor();
+        } catch (InterruptedException | IOException ex) {
+            Assert.fail("Unexpected Exception", ex);
+        } finally {
+            printf("Duration: %s%n", Duration.between(start, Instant.now()));
+            // Cleanup any left over processes
+            if (p1Handle.isAlive()) {
+                printDeep(p1Handle, "test5 cleanup: ");
+            }
+            destroyProcessTree(ProcessHandle.current());
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/String/LiteralReplace.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 8058779
+ * @library /lib/testlibrary/
+ * @build jdk.testlibrary.RandomFactory
+ * @run testng LiteralReplace
+ * @summary Basic tests of String.replace(CharSequence, CharSequence)
+ * @key randomness
+ */
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.Random;
+
+import jdk.testlibrary.RandomFactory;
+
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+import static org.testng.Assert.fail;
+
+public class LiteralReplace {
+
+    @Test(dataProvider="sourceTargetReplacementExpected")
+    public void testExpected(String source, String target,
+             String replacement, String expected)
+    {
+        String canonical = canonicalReplace(source, target, replacement);
+        if (!canonical.equals(expected)) {
+            fail("Canonical: " + canonical + " != " + expected);
+        }
+        test0(source, target, replacement, expected);
+    }
+
+    @Test(dataProvider="sourceTargetReplacement")
+    public void testCanonical(String source, String target,
+            String replacement)
+    {
+        String canonical = canonicalReplace(source, target, replacement);
+        test0(source, target, replacement, canonical);
+    }
+
+    private void test0(String source, String target, String replacement,
+            String expected)
+    {
+        String result = source.replace(target, replacement);
+        if (!result.equals(expected)) {
+            fail(result + " != " + expected);
+        }
+    }
+
+    @Test(dataProvider="sourceTargetReplacementWithNull",
+            expectedExceptions = {NullPointerException.class})
+    public void testNPE(String source, String target, String replacement) {
+        source.replace(target, replacement);
+    }
+
+
+    @DataProvider
+    public static Object[][] sourceTargetReplacementExpected() {
+        return new Object[][] {
+            {"aaa", "aa", "b", "ba"},
+            {"abcdefgh", "def", "DEF", "abcDEFgh"},
+            {"abcdefgh", "123", "DEF", "abcdefgh"},
+            {"abcdefgh", "abcdefghi", "DEF", "abcdefgh"},
+            {"abcdefghabc", "abc", "DEF", "DEFdefghDEF"},
+            {"abcdefghdef", "def", "", "abcgh"},
+            {"abcdefgh", "", "_", "_a_b_c_d_e_f_g_h_"},
+            {"", "", "", ""},
+            {"", "a", "b", ""},
+            {"", "", "abc", "abc"},
+            {"abcdefgh", "abcdefgh", "abcdefgh", "abcdefgh"},
+            {"abcdefgh", "abcdefgh", "abcdefghi", "abcdefghi"},
+            {"abcdefgh", "abcdefgh", "", ""},
+            {"abcdabcd", "abcd", "", ""},
+            {"aaaaaaaaa", "aa", "_X_", "_X__X__X__X_a"},
+            {"aaaaaaaaa", "aa", "aaa", "aaaaaaaaaaaaa"},
+            {"aaaaaaaaa", "aa", "aa", "aaaaaaaaa"},
+            {"a.c.e.g.", ".", "-", "a-c-e-g-"},
+            {"abcdefgh", "[a-h]", "X", "abcdefgh"},
+            {"aa+", "a+", "", "a"},
+            {"^abc$", "abc", "x", "^x$"},
+        };
+    }
+
+    @DataProvider
+    public static Iterator<Object[]> sourceTargetReplacement() {
+        ArrayList<Object[]> list = new ArrayList<>();
+        for (int maxSrcLen = 1; maxSrcLen <= (1 << 10); maxSrcLen <<= 1) {
+            for (int maxTrgLen = 1; maxTrgLen <= (1 << 10); maxTrgLen <<= 1) {
+                for (int maxPrlLen = 1; maxPrlLen <= (1 << 10); maxPrlLen <<= 1) {
+                    list.add(makeArray(makeRandomString(maxSrcLen),
+                                       makeRandomString(maxTrgLen),
+                                       makeRandomString(maxPrlLen)));
+
+                    String source = makeRandomString(maxSrcLen);
+                    list.add(makeArray(source,
+                                       mekeRandomSubstring(source, maxTrgLen),
+                                       makeRandomString(maxPrlLen)));
+                }
+            }
+        }
+        return list.iterator();
+    }
+
+    @DataProvider
+    public static Iterator<Object[]> sourceTargetReplacementWithNull() {
+        ArrayList<Object[]> list = new ArrayList<>();
+        Object[] arr = {null, "", "a", "b", "string", "str", "ababstrstr"};
+        for (int i = 0; i < arr.length; ++i) {
+            for (int j = 0; j < arr.length; ++j) {
+                for (int k = 0; k < arr.length; ++k) {
+                    if (arr[i] != null && (arr[j] == null || arr[k] == null)) {
+                        list.add(makeArray(arr[i], arr[j], arr[k]));
+                    }
+                }
+            }
+        }
+        return list.iterator();
+    }
+
+    // utilities
+
+    /**
+     * How the String.replace(CharSequence, CharSequence) used to be implemented
+     */
+    private static String canonicalReplace(String source, String target, String replacement) {
+        return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(
+                source).replaceAll(Matcher.quoteReplacement(replacement.toString()));
+    }
+
+    private static final Random random = RandomFactory.getRandom();
+
+    private static final char[] CHARS = ("qwertyuiop[]12345678" +
+        "90-=\\`asdfghjkl;'zxcvbnm,./~!@#$%^&*()_+|QWERTYUIOP{" +
+        "}ASDFGHJKL:\"ZXCVBNM<>?\n\r\t\u0444\u044B\u0432\u0430").toCharArray();
+
+    private static String makeRandomString(int maxLen) {
+        int len = random.nextInt(maxLen);
+        char[] buf = new char[len];
+        for (int i = 0; i < len; ++i) {
+            buf[i] = CHARS[random.nextInt(CHARS.length)];
+        }
+        return new String(buf);
+    }
+
+    private static String mekeRandomSubstring(String source, int maxLen) {
+        if (source.isEmpty()) {
+            return source;
+        }
+        int pos = random.nextInt(source.length());
+        int len = Integer.min(source.length() - pos,
+                              random.nextInt(maxLen));
+        return source.substring(pos, pos + len);
+    }
+
+    private static Object[] makeArray(Object... array) {
+         return array;
+    }
+}
--- a/jdk/test/java/net/SocketOption/OptionsTest.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/java/net/SocketOption/OptionsTest.java	Wed Jul 05 20:37:09 2017 +0200
@@ -23,8 +23,9 @@
 
 /*
  * @test
- * @bug 8036979
+ * @bug 8036979 8072384
  * @run main/othervm -Xcheck:jni OptionsTest
+ * @run main/othervm -Xcheck:jni -Djava.net.preferIPv4Stack=true OptionsTest
  */
 
 import java.net.*;
@@ -59,7 +60,8 @@
 
     static Test[] serverSocketTests = new Test[] {
         Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)),
-        Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE)
+        Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE),
+        Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(100))
     };
 
     static Test[] dgSocketTests = new Test[] {
@@ -193,6 +195,9 @@
                 return Integer.valueOf(socket.getReceiveBufferSize());
             } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) {
                 return Boolean.valueOf(socket.getReuseAddress());
+            } else if (option.equals(StandardSocketOptions.IP_TOS)) {
+                return Integer.valueOf(jdk.net.Sockets.getOption(
+                    socket, StandardSocketOptions.IP_TOS));
             } else {
                 throw new RuntimeException("unexecpted socket option");
             }
--- a/jdk/test/java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java	Wed Jul 05 20:37:09 2017 +0200
@@ -34,6 +34,7 @@
  *          java.rmi/sun.rmi.transport.tcp
  * @build TestLibrary RMID ActivationLibrary
  * @run main/othervm/timeout=240 RmidViaInheritedChannel
+ * @key intermittent
  */
 
 import java.io.IOException;
--- a/jdk/test/java/time/tck/java/time/zone/TCKZoneOffsetTransitionRule.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/java/time/tck/java/time/zone/TCKZoneOffsetTransitionRule.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -156,6 +156,13 @@
                 OFFSET_0200, OFFSET_0200, OFFSET_0300);
     }
 
+    @Test(expectedExceptions=IllegalArgumentException.class)
+    public void test_factory_nonZeroTimeNanos() {
+        ZoneOffsetTransitionRule.of(
+            Month.MARCH, 20, DayOfWeek.SUNDAY, LocalTime.of(1, 2, 3, 400_000_000),
+            false, TimeDefinition.WALL, OFFSET_0200, OFFSET_0200, OFFSET_0300);
+    }
+
     //-----------------------------------------------------------------------
     // getters
     //-----------------------------------------------------------------------
--- a/jdk/test/java/util/Arrays/ParallelPrefix.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/java/util/Arrays/ParallelPrefix.java	Wed Jul 05 20:37:09 2017 +0200
@@ -51,7 +51,7 @@
     private final static int MEDIUM_ARRAY_SIZE = 1 << 8;
 
     //Array size much greater than MIN_PARTITION
-    private final static int LARGE_ARRAY_SIZE = 1 << 12;
+    private final static int LARGE_ARRAY_SIZE = 1 << 14;
 
     private final static int[] ARRAY_SIZE_COLLECTION  = new int[]{
         SMALL_ARRAY_SIZE,
@@ -60,7 +60,7 @@
         LARGE_ARRAY_SIZE
     };
 
-    @DataProvider
+    @DataProvider(name = "intSet")
     public static Object[][] intSet(){
         return genericData(size -> IntStream.range(0, size).toArray(),
                 new IntBinaryOperator[]{
@@ -68,7 +68,7 @@
                     Integer::min});
     }
 
-    @DataProvider
+    @DataProvider(name = "longSet")
     public static Object[][] longSet(){
         return genericData(size -> LongStream.range(0, size).toArray(),
                 new LongBinaryOperator[]{
@@ -76,7 +76,7 @@
                     Long::min});
     }
 
-    @DataProvider
+    @DataProvider(name = "doubleSet")
     public static Object[][] doubleSet(){
         return genericData(size -> IntStream.range(0, size).mapToDouble(i -> (double)i).toArray(),
                 new DoubleBinaryOperator[]{
@@ -84,7 +84,7 @@
                     Double::min});
     }
 
-    @DataProvider
+    @DataProvider(name = "stringSet")
     public static Object[][] stringSet(){
         Function<Integer, String[]> stringsFunc = size ->
                 IntStream.range(0, size).mapToObj(Integer::toString).toArray(String[]::new);
@@ -121,11 +121,11 @@
 
         int[] parallelResult = data.clone();
         Arrays.parallelPrefix(parallelResult, fromIndex, toIndex, op);
-        assertEquals(parallelResult, sequentialResult);
+        assertArraysEqual(parallelResult, sequentialResult);
 
         int[] parallelRangeResult = Arrays.copyOfRange(data, fromIndex, toIndex);
         Arrays.parallelPrefix(parallelRangeResult, op);
-        assertEquals(parallelRangeResult, Arrays.copyOfRange(sequentialResult, fromIndex, toIndex));
+        assertArraysEqual(parallelRangeResult, Arrays.copyOfRange(sequentialResult, fromIndex, toIndex));
     }
 
     @Test(dataProvider="longSet")
@@ -137,11 +137,11 @@
 
         long[] parallelResult = data.clone();
         Arrays.parallelPrefix(parallelResult, fromIndex, toIndex, op);
-        assertEquals(parallelResult, sequentialResult);
+        assertArraysEqual(parallelResult, sequentialResult);
 
         long[] parallelRangeResult = Arrays.copyOfRange(data, fromIndex, toIndex);
         Arrays.parallelPrefix(parallelRangeResult, op);
-        assertEquals(parallelRangeResult, Arrays.copyOfRange(sequentialResult, fromIndex, toIndex));
+        assertArraysEqual(parallelRangeResult, Arrays.copyOfRange(sequentialResult, fromIndex, toIndex));
     }
 
     @Test(dataProvider="doubleSet")
@@ -153,11 +153,11 @@
 
         double[] parallelResult = data.clone();
         Arrays.parallelPrefix(parallelResult, fromIndex, toIndex, op);
-        assertEquals(parallelResult, sequentialResult);
+        assertArraysEqual(parallelResult, sequentialResult);
 
         double[] parallelRangeResult = Arrays.copyOfRange(data, fromIndex, toIndex);
         Arrays.parallelPrefix(parallelRangeResult, op);
-        assertEquals(parallelRangeResult, Arrays.copyOfRange(sequentialResult, fromIndex, toIndex));
+        assertArraysEqual(parallelRangeResult, Arrays.copyOfRange(sequentialResult, fromIndex, toIndex));
     }
 
     @Test(dataProvider="stringSet")
@@ -169,11 +169,11 @@
 
         String[] parallelResult = data.clone();
         Arrays.parallelPrefix(parallelResult, fromIndex, toIndex, op);
-        assertEquals(parallelResult, sequentialResult);
+        assertArraysEqual(parallelResult, sequentialResult);
 
         String[] parallelRangeResult = Arrays.copyOfRange(data, fromIndex, toIndex);
         Arrays.parallelPrefix(parallelRangeResult, op);
-        assertEquals(parallelRangeResult, Arrays.copyOfRange(sequentialResult, fromIndex, toIndex));
+        assertArraysEqual(parallelRangeResult, Arrays.copyOfRange(sequentialResult, fromIndex, toIndex));
     }
 
     @Test
@@ -293,5 +293,41 @@
     public static void assertInstance(Object actual, Class<?> expected, String message) {
         assertTrue(expected.isInstance(actual), message);
     }
+
+    static void assertArraysEqual(int[] actual, int[] expected) {
+        try {
+            assertEquals(actual, expected, "");
+        } catch (AssertionError x) {
+            throw new AssertionError(String.format("Expected:%s, actual:%s",
+                    Arrays.toString(expected), Arrays.toString(actual)), x);
+        }
+    }
+
+    static void assertArraysEqual(long[] actual, long[] expected) {
+        try {
+            assertEquals(actual, expected, "");
+        } catch (AssertionError x) {
+            throw new AssertionError(String.format("Expected:%s, actual:%s",
+                    Arrays.toString(expected), Arrays.toString(actual)), x);
+        }
+    }
+
+    static void assertArraysEqual(double[] actual, double[] expected) {
+        try {
+            assertEquals(actual, expected, "");
+        } catch (AssertionError x) {
+            throw new AssertionError(String.format("Expected:%s, actual:%s",
+                    Arrays.toString(expected), Arrays.toString(actual)), x);
+        }
+    }
+
+    static void assertArraysEqual(String[] actual, String[] expected) {
+        try {
+            assertEquals(actual, expected, "");
+        } catch (AssertionError x) {
+            throw new AssertionError(String.format("Expected:%s, actual:%s",
+                    Arrays.toString(expected), Arrays.toString(actual)), x);
+        }
+    }
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Collections/EnumerationAsIterator.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8072726
+ * @summary Tests for Enumeration-to-Iterator conversion.
+ * @run testng EnumerationAsIterator
+ */
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Supplier;
+
+import static org.testng.Assert.*;
+
+@Test
+public class EnumerationAsIterator {
+    static Object[] of(String description, Supplier<Enumeration<?>> s, Collection<?> exp) {
+        return new Object[]{description, s, exp};
+    }
+
+    static Object[] of(String description, Collection<?> c, Collection<?> exp) {
+        return of(description, () -> Collections.enumeration(c), exp);
+    }
+
+    /**
+     * A wrapper Enumeration that doesn't override the
+     * default method on Enumeration.
+     */
+    static <T> Enumeration<T> wrapInDefault(Enumeration<T> e) {
+        return new Enumeration<>() {
+            @Override
+            public boolean hasMoreElements() {
+                return e.hasMoreElements();
+            }
+
+            @Override
+            public T nextElement() {
+                return e.nextElement();
+            }
+        };
+    }
+
+    @DataProvider
+    public static Iterator<Object[]> unmodifiable() {
+        return Arrays.asList(
+            of("Default-wrapped ArrayList",
+               () -> wrapInDefault(
+                   Collections.enumeration(new ArrayList<>(Arrays.asList("a")))),
+               Arrays.asList("a")),
+
+            of("Unmodifiable ArrayList",
+               Collections.unmodifiableList(new ArrayList<>(Arrays.asList("a"))),
+               Arrays.asList("a")),
+
+            of("Modifiable ArrayList",
+               new ArrayList<>(Arrays.asList("a")),
+               Arrays.asList("a"))
+        ).iterator();
+    }
+
+    @DataProvider
+    public static Iterator<Object[]> others() {
+        return Arrays.asList(
+            of("Default Collections.emptyEnumeration()",
+               () -> wrapInDefault(Collections.emptyEnumeration()),
+               Collections.emptyList()),
+
+            of("Collections.emptyEnumeration()",
+               Collections::emptyEnumeration,
+               Collections.emptyList()),
+
+            of("Collections.emptyList()",
+               Collections.emptyList(),
+               Collections.emptyList()),
+
+            of("Collections.singletonList()",
+               Collections.singletonList("a"),
+               Collections.singletonList("a")),
+
+            of("Arrays.asList(...)",
+               Arrays.asList("a", "b", "c"),
+               Arrays.asList("a", "b", "c"))
+        ).iterator();
+    }
+
+    @DataProvider
+    public static Iterator<Object[]> all() {
+        List<Object[]> all = new ArrayList<>();
+        unmodifiable().forEachRemaining(all::add);
+        others().forEachRemaining(all::add);
+        return all.iterator();
+    }
+
+    @Test(dataProvider = "all")
+    public void consumeByNext(String description, Supplier<Enumeration<?>> s, Collection<?> exp) {
+        Iterator<?> i = s.get().asIterator();
+        int count = 0;
+        while (i.hasNext()) {
+            assertTrue(i.hasNext());
+
+            i.next();
+            count++;
+        }
+        assertEquals(count, exp.size());
+
+        assertFalse(i.hasNext());
+
+        try {
+            i.next();
+            fail();
+        } catch (NoSuchElementException e) {
+        }
+    }
+
+    @Test(dataProvider = "all")
+    public void consumeByForEachRemaining(String description,
+                                          Supplier<Enumeration<?>> s,
+                                          Collection<?> exp) {
+        Iterator<?> i = s.get().asIterator();
+        AtomicInteger ai = new AtomicInteger();
+        i.forEachRemaining(e -> ai.getAndIncrement());
+        assertEquals(ai.get(), exp.size());
+        i.forEachRemaining(e -> ai.getAndIncrement());
+        assertEquals(ai.get(), exp.size());
+
+        assertFalse(i.hasNext());
+
+        try {
+            i.next();
+            fail();
+        } catch (NoSuchElementException e) {
+        }
+    }
+
+    @Test(dataProvider = "all")
+    public void consumeByNextThenForEachRemaining(String description,
+                                                  Supplier<Enumeration<?>> s,
+                                                  Collection<?> exp) {
+        Iterator<?> i = s.get().asIterator();
+        AtomicInteger ai = new AtomicInteger();
+        if (i.hasNext()) {
+            i.next();
+            ai.getAndIncrement();
+        }
+        i.forEachRemaining(e -> ai.getAndIncrement());
+        assertEquals(ai.get(), exp.size());
+        i.forEachRemaining(e -> ai.getAndIncrement());
+        assertEquals(ai.get(), exp.size());
+
+        assertFalse(i.hasNext());
+
+        try {
+            i.next();
+            fail();
+        } catch (NoSuchElementException e) {
+        }
+    }
+
+    @Test(dataProvider = "all")
+    public void contents(String description, Supplier<Enumeration<?>> s, Collection<?> exp) {
+        assertEquals(copy(s.get()), exp);
+    }
+
+    private List<?> copy(Enumeration<?> input) {
+        List<Object> output = new ArrayList<>();
+        input.asIterator().forEachRemaining(output::add);
+        return output;
+    }
+
+    @Test(dataProvider = "unmodifiable",
+          expectedExceptions=UnsupportedOperationException.class)
+    public void removeThrowsAfterAdvancingE(String description,
+                                            Supplier<Enumeration<?>> s,
+                                            Collection<?> exp) {
+        Enumeration<?> e = s.get();
+        e.nextElement();
+        e.asIterator().remove();
+    }
+
+    @Test(dataProvider = "unmodifiable",
+          expectedExceptions=UnsupportedOperationException.class)
+    public void removeThrowsAfterAdvancingI(String description,
+                                            Supplier<Enumeration<?>> s,
+                                            Collection<?> exp) {
+        Iterator<?> i = s.get().asIterator();
+        i.next();
+        i.remove();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/net/ssl/DTLS/CipherSuite.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 8043758
+ * @summary Datagram Transport Layer Security (DTLS)
+ * @compile DTLSOverDatagram.java
+ * @run main/othervm CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA
+ * @run main/othervm CipherSuite TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
+ * @run main/othervm CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA256
+ * @run main/othervm CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
+ * @run main/othervm CipherSuite TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
+ * @run main/othervm CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_SHA
+ * @run main/othervm CipherSuite TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
+ * @run main/othervm CipherSuite TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+ * @run main/othervm CipherSuite TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+ * @run main/othervm CipherSuite TLS_RSA_WITH_AES_128_GCM_SHA256
+ * @run main/othervm CipherSuite TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
+ * @run main/othervm CipherSuite TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
+ * @run main/othervm CipherSuite TLS_DHE_DSS_WITH_AES_128_GCM_SHA256
+ * @run main/othervm CipherSuite TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
+ */
+
+import javax.net.ssl.SSLEngine;
+
+/**
+ * Test common DTLS cipher suites.
+ */
+public class CipherSuite extends DTLSOverDatagram {
+
+    // use the specific cipher suite
+    volatile static String cipherSuite;
+
+    public static void main(String[] args) throws Exception {
+        cipherSuite = args[0];
+
+        CipherSuite testCase = new CipherSuite();
+        testCase.runTest(testCase);
+    }
+
+    @Override
+    SSLEngine createSSLEngine(boolean isClient) throws Exception {
+        SSLEngine engine = super.createSSLEngine(isClient);
+
+        if (isClient) {
+            engine.setEnabledCipherSuites(new String[]{cipherSuite});
+        }
+
+        return engine;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/net/ssl/DTLS/ClientAuth.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 8043758
+ * @summary Datagram Transport Layer Security (DTLS)
+ * @compile DTLSOverDatagram.java
+ * @run main/othervm ClientAuth
+ */
+
+import javax.net.ssl.SSLEngine;
+
+/**
+ * Test DTLS client authentication.
+ */
+public class ClientAuth extends DTLSOverDatagram {
+
+    public static void main(String[] args) throws Exception {
+        ClientAuth testCase = new ClientAuth();
+        testCase.runTest(testCase);
+    }
+
+    @Override
+    SSLEngine createSSLEngine(boolean isClient) throws Exception {
+        SSLEngine engine = super.createSSLEngine(isClient);
+
+        if (!isClient) {
+            engine.setNeedClientAuth(true);
+        }
+
+        return engine;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/net/ssl/DTLS/DTLSOverDatagram.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,602 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 8043758
+ * @summary Datagram Transport Layer Security (DTLS)
+ * @run main/othervm DTLSOverDatagram
+ */
+
+import java.io.*;
+import java.nio.*;
+import java.net.*;
+import java.util.*;
+import java.security.*;
+import java.security.cert.*;
+import javax.net.ssl.*;
+import java.util.concurrent.*;
+
+import sun.misc.HexDumpEncoder;
+
+/**
+ * An example to show the way to use SSLEngine in datagram connections.
+ */
+public class DTLSOverDatagram {
+    private static int MAX_HANDSHAKE_LOOPS = 60;
+    private static int MAX_APP_READ_LOOPS = 10;
+
+    /*
+     * The following is to set up the keystores.
+     */
+    private static String pathToStores = "../etc";
+    private static String keyStoreFile = "keystore";
+    private static String trustStoreFile = "truststore";
+    private static String passwd = "passphrase";
+
+    private static String keyFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + keyStoreFile;
+    private static String trustFilename =
+            System.getProperty("test.src", ".") + "/" + pathToStores +
+                "/" + trustStoreFile;
+    private static Exception clientException = null;
+    private static Exception serverException = null;
+
+    private static ByteBuffer serverApp =
+                ByteBuffer.wrap("Hi Client, I'm Server".getBytes());
+    private static ByteBuffer clientApp =
+                ByteBuffer.wrap("Hi Server, I'm Client".getBytes());
+
+    /*
+     * =============================================================
+     * The test case
+     */
+    public static void main(String[] args) throws Exception {
+        DTLSOverDatagram testCase = new DTLSOverDatagram();
+        testCase.runTest(testCase);
+    }
+
+    /*
+     * Define the server side of the test.
+     */
+    void doServerSide() throws Exception {
+        DatagramSocket socket = serverDatagramSocket;
+        socket.setSoTimeout(10000);   // 10 second
+
+        // create SSLEngine
+        SSLEngine engine = createSSLEngine(false);
+
+        // handshaking
+        handshake(engine, socket, clientSocketAddr);
+
+        // read client application data
+        receiveAppData(engine, socket, clientApp);
+
+        // write server application data
+        deliverAppData(engine, socket, serverApp, clientSocketAddr);
+
+        socket.close();
+    }
+
+    /*
+     * Define the client side of the test.
+     */
+    void doClientSide() throws Exception {
+        DatagramSocket socket = clientDatagramSocket;
+        socket.setSoTimeout(1000);     // 1 second read timeout
+
+        // create SSLEngine
+        SSLEngine engine = createSSLEngine(true);
+
+        // handshaking
+        handshake(engine, socket, serverSocketAddr);
+
+        // write client application data
+        deliverAppData(engine, socket, clientApp, serverSocketAddr);
+
+        // read server application data
+        receiveAppData(engine, socket, serverApp);
+    }
+
+    /*
+     * =============================================================
+     * The remainder is support stuff for DTLS operations.
+     */
+    SSLEngine createSSLEngine(boolean isClient) throws Exception {
+        SSLContext context = getDTLSContext();
+        SSLEngine engine = context.createSSLEngine();
+
+        SSLParameters paras = engine.getSSLParameters();
+        paras.setMaximumPacketSize(1024);
+
+        engine.setUseClientMode(isClient);
+        engine.setSSLParameters(paras);
+
+        return engine;
+    }
+
+    // handshake
+    void handshake(SSLEngine engine, DatagramSocket socket,
+            SocketAddress peerAddr) throws Exception {
+
+        boolean endLoops = false;
+        int loops = MAX_HANDSHAKE_LOOPS;
+        engine.beginHandshake();
+        while (!endLoops &&
+                (serverException == null) && (clientException == null)) {
+
+            if (--loops < 0) {
+                throw new RuntimeException(
+                        "Too much loops to produce handshake packets");
+            }
+
+            SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus();
+            if (hs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP ||
+                hs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP_AGAIN) {
+
+                ByteBuffer iNet;
+                ByteBuffer iApp;
+                if (hs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP) {
+                    // receive ClientHello request and other SSL/TLS records
+                    byte[] buf = new byte[1024];
+                    DatagramPacket packet = new DatagramPacket(buf, buf.length);
+                    try {
+                        socket.receive(packet);
+                    } catch (SocketTimeoutException ste) {
+                        List<DatagramPacket> packets =
+                                onReceiveTimeout(engine, peerAddr);
+                        for (DatagramPacket p : packets) {
+                            socket.send(p);
+                        }
+
+                        continue;
+                    }
+
+                    iNet = ByteBuffer.wrap(buf, 0, packet.getLength());
+                    iApp = ByteBuffer.allocate(1024);
+                } else {
+                    iNet = ByteBuffer.allocate(0);
+                    iApp = ByteBuffer.allocate(1024);
+                }
+
+                SSLEngineResult r = engine.unwrap(iNet, iApp);
+                SSLEngineResult.Status rs = r.getStatus();
+                hs = r.getHandshakeStatus();
+                if (rs == SSLEngineResult.Status.BUFFER_OVERFLOW) {
+                    // the client maximum fragment size config does not work?
+                    throw new Exception("Buffer overflow: " +
+                        "incorrect client maximum fragment size");
+                } else if (rs == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
+                    // bad packet, or the client maximum fragment size
+                    // config does not work?
+                    if (hs != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
+                        throw new Exception("Buffer underflow: " +
+                            "incorrect client maximum fragment size");
+                    } // otherwise, ignore this packet
+                } else if (rs == SSLEngineResult.Status.CLOSED) {
+                    endLoops = true;
+                }   // otherwise, SSLEngineResult.Status.OK:
+
+                if (rs != SSLEngineResult.Status.OK) {
+                    continue;
+                }
+            } else if (hs == SSLEngineResult.HandshakeStatus.NEED_WRAP) {
+                List<DatagramPacket> packets =
+                        produceHandshakePackets(engine, peerAddr);
+                for (DatagramPacket p : packets) {
+                    socket.send(p);
+                }
+            } else if (hs == SSLEngineResult.HandshakeStatus.NEED_TASK) {
+                runDelegatedTasks(engine);
+            } else if (hs == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
+                // OK, time to do application data exchange.
+                endLoops = true;
+            } else if (hs == SSLEngineResult.HandshakeStatus.FINISHED) {
+                endLoops = true;
+            }
+        }
+
+        SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus();
+        if (hs != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
+            throw new Exception("Not ready for application data yet");
+        }
+    }
+
+    // deliver application data
+    void deliverAppData(SSLEngine engine, DatagramSocket socket,
+            ByteBuffer appData, SocketAddress peerAddr) throws Exception {
+
+        // Note: have not consider the packet loses
+        List<DatagramPacket> packets =
+                produceApplicationPackets(engine, appData, peerAddr);
+        appData.flip();
+        for (DatagramPacket p : packets) {
+            socket.send(p);
+        }
+    }
+
+    // receive application data
+    void receiveAppData(SSLEngine engine,
+            DatagramSocket socket, ByteBuffer expectedApp) throws Exception {
+
+        int loops = MAX_APP_READ_LOOPS;
+        while ((serverException == null) && (clientException == null)) {
+            if (--loops < 0) {
+                throw new RuntimeException(
+                        "Too much loops to receive application data");
+            }
+
+            byte[] buf = new byte[1024];
+            DatagramPacket packet = new DatagramPacket(buf, buf.length);
+            socket.receive(packet);
+            ByteBuffer netBuffer = ByteBuffer.wrap(buf, 0, packet.getLength());
+            ByteBuffer recBuffer = ByteBuffer.allocate(1024);
+            SSLEngineResult rs = engine.unwrap(netBuffer, recBuffer);
+            recBuffer.flip();
+            if (recBuffer.remaining() != 0) {
+                printHex("Received application data", recBuffer);
+                if (!recBuffer.equals(expectedApp)) {
+                    System.out.println("Engine status is " + rs);
+                    throw new Exception("Not the right application data");
+                }
+                break;
+            }
+        }
+    }
+
+    // produce handshake packets
+    List<DatagramPacket> produceHandshakePackets(
+            SSLEngine engine, SocketAddress socketAddr) throws Exception {
+
+        List<DatagramPacket> packets = new ArrayList<>();
+        boolean endLoops = false;
+        int loops = MAX_HANDSHAKE_LOOPS;
+        while (!endLoops &&
+                (serverException == null) && (clientException == null)) {
+
+            if (--loops < 0) {
+                throw new RuntimeException(
+                        "Too much loops to produce handshake packets");
+            }
+
+            ByteBuffer oNet = ByteBuffer.allocate(32768);
+            ByteBuffer oApp = ByteBuffer.allocate(0);
+            SSLEngineResult r = engine.wrap(oApp, oNet);
+            oNet.flip();
+
+            SSLEngineResult.Status rs = r.getStatus();
+            SSLEngineResult.HandshakeStatus hs = r.getHandshakeStatus();
+            if (rs == SSLEngineResult.Status.BUFFER_OVERFLOW) {
+                // the client maximum fragment size config does not work?
+                throw new Exception("Buffer overflow: " +
+                            "incorrect server maximum fragment size");
+            } else if (rs == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
+                // bad packet, or the client maximum fragment size
+                // config does not work?
+                if (hs != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
+                    throw new Exception("Buffer underflow: " +
+                            "incorrect server maximum fragment size");
+                } // otherwise, ignore this packet
+            } else if (rs == SSLEngineResult.Status.CLOSED) {
+                throw new Exception("SSLEngine has closed");
+            }   // otherwise, SSLEngineResult.Status.OK
+
+            // SSLEngineResult.Status.OK:
+            if (oNet.hasRemaining()) {
+                byte[] ba = new byte[oNet.remaining()];
+                oNet.get(ba);
+                DatagramPacket packet = createHandshakePacket(ba, socketAddr);
+                packets.add(packet);
+            }
+            boolean endInnerLoop = false;
+            SSLEngineResult.HandshakeStatus nhs = hs;
+            while (!endInnerLoop) {
+                if (nhs == SSLEngineResult.HandshakeStatus.NEED_TASK) {
+                    runDelegatedTasks(engine);
+                    nhs = engine.getHandshakeStatus();
+                } else if ((nhs == SSLEngineResult.HandshakeStatus.FINISHED) ||
+                    (nhs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP) ||
+                    (nhs == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING)) {
+
+                    endInnerLoop = true;
+                    endLoops = true;
+                } else if (nhs == SSLEngineResult.HandshakeStatus.NEED_WRAP) {
+                    endInnerLoop = true;
+                }
+            }
+        }
+
+        return packets;
+    }
+
+    DatagramPacket createHandshakePacket(byte[] ba, SocketAddress socketAddr) {
+        return new DatagramPacket(ba, ba.length, socketAddr);
+    }
+
+    // produce application packets
+    List<DatagramPacket> produceApplicationPackets(
+            SSLEngine engine, ByteBuffer source,
+            SocketAddress socketAddr) throws Exception {
+
+        List<DatagramPacket> packets = new ArrayList<>();
+        ByteBuffer appNet = ByteBuffer.allocate(32768);
+        SSLEngineResult r = engine.wrap(source, appNet);
+        appNet.flip();
+
+        SSLEngineResult.Status rs = r.getStatus();
+        if (rs == SSLEngineResult.Status.BUFFER_OVERFLOW) {
+            // the client maximum fragment size config does not work?
+            throw new Exception("Buffer overflow: " +
+                        "incorrect server maximum fragment size");
+        } else if (rs == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
+            // unlikely
+            throw new Exception("Buffer underflow during wraping");
+        } else if (rs == SSLEngineResult.Status.CLOSED) {
+                throw new Exception("SSLEngine has closed");
+        }   // otherwise, SSLEngineResult.Status.OK
+
+        // SSLEngineResult.Status.OK:
+        if (appNet.hasRemaining()) {
+            byte[] ba = new byte[appNet.remaining()];
+            appNet.get(ba);
+            DatagramPacket packet =
+                    new DatagramPacket(ba, ba.length, socketAddr);
+            packets.add(packet);
+        }
+
+        return packets;
+    }
+
+    // run delegated tasks
+    void runDelegatedTasks(SSLEngine engine) throws Exception {
+        Runnable runnable;
+        while ((runnable = engine.getDelegatedTask()) != null) {
+            runnable.run();
+        }
+
+        SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus();
+        if (hs == SSLEngineResult.HandshakeStatus.NEED_TASK) {
+            throw new Exception("handshake shouldn't need additional tasks");
+        }
+    }
+
+    // retransmission if timeout
+    List<DatagramPacket> onReceiveTimeout(
+            SSLEngine engine, SocketAddress socketAddr) throws Exception {
+
+        SSLEngineResult.HandshakeStatus hs = engine.getHandshakeStatus();
+        if (hs == SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) {
+            return new ArrayList<DatagramPacket>();
+        } else {
+            // retransmission of handshake messages
+            return produceHandshakePackets(engine, socketAddr);
+        }
+    }
+
+    // get DTSL context
+    SSLContext getDTLSContext() throws Exception {
+        KeyStore ks = KeyStore.getInstance("JKS");
+        KeyStore ts = KeyStore.getInstance("JKS");
+
+        char[] passphrase = "passphrase".toCharArray();
+
+        ks.load(new FileInputStream(keyFilename), passphrase);
+        ts.load(new FileInputStream(trustFilename), passphrase);
+
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
+        kmf.init(ks, passphrase);
+
+        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
+        tmf.init(ts);
+
+        SSLContext sslCtx = SSLContext.getInstance("DTLS");
+
+        sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+
+        return sslCtx;
+    }
+
+
+    /*
+     * =============================================================
+     * The remainder is support stuff to kickstart the testing.
+     */
+
+    // the server side SocketAddress
+    volatile static SocketAddress serverSocketAddr = null;
+
+    // the client side SocketAddress
+    volatile static SocketAddress clientSocketAddr = null;
+
+    // the server side DatagramSocket instance
+    volatile static DatagramSocket serverDatagramSocket = null;
+
+    // the server side DatagramSocket instance
+    volatile static DatagramSocket clientDatagramSocket = null;
+
+    // get server side SocketAddress object
+    public SocketAddress getServerSocketAddress() {
+        return serverSocketAddr;
+    }
+
+    // get client side SocketAddress object
+    public SocketAddress getClientSocketAddress() {
+        return clientSocketAddr;
+    }
+
+    // get server side DatagramSocket object
+    public DatagramSocket getServerDatagramSocket() {
+        return serverDatagramSocket;
+    }
+
+    // get client side DatagramSocket object
+    public DatagramSocket getClientDatagramSocket() {
+        return clientDatagramSocket;
+    }
+
+    // Will the handshaking and application data exchange succeed?
+    public boolean isGoodJob() {
+        return true;
+    }
+
+    public final void runTest(DTLSOverDatagram testCase) throws Exception {
+        serverDatagramSocket = new DatagramSocket();
+        serverSocketAddr = new InetSocketAddress(
+            InetAddress.getLocalHost(), serverDatagramSocket.getLocalPort());
+
+        clientDatagramSocket = new DatagramSocket();
+        clientSocketAddr = new InetSocketAddress(
+            InetAddress.getLocalHost(), clientDatagramSocket.getLocalPort());
+
+        ExecutorService pool = Executors.newFixedThreadPool(2);
+        List<Future<String>> list = new ArrayList<Future<String>>();
+
+        try {
+            list.add(pool.submit(new ServerCallable(testCase)));  // server task
+            list.add(pool.submit(new ClientCallable(testCase)));  // client task
+        } finally {
+            pool.shutdown();
+        }
+
+        Exception reserved = null;
+        for (Future<String> fut : list) {
+            try {
+                System.out.println(fut.get());
+            } catch (CancellationException |
+                    InterruptedException | ExecutionException cie) {
+                if (reserved != null) {
+                    cie.addSuppressed(reserved);
+                    reserved = cie;
+                } else {
+                    reserved = cie;
+                }
+            }
+        }
+
+        if (reserved != null) {
+            throw reserved;
+        }
+    }
+
+    final static class ServerCallable implements Callable<String> {
+        DTLSOverDatagram testCase;
+
+        ServerCallable(DTLSOverDatagram testCase) {
+            this.testCase = testCase;
+        }
+
+        @Override
+        public String call() throws Exception {
+            try {
+                testCase.doServerSide();
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                serverException = e;
+
+                if (testCase.isGoodJob()) {
+                    throw e;
+                } else {
+                    return "Well done, server!";
+                }
+            } finally {
+                if (serverDatagramSocket != null) {
+                    serverDatagramSocket.close();
+                }
+            }
+
+            if (testCase.isGoodJob()) {
+                return "Well done, server!";
+            } else {
+                throw new Exception("No expected exception");
+            }
+        }
+    }
+
+    final static class ClientCallable implements Callable<String> {
+        DTLSOverDatagram testCase;
+
+        ClientCallable(DTLSOverDatagram testCase) {
+            this.testCase = testCase;
+        }
+
+        @Override
+        public String call() throws Exception {
+            try {
+                testCase.doClientSide();
+            } catch (Exception e) {
+                e.printStackTrace(System.out);
+                clientException = e;
+                if (testCase.isGoodJob()) {
+                    throw e;
+                } else {
+                    return "Well done, client!";
+                }
+            } finally {
+                if (clientDatagramSocket != null) {
+                    clientDatagramSocket.close();
+                }
+            }
+
+            if (testCase.isGoodJob()) {
+                return "Well done, client!";
+            } else {
+                throw new Exception("No expected exception");
+            }
+        }
+    }
+
+    final static void printHex(String prefix, ByteBuffer bb) {
+        HexDumpEncoder  dump = new HexDumpEncoder();
+
+        synchronized (System.out) {
+            System.out.println(prefix);
+            try {
+                dump.encodeBuffer(bb.slice(), System.out);
+            } catch (Exception e) {
+                // ignore
+            }
+            System.out.flush();
+        }
+    }
+
+    final static void printHex(String prefix,
+            byte[] bytes, int offset, int length) {
+
+        HexDumpEncoder  dump = new HexDumpEncoder();
+
+        synchronized (System.out) {
+            System.out.println(prefix);
+            try {
+                ByteBuffer bb = ByteBuffer.wrap(bytes, offset, length);
+                dump.encodeBuffer(bb, System.out);
+            } catch (Exception e) {
+                // ignore
+            }
+            System.out.flush();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/net/ssl/DTLS/InvalidCookie.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 8043758
+ * @summary Datagram Transport Layer Security (DTLS)
+ * @compile DTLSOverDatagram.java
+ * @run main/othervm InvalidCookie
+ */
+
+import java.net.DatagramPacket;
+import java.net.SocketAddress;
+
+/**
+ * Test that if the handshake cookie in client side is incorrect, the handshake
+ * process can continue as if the client does not use cookie.
+ */
+public class InvalidCookie extends DTLSOverDatagram {
+    boolean needInvalidCookie = true;
+
+    public static void main(String[] args) throws Exception {
+        InvalidCookie testCase = new InvalidCookie();
+        testCase.runTest(testCase);
+    }
+
+    @Override
+    DatagramPacket createHandshakePacket(byte[] ba, SocketAddress socketAddr) {
+        if (needInvalidCookie && (ba.length >= 60) &&
+                (ba[0] == (byte)0x16) && (ba[13] == (byte)0x03)) {
+            // HelloVerifyRequest
+            needInvalidCookie = false;
+            System.out.println("invalidate handshake verify cookie");
+            if (ba[ba.length - 1] == (byte)0xFF) {
+                ba[ba.length - 1] = (byte)0xFE;
+            } else {
+                ba[ba.length - 1] = (byte)0xFF;
+            }
+        }
+
+        return super.createHandshakePacket(ba, socketAddr);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/net/ssl/DTLS/InvalidRecords.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 8043758
+ * @summary Datagram Transport Layer Security (DTLS)
+ * @compile DTLSOverDatagram.java
+ * @run main/othervm InvalidRecords
+ */
+
+import java.net.DatagramPacket;
+import java.net.SocketAddress;
+
+/**
+ * Test that if handshake messages are crasged, the handshake would fail
+ * because of handshaking hash verification.
+ */
+public class InvalidRecords extends DTLSOverDatagram {
+    boolean needInvalidRecords = true;
+
+    public static void main(String[] args) throws Exception {
+        InvalidRecords testCase = new InvalidRecords();
+        testCase.runTest(testCase);
+    }
+
+    @Override
+    public boolean isGoodJob() {
+        return false;
+    }
+
+    @Override
+    DatagramPacket createHandshakePacket(byte[] ba, SocketAddress socketAddr) {
+        if (needInvalidRecords && (ba.length >= 60) &&
+                (ba[0x00] == (byte)0x16) && (ba[0x0D] == (byte)0x01) &&
+                (ba[0x3B] == (byte)0x00) && (ba[0x3C] > 0)) {
+
+            // ba[0x00]: record type
+            // ba[0x0D]: handshake type
+            // ba[0x3B]: length of session ID
+            // ba[0x3C]: length of cookie
+
+            // ClientHello with cookie
+            needInvalidRecords = false;
+            System.out.println("invalidate ClientHello message");
+            if (ba[ba.length - 1] == (byte)0xFF) {
+                ba[ba.length - 1] = (byte)0xFE;
+            } else {
+                ba[ba.length - 1] = (byte)0xFF;
+            }
+        }
+
+        return super.createHandshakePacket(ba, socketAddr);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/net/ssl/DTLS/NoMacInitialClientHello.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 8043758
+ * @summary Datagram Transport Layer Security (DTLS)
+ * @compile DTLSOverDatagram.java
+ * @run main/othervm NoMacInitialClientHello
+ */
+
+import java.net.DatagramPacket;
+import java.net.SocketAddress;
+
+/**
+ * Test that a server is able to discard invalid initial ClientHello silently.
+ */
+public class NoMacInitialClientHello extends DTLSOverDatagram {
+    boolean needInvalidRecords = true;
+
+    public static void main(String[] args) throws Exception {
+        NoMacInitialClientHello testCase = new NoMacInitialClientHello();
+        testCase.runTest(testCase);
+    }
+
+    @Override
+    DatagramPacket createHandshakePacket(byte[] ba, SocketAddress socketAddr) {
+        if (needInvalidRecords && (ba.length >= 60) &&
+            (ba[0] == (byte)0x16) && (ba[13] == (byte)0x01)) {  // ClientHello
+
+            needInvalidRecords = false;
+            System.out.println("invalidate ClientHello message");
+            if (ba[ba.length - 1] == (byte)0xFF) {
+                ba[ba.length - 1] = (byte)0xFE;
+            } else {
+                ba[ba.length - 1] = (byte)0xFF;
+            }
+        }
+
+        return super.createHandshakePacket(ba, socketAddr);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/net/ssl/DTLS/Reordered.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 8043758
+ * @summary Datagram Transport Layer Security (DTLS)
+ * @compile DTLSOverDatagram.java
+ * @run main/othervm Reordered
+ */
+
+import java.util.List;
+import java.util.Collections;
+import java.net.DatagramPacket;
+import java.net.SocketAddress;
+import javax.net.ssl.SSLEngine;
+
+/**
+ * Test that DTLS implementation is able to reorder data traffic.
+ */
+public class Reordered extends DTLSOverDatagram {
+    boolean needPacketReorder = true;
+
+    public static void main(String[] args) throws Exception {
+        Reordered testCase = new Reordered();
+        testCase.runTest(testCase);
+    }
+
+    @Override
+    List<DatagramPacket> produceHandshakePackets(
+            SSLEngine engine, SocketAddress socketAddr) throws Exception {
+        List<DatagramPacket> packets =
+                super.produceHandshakePackets(engine, socketAddr);
+
+        if (needPacketReorder && (!engine.getUseClientMode())) {
+            needPacketReorder = false;
+            Collections.reverse(packets);
+        }
+
+        return packets;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/net/ssl/DTLS/Retransmission.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 8043758
+ * @summary Datagram Transport Layer Security (DTLS)
+ * @compile DTLSOverDatagram.java
+ * @run main/othervm Retransmission
+ */
+
+import java.util.List;
+import java.util.ArrayList;
+import java.net.DatagramPacket;
+import java.net.SocketAddress;
+import javax.net.ssl.SSLEngine;
+
+/**
+ * Test that DTLS implementation is able to do retransmission internally
+ * automatically if packet get lost.
+ */
+public class Retransmission extends DTLSOverDatagram {
+    boolean needPacketLoss = true;
+
+    public static void main(String[] args) throws Exception {
+        Retransmission testCase = new Retransmission();
+        testCase.runTest(testCase);
+    }
+
+    @Override
+    List<DatagramPacket> produceHandshakePackets(
+            SSLEngine engine, SocketAddress socketAddr) throws Exception {
+        List<DatagramPacket> packets =
+                super.produceHandshakePackets(engine, socketAddr);
+
+        if (!needPacketLoss || (!engine.getUseClientMode())) {
+            return packets;
+        }
+
+        List<DatagramPacket> parts = new ArrayList<>();
+        int lostSeq = 2;
+        for (DatagramPacket packet : packets) {
+            lostSeq--;
+            if (lostSeq == 0) {
+                needPacketLoss = false;
+                // loss this packet
+                System.out.println("Loss a packet");
+                continue;
+            }
+
+            parts.add(packet);
+        }
+
+        return parts;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/net/ssl/DTLS/WeakCipherSuite.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+
+/*
+ * @test
+ * @bug 8043758
+ * @summary Datagram Transport Layer Security (DTLS)
+ * @compile DTLSOverDatagram.java
+ * @run main/othervm WeakCipherSuite TLS_DH_anon_WITH_AES_128_GCM_SHA256
+ * @run main/othervm WeakCipherSuite SSL_DH_anon_WITH_DES_CBC_SHA
+ * @run main/othervm WeakCipherSuite SSL_RSA_WITH_DES_CBC_SHA
+ * @run main/othervm WeakCipherSuite SSL_DHE_RSA_WITH_DES_CBC_SHA
+ * @run main/othervm WeakCipherSuite SSL_DHE_DSS_WITH_DES_CBC_SHA
+ */
+
+import javax.net.ssl.SSLEngine;
+import java.security.Security;
+
+/**
+ * Test common DTLS weak cipher suites.
+ */
+public class WeakCipherSuite extends DTLSOverDatagram {
+
+    // use the specific cipher suite
+    volatile static String cipherSuite;
+
+    public static void main(String[] args) throws Exception {
+        // reset security properties to make sure that the algorithms
+        // and keys used in this test are not disabled.
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+        Security.setProperty("jdk.certpath.disabledAlgorithms", "");
+
+        cipherSuite = args[0];
+
+        WeakCipherSuite testCase = new WeakCipherSuite();
+        testCase.runTest(testCase);
+    }
+
+    @Override
+    SSLEngine createSSLEngine(boolean isClient) throws Exception {
+        SSLEngine engine = super.createSSLEngine(isClient);
+        engine.setEnabledCipherSuites(new String[]{cipherSuite});
+
+        return engine;
+    }
+}
--- a/jdk/test/javax/net/ssl/SSLEngine/CheckStatus.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/javax/net/ssl/SSLEngine/CheckStatus.java	Wed Jul 05 20:37:09 2017 +0200
@@ -391,7 +391,7 @@
         appOut2.rewind();
 
         log("======================================");
-        log("Client Cert");
+        log("Client Cert and Key Exchange");
         result1 = ssle1.wrap(appOut1, oneToTwo);
         checkResult(appOut1, oneToTwo, result1,
              Status.OK, HandshakeStatus.NEED_WRAP, 0, -1);
@@ -406,22 +406,6 @@
         oneToTwo.compact();
 
         log("======================================");
-        log("Key Exchange");
-        result1 = ssle1.wrap(appOut1, oneToTwo);
-        checkResult(appOut1, oneToTwo, result1,
-             Status.OK, HandshakeStatus.NEED_WRAP, 0, -1);
-
-        oneToTwo.flip();
-        result2 = ssle2.unwrap(oneToTwo, appIn2);
-
-        checkResult(oneToTwo, appIn2, result2,
-             Status.OK, HandshakeStatus.NEED_TASK,
-             result1.bytesProduced(), 0);
-        runDelegatedTasks(ssle2);
-
-        oneToTwo.compact();
-
-        log("======================================");
         log("CCS");
         result1 = ssle1.wrap(appOut1, oneToTwo);
         checkResult(appOut1, oneToTwo, result1,
--- a/jdk/test/javax/net/ssl/SSLEngine/LargeBufs.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/javax/net/ssl/SSLEngine/LargeBufs.java	Wed Jul 05 20:37:09 2017 +0200
@@ -116,7 +116,7 @@
             if ((result2.bytesConsumed() != 0) &&
                 (result2.bytesConsumed() != appBufferMax) &&
                 (result2.bytesConsumed() != 2 * OFFSET)) {
-                throw new Exception("result1: " + result1);
+                throw new Exception("result2: " + result2);
             }
 
             log("wrap1:  " + result1);
--- a/jdk/test/javax/net/ssl/TLS/CipherTestUtils.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/javax/net/ssl/TLS/CipherTestUtils.java	Wed Jul 05 20:37:09 2017 +0200
@@ -406,6 +406,7 @@
                 return params;
             }).forEach((params) -> {
                 try {
+                    System.out.println("Testing " + params);
                     runTest(params);
                     System.out.println("Passed " + params);
                 } catch (Exception e) {
--- a/jdk/test/javax/net/ssl/TLSv11/ExportableBlockCipher.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/javax/net/ssl/TLSv11/ExportableBlockCipher.java	Wed Jul 05 20:37:09 2017 +0200
@@ -23,15 +23,16 @@
  * questions.
  */
 
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
 /*
  * @test
  * @bug 4873188
  * @summary Support TLS 1.1
  * @run main/othervm ExportableBlockCipher
- *
- *     SunJSSE does not support dynamic system properties, no way to re-use
- *     system properties in samevm/agentvm mode.
- *
  * @author Xuelei Fan
  */
 
@@ -109,7 +110,7 @@
             sslIS.read();
             sslOS.write('A');
             sslOS.flush();
-        } catch (SSLException ssle) {
+        } catch (IOException ioe) {
             // get the expected exception
             interrupted = true;
         } finally {
--- a/jdk/test/javax/net/ssl/TLSv11/ExportableStreamCipher.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/javax/net/ssl/TLSv11/ExportableStreamCipher.java	Wed Jul 05 20:37:09 2017 +0200
@@ -23,15 +23,16 @@
  * questions.
  */
 
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
 /*
  * @test
  * @bug 4873188
  * @summary Support TLS 1.1
  * @run main/othervm ExportableStreamCipher
- *
- *     SunJSSE does not support dynamic system properties, no way to re-use
- *     system properties in samevm/agentvm mode.
- *
  * @author Xuelei Fan
  */
 
@@ -109,7 +110,7 @@
             sslIS.read();
             sslOS.write('A');
             sslOS.flush();
-        } catch (SSLException ssle) {
+        } catch (IOException ioe) {
             // get the expected exception
             interrupted = true;
         } finally {
--- a/jdk/test/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java	Wed Jul 05 20:37:09 2017 +0200
@@ -139,6 +139,11 @@
      * Main entry point for this test.
      */
     public static void main(String args[]) throws Exception {
+        // reset security properties to make sure that the algorithms
+        // and keys used in this test are not disabled.
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+        Security.setProperty("jdk.certpath.disabledAlgorithms", "");
+
         if (debug) {
             System.setProperty("javax.net.debug", "all");
         }
@@ -153,7 +158,12 @@
              */
             SSLSocketSSLEngineTemplate test =
                 new SSLSocketSSLEngineTemplate(protocol);
+            log("-------------------------------------");
+            log("Testing " + protocol + " for direct buffers ...");
             test.runTest(true);
+
+            log("---------------------------------------");
+            log("Testing " + protocol + " for indirect buffers ...");
             test.runTest(false);
         }
 
@@ -329,6 +339,10 @@
                 thread.join();
             }
 
+            if (sslSocket != null) {
+                sslSocket.close();
+            }
+
             if (serverException != null) {
                 if (clientException != null) {
                     serverException.initCause(clientException);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/print/attribute/URLPDFPrinting.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2014, 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 4899773
+ * @summary Test for DocFlavor.URL.PDF support.  No exception should be thrown.
+ * @run main URLPDFPrinting
+*/
+
+import java.awt.*;
+import javax.print.*;
+import javax.print.attribute.standard.*;
+import javax.print.attribute.*;
+import java.io.*;
+import java.util.Locale;
+import java.net.URL;
+
+public class URLPDFPrinting {
+        /**
+         * Constructor
+         */
+         public URLPDFPrinting() {
+                super();
+        }
+        /**
+         * Starts the application.
+         */
+        public static void main(java.lang.String[] args) {
+                URLPDFPrinting pd = new URLPDFPrinting();
+                PrintService service[] = null, defService = null;
+
+                service = PrintServiceLookup.lookupPrintServices(DocFlavor.URL.PDF, null);
+                if (service.length == 0) {
+                        System.out.println("No PrintService support DocFlavor.URL.PDF");
+                        return;
+                } else {
+                        defService = service[0];
+                        System.out.println("Print Service which supports DocFlavor.URL.PDF: "+defService);
+                }
+
+                System.out.println("is DocFlavor.URL.PDF supported? "+defService.isDocFlavorSupported(DocFlavor.URL.PDF));
+                HashPrintRequestAttributeSet prSet = new HashPrintRequestAttributeSet();
+                prSet.add(new Destination(new File("./dest.prn").toURI()));
+
+                DocPrintJob pj = defService.createPrintJob();
+                PrintDocument prDoc = new PrintDocument();
+                try {
+                        pj.print(prDoc, prSet);
+                } catch (Exception e) {
+                        e.printStackTrace();
+                }
+
+        }
+}
+
+class PrintDocument implements Doc {
+        InputStream fStream = null;
+        DocFlavor flavor = null;
+        HashDocAttributeSet docSet = new HashDocAttributeSet();
+        URL url =  null;
+
+        public PrintDocument() {
+                try {
+                        url =  PrintDocument.class.getResource("hello.pdf");
+                        try{ Thread.sleep(6000); }catch(Exception e){ e.printStackTrace();}
+                        fStream = url.openStream();
+                        System.out.println("URL input stream "+fStream);
+                } catch(Exception e) {
+                        e.printStackTrace();
+                }
+                docSet.add(OrientationRequested.LANDSCAPE);
+        }
+
+        public DocAttributeSet getAttributes() {
+                System.out.println("getAttributes called");
+                return docSet;
+        }
+
+        public DocFlavor getDocFlavor() {
+                System.out.println("getDocFlavor called");
+                return DocFlavor.URL.PDF;
+        }
+
+        public Object getPrintData(){
+                System.out.println("getPrintData called");
+                return url;
+        }
+
+        public Reader getReaderForText() {
+                return null;
+        }
+
+        public InputStream getStreamForBytes() {
+                System.out.println("getStreamForBytes called");
+                return fStream;
+        }
+}
Binary file jdk/test/javax/print/attribute/hello.pdf has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/GroupLayout/8079640/bug8079640.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+   @bug 8079640
+   @summary GroupLayout incorrect layout with large JTextArea
+   @author Semyon Sadetsky
+  */
+
+
+import javax.swing.*;
+import java.awt.*;
+
+public class bug8079640 {
+
+    private static JFrame frame;
+    private static JComponent comp2;
+
+    public static void main(String[] args) throws Exception {
+
+        try {
+            SwingUtilities.invokeAndWait(new Runnable() {
+                @Override
+                public void run() {
+                    frame = new JFrame("A Frame");
+                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+                    frame.setUndecorated(true);
+                    setup(frame);
+                    frame.setVisible(true);
+                }
+            });
+
+            test();
+            System.out.println("ok");
+
+        } finally {
+            SwingUtilities.invokeLater(new Runnable() {
+                @Override
+                public void run() {
+                    frame.dispose();
+                }
+            });
+        }
+    }
+
+    private static void test() throws Exception {
+        SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                if(comp2.getLocation().getY() > frame.getHeight())
+                    throw new RuntimeException("GroupLayout fails: comp2 is out of the window");
+            }
+        });
+    }
+
+
+    static void setup(JFrame frame)  {
+        JPanel panel = new JPanel();
+        JComponent comp1 = new JLabel("Test Label 1");
+        comp1.setMinimumSize(new Dimension(1000, 40000));
+        comp1.setPreferredSize(new Dimension(1000, 40000));
+        JScrollPane scroll = new JScrollPane(comp1);
+        comp2 = new JLabel("Test Label 2");
+        GroupLayout layout = new GroupLayout(panel);
+        layout.setHorizontalGroup(
+                layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+                        .addComponent(scroll)
+                        .addComponent(comp2));
+        layout.setVerticalGroup(
+                layout.createSequentialGroup()
+                        .addComponent(scroll)
+                        .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+                        .addComponent(comp2));
+        panel.setLayout(layout);
+        frame.getContentPane().add(panel, BorderLayout.CENTER);
+        frame.setSize(800, 600);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/JComboBox/8033069/bug8033069NoScrollBar.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.awt.AWTException;
+import java.awt.Dimension;
+import java.awt.GridLayout;
+import java.awt.Point;
+import java.awt.Robot;
+import java.awt.event.InputEvent;
+import javax.swing.JComboBox;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.UIManager.LookAndFeelInfo;
+import javax.swing.UnsupportedLookAndFeelException;
+
+/* @test
+ * @bug 8033069
+ * @summary Checks that JComboBox popup does not close when mouse wheel is
+ *          rotated over combo box and over its popup. The case where popup
+ *          has no scroll bar.
+ * @library ../../regtesthelpers
+ * @build Util
+ * @run main bug8033069NoScrollBar
+ * @author Alexey Ivanov
+ */
+public class bug8033069NoScrollBar implements Runnable {
+
+    private static final String[] NO_SCROLL_ITEMS = new String[] {
+        "A", "B", "C", "D", "E", "F"
+    };
+
+    private final Robot robot;
+
+    private final String[] items;
+
+    private JFrame frame;
+    private JComboBox cb1;
+    private JComboBox cb2;
+
+    public static void main(String[] args) throws Exception {
+        iterateLookAndFeels(new bug8033069NoScrollBar(NO_SCROLL_ITEMS));
+    }
+
+    protected static void iterateLookAndFeels(final bug8033069NoScrollBar test) throws Exception {
+        LookAndFeelInfo[] lafInfo = UIManager.getInstalledLookAndFeels();
+        for (LookAndFeelInfo info : lafInfo) {
+            try {
+                UIManager.setLookAndFeel(info.getClassName());
+                System.out.println("Look and Feel: " + info.getClassName());
+                test.runTest();
+            } catch (UnsupportedLookAndFeelException e) {
+                System.out.println("Skipping unsupported LaF: " + info);
+            }
+        }
+    }
+
+    public bug8033069NoScrollBar(String[] items) throws AWTException {
+        this.items = items;
+
+        robot = new Robot();
+        robot.setAutoDelay(200);
+    }
+
+    private void setupUI() {
+        frame = new JFrame();
+        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+        cb1 = new JComboBox<>(items);
+        cb2 = new JComboBox<>(items);
+        JPanel panel = new JPanel(new GridLayout(1, 2));
+        panel.add(cb1);
+        panel.add(cb2);
+
+        frame.add(panel);
+
+        frame.pack();
+        frame.setVisible(true);
+    }
+
+    public void runTest() throws Exception {
+        try {
+            SwingUtilities.invokeAndWait(this);
+
+            robot.waitForIdle();
+            assertFalse("cb1 popup is visible",
+                        Util.invokeOnEDT(cb1::isPopupVisible));
+
+            // Move mouse pointer to the center of the fist combo box
+            Point p = cb1.getLocationOnScreen();
+            Dimension d = cb1.getSize();
+            robot.mouseMove(p.x + d.width / 2, p.y + d.height / 2);
+            // Click it to open popup
+            robot.mousePress(InputEvent.BUTTON1_MASK);
+            robot.mouseRelease(InputEvent.BUTTON1_MASK);
+
+            robot.waitForIdle();
+            assertTrue("cb1 popup is not visible",
+                       Util.invokeOnEDT(cb1::isPopupVisible));
+
+            robot.mouseWheel(1);
+            robot.waitForIdle();
+            assertTrue("cb1 popup is not visible after mouse wheel up on combo box",
+                       Util.invokeOnEDT(cb1::isPopupVisible));
+
+            robot.mouseWheel(-1);
+            robot.waitForIdle();
+            assertTrue("cb1 popup is not visible after mouse wheel down on combo box",
+                       Util.invokeOnEDT(cb1::isPopupVisible));
+
+            // Move mouse down on the popup
+            robot.mouseMove(p.x + d.width / 2, p.y + d.height * 3);
+
+            robot.mouseWheel(1);
+            robot.waitForIdle();
+            assertTrue("cb1 popup is not visible after mouse wheel up on popup",
+                       Util.invokeOnEDT(cb1::isPopupVisible));
+
+            robot.mouseWheel(-1);
+            robot.waitForIdle();
+            assertTrue("cb1 popup is not visible after mouse wheel down on popup",
+                       Util.invokeOnEDT(cb1::isPopupVisible));
+
+
+            // Move mouse pointer to the center of the second combo box
+            p = cb2.getLocationOnScreen();
+            d = cb2.getSize();
+            robot.mouseMove(p.x + d.width / 2, p.y + d.height / 2);
+
+            robot.mouseWheel(1);
+            robot.waitForIdle();
+            assertFalse("cb1 popup is visible after mouse wheel up on cb2",
+                        Util.invokeOnEDT(cb1::isPopupVisible));
+        } finally {
+            if (frame != null) {
+                frame.dispose();
+            }
+        }
+
+        System.out.println("Test passed");
+    }
+
+    @Override
+    public void run() {
+        setupUI();
+    }
+
+    private static void assertTrue(String message, boolean value) {
+        assertEquals(message, true, value);
+    }
+
+    private static void assertFalse(String message, boolean value) {
+        assertEquals(message, false, value);
+    }
+
+    private static void assertEquals(String message, boolean expected, boolean actual) {
+        if (expected != actual) {
+            throw new RuntimeException(message);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/JComboBox/8033069/bug8033069ScrollBar.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.awt.AWTException;
+
+/* @test
+ * @bug 8033069
+ * @summary Checks that JComboBox popup does not close when mouse wheel is
+ *          rotated over combo box and over its popup. The case where
+ *          popup has scroll bar.
+ * @library ../../regtesthelpers
+ * @build Util
+ * @run main bug8033069ScrollBar
+ * @author Alexey Ivanov
+ */
+public class bug8033069ScrollBar extends bug8033069NoScrollBar {
+
+    private static final String[] SCROLL_ITEMS = new String[] {
+            "A", "B", "C", "D", "E", "F",
+            "G", "H", "I", "J", "K", "L",
+            "M", "N", "O", "P", "Q", "R"
+    };
+
+    public static void main(String[] args) throws Exception {
+        iterateLookAndFeels(new bug8033069ScrollBar(SCROLL_ITEMS));
+    }
+
+    public bug8033069ScrollBar(String[] items) throws AWTException {
+        super(items);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/JFileChooser/8080628/bug8080628.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.Locale;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.UIManager.LookAndFeelInfo;
+
+import sun.swing.SwingUtilities2;
+
+/*
+ * @test
+ * @bug 8080628
+ * @summary No mnemonics on Open and Save buttons in JFileChooser.
+ * @author Alexey Ivanov
+ * @run main bug8080628
+ */
+public class bug8080628 {
+    public static final String[] MNEMONIC_KEYS = new String[] {
+            "FileChooser.saveButtonMnemonic",
+            "FileChooser.openButtonMnemonic",
+            "FileChooser.cancelButtonMnemonic",
+            "FileChooser.directoryOpenButtonMnemonic"
+    };
+
+    public static final Locale[] LOCALES = new Locale[] {
+            new Locale("en"),
+            new Locale("de"),
+            new Locale("es"),
+            new Locale("fr"),
+            new Locale("it"),
+            new Locale("ja"),
+            new Locale("ko"),
+            new Locale("pt", "BR"),
+            new Locale("sv"),
+            new Locale("zh", "CN"),
+            new Locale("zh", "TW")
+    };
+
+    private static volatile Exception exception;
+
+    public static void main(String[] args) throws Exception {
+        SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                runTest();
+            }
+        });
+
+        if (exception != null) {
+            throw exception;
+        }
+    }
+
+    private static void runTest() {
+        try {
+            LookAndFeelInfo[] lafInfo = UIManager.getInstalledLookAndFeels();
+            for (LookAndFeelInfo info : lafInfo) {
+                UIManager.setLookAndFeel(info.getClassName());
+
+                for (Locale locale : LOCALES) {
+                    for (String key : MNEMONIC_KEYS) {
+                        int mnemonic = SwingUtilities2.getUIDefaultsInt(key, locale);
+                        if (mnemonic != 0) {
+                            throw new RuntimeException("No mnemonic expected (" + mnemonic + ") " +
+                                    "for '" + key + "' " +
+                                    "in locale '" + locale + "' " +
+                                    "in Look-and-Feel '"
+                                        + UIManager.getLookAndFeel().getClass().getName() + "'");
+                        }
+                    }
+                }
+            }
+            System.out.println("Test passed");
+        } catch (Exception e) {
+            exception = e;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/JRadioButton/8075609/bug8075609.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+ /*
+ * @test
+ * @library ../../regtesthelpers
+ * @build Util
+ * @bug 8075609
+ * @summary  IllegalArgumentException when transferring focus from JRadioButton using tab
+ * @author Vivi An
+ * @run main bug8075609
+ */
+
+import javax.swing.*;
+import javax.swing.event.*;
+import java.awt.event.*;
+import java.awt.*;
+import sun.awt.SunToolkit;
+
+public class bug8075609 {
+    private static Robot robot;
+    private static SunToolkit toolkit;
+    private static JTextField textField;
+
+    public static void main(String args[]) throws Throwable {
+        SwingUtilities.invokeAndWait(new Runnable() {
+            public void run() {
+                createAndShowGUI();
+            }
+        });
+
+        robot = new Robot();
+        Thread.sleep(100);
+
+        robot.setAutoDelay(100);
+        toolkit = (SunToolkit) Toolkit.getDefaultToolkit();
+
+        // Radio button group tab key test
+        runTest1();
+    }
+
+    private static void createAndShowGUI() {
+        JFrame mainFrame = new JFrame("Bug 8075609 - 1 test");
+
+        JPanel rootPanel = new JPanel();
+        rootPanel.setLayout(new BorderLayout());
+
+        JPanel formPanel = new JPanel();
+        formPanel.setFocusTraversalPolicy(new LayoutFocusTraversalPolicy());
+        formPanel.setFocusCycleRoot(true);
+
+        JRadioButton option1 = new JRadioButton("Option 1", true);
+        JRadioButton option2 = new JRadioButton("Option 2");
+
+        ButtonGroup radioButtonGroup = new ButtonGroup();
+        radioButtonGroup.add(option1);
+        radioButtonGroup.add(option2);
+
+        formPanel.add(option1);
+        formPanel.add(option2);
+        textField = new JTextField("Another focusable component");
+        formPanel.add(textField);
+
+        rootPanel.add(formPanel, BorderLayout.CENTER);
+
+        JButton okButton = new JButton("OK");
+        rootPanel.add(okButton, BorderLayout.SOUTH);
+
+        mainFrame.add(rootPanel);
+        mainFrame.pack();
+        mainFrame.setVisible(true);
+        mainFrame.toFront();
+    }
+
+    // Radio button Group as a single component when traversing through tab key
+    private static void runTest1() throws Exception{
+        hitKey(robot, KeyEvent.VK_TAB);
+
+        robot.setAutoDelay(1000 );
+        SwingUtilities.invokeAndWait(new Runnable() {
+            public void run() {
+                if (textField.hasFocus()) {
+                    System.out.println("Radio Button Group Go To Next Component through Tab Key failed");
+                    throw new RuntimeException("Focus is not on textField as Expected");
+                }
+            }
+        });
+    }
+
+    private static void hitKey(Robot robot, int keycode) {
+        robot.keyPress(keycode);
+        robot.keyRelease(keycode);
+        toolkit.realSync();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/JRootPane/SilenceOfDeprecatedMenuBar/SilenceOfDeprecatedMenuBar.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import javax.swing.JFrame;
+import javax.swing.JMenuBar;
+import javax.swing.JRootPane;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.UnsupportedLookAndFeelException;
+
+import static javax.swing.UIManager.getInstalledLookAndFeels;
+
+/**
+ * @test
+ * @bug 6368321
+ * @author Sergey Bylokhov
+ */
+public final class SilenceOfDeprecatedMenuBar implements Runnable {
+
+    public static void main(final String[] args) throws Exception {
+        for (final UIManager.LookAndFeelInfo laf : getInstalledLookAndFeels()) {
+            SwingUtilities.invokeAndWait(() -> setLookAndFeel(laf));
+            SwingUtilities.invokeAndWait(new SilenceOfDeprecatedMenuBar());
+        }
+    }
+
+    @Override
+    public void run() {
+        final JFrame frame = new DeprecatedFrame();
+        try {
+            final JMenuBar bar = new JMenuBar();
+            frame.setJMenuBar(bar);
+            frame.setBounds(100, 100, 100, 100);
+            frame.setLocationRelativeTo(null);
+            frame.setVisible(true);
+            if (bar != frame.getJMenuBar()) {
+                throw new RuntimeException("Wrong JMenuBar");
+            }
+        } finally {
+            frame.dispose();
+        }
+    }
+
+    private static void setLookAndFeel(final UIManager.LookAndFeelInfo laf) {
+        try {
+            UIManager.setLookAndFeel(laf.getClassName());
+            System.out.println("LookAndFeel: " + laf.getClassName());
+        } catch (ClassNotFoundException | InstantiationException |
+                UnsupportedLookAndFeelException | IllegalAccessException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static class DeprecatedFrame extends JFrame {
+
+        @Override
+        protected JRootPane createRootPane() {
+            return new JRootPane() {
+                @Override
+                public JMenuBar getMenuBar() {
+                    throw new RuntimeException("Should not be here");
+                }
+                @Override
+                public void setMenuBar(final JMenuBar menu) {
+                    throw new RuntimeException("Should not be here");
+                }
+            };
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/JSpinner/WrongEditorTextFieldFont/WrongEditorTextFieldFont.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.awt.FlowLayout;
+import java.awt.Font;
+
+import javax.swing.JFrame;
+import javax.swing.JSpinner;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+import javax.swing.UnsupportedLookAndFeelException;
+import javax.swing.plaf.UIResource;
+
+import static javax.swing.JSpinner.*;
+import static javax.swing.UIManager.getInstalledLookAndFeels;
+
+/**
+ * @test
+ * @bug 5036022
+ * @author Sergey Bylokhov
+ */
+public class WrongEditorTextFieldFont implements Runnable {
+
+    private static final Font USERS_FONT = new Font("dialog", Font.BOLD, 41);
+
+    public static void main(final String[] args) throws Exception {
+        for (final UIManager.LookAndFeelInfo laf : getInstalledLookAndFeels()) {
+            SwingUtilities.invokeAndWait(() -> setLookAndFeel(laf));
+            SwingUtilities.invokeAndWait(new WrongEditorTextFieldFont());
+        }
+    }
+
+    @Override
+    public void run() {
+        final JFrame frame1 = new JFrame();
+        try {
+            testDefaultFont(frame1);
+        } finally {
+            frame1.dispose();
+        }
+    }
+
+    private static void testDefaultFont(final JFrame frame) {
+        final JSpinner spinner = new JSpinner();
+        final JSpinner spinner_u = new JSpinner();
+        frame.setLayout(new FlowLayout(FlowLayout.CENTER, 50, 50));
+        frame.getContentPane().add(spinner);
+        frame.getContentPane().add(spinner_u);
+        frame.pack();
+        frame.setLocationRelativeTo(null);
+        frame.setVisible(true);
+        final DefaultEditor ed = (DefaultEditor) spinner.getEditor();
+        final DefaultEditor ed_u = (DefaultEditor) spinner_u.getEditor();
+        ed_u.getTextField().setFont(USERS_FONT);
+
+        for (int i = 5; i < 40; i += 5) {
+            /*
+             * Validate that the font of the text field is changed to the
+             * font of JSpinner if the font of text field was not set by the
+             * user.
+             */
+            final Font tff = ed.getTextField().getFont();
+            if (!(tff instanceof UIResource)) {
+                throw new RuntimeException("Font must be UIResource");
+            }
+            if (spinner.getFont().getSize() != tff.getSize()) {
+                throw new RuntimeException("Rrong size");
+            }
+            spinner.setFont(new Font("dialog", Font.BOLD, i));
+            /*
+             * Validate that the font of the text field is NOT changed to the
+             * font of JSpinner if the font of text field was set by the user.
+             */
+            final Font tff_u = ed_u.getTextField().getFont();
+            if (tff_u instanceof UIResource || !tff_u.equals(USERS_FONT)) {
+                throw new RuntimeException("Font must NOT be UIResource");
+            }
+            if (spinner_u.getFont().getSize() == tff_u.getSize()) {
+                throw new RuntimeException("Wrong size");
+            }
+            spinner_u.setFont(new Font("dialog", Font.BOLD, i));
+        }
+    }
+
+    private static void setLookAndFeel(final UIManager.LookAndFeelInfo laf) {
+        try {
+            UIManager.setLookAndFeel(laf.getClassName());
+            System.out.println("LookAndFeel: " + laf.getClassName());
+        } catch (ClassNotFoundException | InstantiationException |
+                UnsupportedLookAndFeelException | IllegalAccessException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/JTextArea/TextViewOOM/TextViewOOM.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.awt.EventQueue;
+
+import javax.swing.JFrame;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+
+/**
+ * @test
+ * @bug 8072775
+ * @run main/othervm -Xmx80m TextViewOOM
+ */
+public class TextViewOOM {
+
+    private static JFrame frame;
+    private static JTextArea ta;
+    private static final String STRING = "\uDC00\uD802\uDFFF";
+    private static final int N = 5000;
+
+    private static void createAndShowGUI() {
+        frame = new JFrame();
+        final JScrollPane jScrollPane1 = new JScrollPane();
+        ta = new JTextArea();
+
+        ta.setEditable(false);
+        ta.setColumns(20);
+        ta.setRows(5);
+        jScrollPane1.setViewportView(ta);
+        frame.add(ta);
+
+        frame.pack();
+        frame.setLocationRelativeTo(null);
+        frame.setVisible(true);
+    }
+
+    public static void main(final String[] args) throws Exception {
+        /* Create and display the form */
+        EventQueue.invokeAndWait(TextViewOOM::createAndShowGUI);
+        for (int i = 0; i < 10; i++) {
+            System.gc();
+            Thread.sleep(1000);
+        }
+        long mem = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
+        System.err.println("Memory before creating the text: "+mem);
+        final StringBuilder sb = new StringBuilder(N * STRING.length());
+        for (int i = 0; i < N; i++) {
+            sb.append(STRING);
+        }
+        for (int i = 0; i < 10; i++) {
+            System.gc();
+            Thread.sleep(1000);
+        }
+        mem = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
+        System.err.println("Memory after  creating the text: "+mem);
+
+        EventQueue.invokeAndWait(() -> {
+            ta.setText(sb.toString());
+            for (int i = 0; i < 10; i++) {
+                System.gc();
+                try {Thread.sleep(200);} catch (InterruptedException iex) {}
+            }
+            long mem1 = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
+            System.err.println("Memory after  setting the text: " + mem1);
+        });
+        for (int i = 0; i < 10; i++) {
+            System.gc();
+            Thread.sleep(1000);
+        }
+        mem = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
+        System.err.println("Final memory  after everything: " + mem);
+        EventQueue.invokeAndWait(frame::dispose);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/RepaintManager/DisplayListenerLeak/DisplayListenerLeak.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.EventQueue;
+import java.awt.GraphicsEnvironment;
+
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+
+import sun.java2d.SunGraphicsEnvironment;
+
+/**
+ * @test
+ * @bug 8041654
+ * @run main/othervm -Xmx80m DisplayListenerLeak
+ */
+public final class DisplayListenerLeak {
+
+    private static JFrame frame;
+    private volatile static boolean failed = false;
+
+    private static void createAndShowGUI() {
+        Thread.currentThread().setUncaughtExceptionHandler((t, e) -> {
+            e.printStackTrace();
+            failed = true;
+        });
+        frame = new JFrame();
+        JLabel emptyLabel = new JLabel("");
+        emptyLabel.setPreferredSize(new Dimension(600, 400));
+        frame.getContentPane().add(emptyLabel, BorderLayout.CENTER);
+        frame.pack();
+        frame.setVisible(true);
+    }
+
+    public static void main(final String[] args) throws Exception {
+        GraphicsEnvironment ge =
+                GraphicsEnvironment.getLocalGraphicsEnvironment();
+        if (!(ge instanceof SunGraphicsEnvironment)) {
+            return;
+        }
+        EventQueue.invokeAndWait(() -> createAndShowGUI());
+        SunGraphicsEnvironment sge = (SunGraphicsEnvironment) ge;
+        final long startTime = System.nanoTime();
+        while (!failed) {
+            if (System.nanoTime() - startTime > 60_000_000_000L) {
+                break;
+            }
+            System.gc(); // clear all weak references
+            EventQueue.invokeAndWait(() -> {
+                frame.setSize(frame.getHeight(), frame.getWidth());
+                frame.pack();
+            });
+            EventQueue.invokeAndWait(sge::displayChanged);
+        }
+        EventQueue.invokeAndWait(frame::dispose);
+        if (failed) {
+            throw new RuntimeException();
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/plaf/basic/BasicComboPopup/7072653/bug7072653.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+   @bug 7072653
+   @summary JComboBox popup mispositioned if its height exceeds the screen height
+   @author Semyon Sadetsky
+  */
+
+
+import javax.swing.*;
+import javax.swing.event.PopupMenuEvent;
+import javax.swing.event.PopupMenuListener;
+import java.awt.*;
+import java.awt.Toolkit;
+
+public class bug7072653 {
+
+    private static JComboBox combobox;
+    private static JFrame frame;
+
+    public static void main(String[] args) throws Exception {
+        try {
+            SwingUtilities.invokeAndWait(new Runnable() {
+                @Override
+                public void run() {
+                    frame = new JFrame("JComboBox Test");
+                    setup(frame);
+                }
+            });
+            test();
+        }
+        finally {
+            frame.dispose();
+        }
+
+    }
+
+    static void setup(JFrame frame)  {
+
+
+        frame.setUndecorated(true);
+        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+        frame.setSize(320, 200);
+
+        frame.getContentPane().setLayout(new FlowLayout());
+
+        combobox = new JComboBox(new DefaultComboBoxModel() {
+            public Object getElementAt(int index) { return "Element " + index; }
+            public int getSize() {
+                return 1000;
+            }
+        });
+
+
+        combobox.setMaximumRowCount(100);
+        frame.getContentPane().add(combobox);
+
+        frame.setVisible(true);
+
+    }
+
+    static void test() throws Exception{
+        SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                combobox.addPopupMenuListener(new PopupMenuListener() {
+                    @Override
+                    public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
+                    }
+
+                    @Override
+                    public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
+                        int height = 0;
+                        for (Window window : JFrame.getWindows()) {
+                            if (Window.Type.POPUP == window.getType()) {
+                                height = window.getSize().height;
+                                break;
+                            }
+                        }
+                        GraphicsConfiguration gc =
+                                combobox.getGraphicsConfiguration();
+                        Insets screenInsets = Toolkit.getDefaultToolkit()
+                                .getScreenInsets(gc);
+
+                        if (height == gc.getBounds().height - screenInsets.top -
+                                screenInsets.bottom ) {
+                            System.out.println("ok");
+                            return;
+                        }
+                        throw new RuntimeException(
+                                "Popup window height is wrong " + height);
+                    }
+
+                    @Override
+                    public void popupMenuCanceled(PopupMenuEvent e) {
+                    }
+                });
+                combobox.setPopupVisible(true);
+                combobox.setPopupVisible(false);
+            }
+        });
+    }
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/plaf/basic/BasicLabelUI/bug7172652.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+   @bug 7172652
+   @summary With JDK 1.7 text field does not obtain focus when using mnemonic Alt/Key combin
+   @author Semyon Sadetsky
+   @library /lib/testlibrary
+   @build jdk.testlibrary.OSInfo
+   @run main bug7172652
+  */
+
+import javax.swing.*;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import java.awt.*;
+import java.awt.event.KeyEvent;
+import jdk.testlibrary.OSInfo;
+
+public class bug7172652  {
+
+    private static JMenu menu;
+    private static JFrame frame;
+    private static Boolean selected;
+
+    public static void main(String[] args) throws Exception {
+        if (OSInfo.getOSType() != OSInfo.OSType.WINDOWS) {
+            System.out.println("ok");
+            return;
+        }
+        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+        SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                setup();
+            }
+        });
+
+        test();
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                frame.dispose();
+            }
+        });
+    }
+
+    private static void test() throws Exception {
+        SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                menu.getModel().addChangeListener(new ChangeListener() {
+                    @Override
+                    public void stateChanged(ChangeEvent e) {
+                        selected = menu.isSelected();
+                    }
+                });
+            }
+        });
+
+        Robot robot = new Robot();
+        robot.setAutoDelay(200);
+
+        robot.keyPress(KeyEvent.VK_ALT);
+        robot.keyPress(KeyEvent.VK_F);
+        robot.keyRelease(KeyEvent.VK_F);
+        robot.keyRelease(KeyEvent.VK_ALT);
+
+        robot.waitForIdle();
+        if( selected != null ) {
+            throw new RuntimeException("Menu is notified selected= " + selected);
+        }
+
+        robot.keyPress(KeyEvent.VK_ALT);
+        robot.keyPress(KeyEvent.VK_F);
+        robot.keyRelease(KeyEvent.VK_F);
+        robot.keyRelease(KeyEvent.VK_ALT);
+        if( selected != null ) {
+            throw new RuntimeException("Menu is notified selected= " + selected);
+        }
+
+        robot.waitForIdle();
+
+        robot.keyPress(KeyEvent.VK_ALT);
+        robot.keyPress(KeyEvent.VK_F);
+        robot.keyRelease(KeyEvent.VK_F);
+        robot.keyRelease(KeyEvent.VK_ALT);
+        if( selected != null ) {
+            throw new RuntimeException("Menu is notified selected= " + selected);
+        }
+
+        robot.waitForIdle();
+
+        robot.keyPress(KeyEvent.VK_ALT);
+        robot.keyPress(KeyEvent.VK_F);
+        robot.keyRelease(KeyEvent.VK_F);
+        robot.keyRelease(KeyEvent.VK_ALT);
+        if( selected != null ) {
+            throw new RuntimeException("Menu is notified selected= " + selected);
+        }
+
+        robot.waitForIdle();
+
+        System.out.printf("ok");
+    }
+
+    private static void setup() {
+        JLabel firstLbl = new JLabel("First name");
+        JLabel lastLbl = new JLabel("Last name");
+        JMenuBar menuBar = new JMenuBar();
+
+        JTextField firstTxtFld = new JTextField(20);
+        JTextField lastTxtFld = new JTextField(20);
+        JDesktopPane desktopPane = new JDesktopPane();
+        JInternalFrame iframe = new JInternalFrame("A frame", true, true, true, true);
+
+        // Set an initial size
+        iframe.setSize(200, 220);
+
+        // By default, internal frames are not visible; make it visible
+        iframe.setVisible(true);
+
+        JPanel pane = new JPanel();
+        pane.setLayout(new FlowLayout());
+
+        pane.add(firstLbl);
+        pane.add(firstTxtFld);
+        pane.add(lastLbl);
+        pane.add(lastTxtFld);
+
+        firstLbl.setLabelFor(firstTxtFld);
+        firstLbl.setDisplayedMnemonic('F');
+
+        lastLbl.setLabelFor(lastTxtFld);
+        lastLbl.setDisplayedMnemonic('L');
+
+        iframe.getContentPane().add(pane);
+        iframe.setJMenuBar(menuBar);
+        menu = new JMenu("FirstMenu");
+        //m.setMnemonic('i');
+        menuBar.add(menu);
+        desktopPane.add(iframe);
+
+        frame = new JFrame();
+        frame.setUndecorated(true);
+        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        frame.getContentPane().add(desktopPane);
+        frame.setSize(300, 300);
+        frame.setVisible(true);
+    }
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/swing/plaf/basic/BasicTextUI/8001470/bug8001470.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+   @bug 8001470
+   @summary JTextField's size is computed incorrectly when it contains Indic or Thai characters
+   @author Semyon Sadetsky
+  */
+
+import javax.swing.*;
+import java.awt.*;
+
+public class bug8001470 {
+
+    private static JFrame frame;
+    private static JTextField textField1;
+    private static JTextField textField2;
+
+    public static void main(String[] args) throws Exception {
+        SwingUtilities.invokeAndWait(new Runnable() {
+            @Override
+            public void run() {
+                frame = new JFrame("JTextField Test");
+                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+                JPanel container = (JPanel) frame.getContentPane();
+                container.setLayout(new GridLayout(2,1));
+
+                textField1 = new JTextField("\u0e01");
+                textField2 = new JTextField("\u0c01");
+
+                container.add(textField1);
+                container.add(textField2);
+                frame.setVisible(true);
+                frame.pack();
+            }
+        });
+        if( textField1.getHeight() < 10 || textField2.getHeight() < 10 )
+            throw new Exception("Wrong field height");
+        System.out.println("ok");
+        SwingUtilities.invokeLater(new Runnable() {
+            @Override
+            public void run() {
+                frame.dispose();
+            }
+        });
+    }
+}
--- a/jdk/test/javax/xml/jaxp/common/8032908/TestFunc.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/javax/xml/jaxp/common/8032908/TestFunc.java	Wed Jul 05 20:37:09 2017 +0200
@@ -26,8 +26,9 @@
 public class TestFunc {
 
     public static String test(Node node) {
-        String s = node.getTextContent();
-        return s;
+        String textContent = node.getTextContent();
+        String nodeValue   = node.getNodeValue();
+        return textContent + ":" + nodeValue;
     }
 
 }
--- a/jdk/test/javax/xml/jaxp/common/8032908/XSLT.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/javax/xml/jaxp/common/8032908/XSLT.java	Wed Jul 05 20:37:09 2017 +0200
@@ -23,9 +23,10 @@
 
 /**
  * @test
- * @bug 8032908
+ * @bug 8032908 8081392
  * @summary Test if Node.getTextContent() function correctly returns children
- * content
+ * content and also check that Node.getNodeValue() returns null value for
+ * Element nodes
  * @compile TestFunc.java XSLT.java
  * @run main/othervm XSLT
  */
@@ -40,7 +41,7 @@
 
     static final String XMLTOTRANSFORM = "/in.xml";
     static final String XSLTRANSFORMER = "/test.xsl";
-    static final String EXPECTEDRESULT = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>ABCDEFG";
+    static final String EXPECTEDRESULT = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>ABCDEFG:null";
 
     public static void main(String[] args) throws TransformerException {
         ByteArrayOutputStream resStream = new ByteArrayOutputStream();
--- a/jdk/test/lib/security/CheckBlacklistedCerts.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/lib/security/CheckBlacklistedCerts.java	Wed Jul 05 20:37:09 2017 +0200
@@ -45,7 +45,7 @@
         File file = new File(home, "lib/security/cacerts");
         KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
         try (FileInputStream fis = new FileInputStream(file)) {
-            ks.load(new FileInputStream(file), null);
+            ks.load(fis, null);
         }
         System.out.println("Check for cacerts: " + ks.size());
         for (String alias: Collections.list(ks.aliases())) {
--- a/jdk/test/lib/testlibrary/AssertsTest.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/lib/testlibrary/AssertsTest.java	Wed Jul 05 20:37:09 2017 +0200
@@ -21,6 +21,8 @@
  * questions.
  */
 
+import java.lang.SuppressWarnings;
+
 import static jdk.testlibrary.Asserts.*;
 
 /* @test
@@ -75,7 +77,7 @@
 
     private static void testEquals() throws Exception {
         expectPass(Assertion.EQ, 1, 1);
-        expectPass(Assertion.EQ, (Comparable)null, (Comparable)null);
+        expectPass(Assertion.EQ, (Integer)null, (Integer)null);
 
         Foo f1 = new Foo(1);
         expectPass(Assertion.EQ, f1, f1);
@@ -112,13 +114,13 @@
         Foo f2 = new Foo(1);
         expectPass(Assertion.NE, f1, f2);
 
-        expectFail(Assertion.NE, (Comparable)null, (Comparable)null);
+        expectFail(Assertion.NE, (Integer)null, (Integer)null);
         expectFail(Assertion.NE, f1, f1);
         expectFail(Assertion.NE, 1, 1);
     }
 
     private static void testNull() throws Exception {
-        expectPass(Assertion.NULL, (Comparable)null);
+        expectPass(Assertion.NULL, (Integer)null);
 
         expectFail(Assertion.NULL, 1);
     }
@@ -126,7 +128,7 @@
     private static void testNotNull() throws Exception {
         expectPass(Assertion.NOTNULL, 1);
 
-        expectFail(Assertion.NOTNULL, (Comparable)null);
+        expectFail(Assertion.NOTNULL, (Integer)null);
     }
 
     private static void testTrue() throws Exception {
@@ -169,13 +171,13 @@
         }
     }
 
-
-
+    @SuppressWarnings("unchecked")
     private static <T extends Comparable<T>> void expectPass(Assertion assertion, T ... args)
         throws Exception {
         Assertion.run(assertion, args);
     }
 
+    @SuppressWarnings("unchecked")
     private static <T extends Comparable<T>> void expectFail(Assertion assertion, T ... args)
         throws Exception {
         try {
@@ -192,8 +194,9 @@
 enum Assertion {
     LT, LTE, EQ, GTE, GT, NE, NULL, NOTNULL, FALSE, TRUE;
 
+    @SuppressWarnings("unchecked")
     public static <T extends Comparable<T>> void run(Assertion assertion, T ... args) {
-        String msg = "Expected " + format(assertion, args) + " to pass";
+        String msg = "Expected " + format(assertion, (Object[])args) + " to pass";
         switch (assertion) {
             case LT:
                 assertLessThan(args[0], args[1], msg);
--- a/jdk/test/lib/testlibrary/OutputAnalyzerReportingTest.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/lib/testlibrary/OutputAnalyzerReportingTest.java	Wed Jul 05 20:37:09 2017 +0200
@@ -28,7 +28,6 @@
  * @summary Test the OutputAnalyzer reporting functionality,
  *     such as printing additional diagnostic info
  *     (exit code, stdout, stderr, command line, etc.)
- * @library /testlibrary
  * @modules java.management
  * @build jdk.testlibrary.*
  * @run main jdk.testlibrary.OutputAnalyzerReportingTest
--- a/jdk/test/lib/testlibrary/OutputAnalyzerTest.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/lib/testlibrary/OutputAnalyzerTest.java	Wed Jul 05 20:37:09 2017 +0200
@@ -25,7 +25,6 @@
 /*
  * @test
  * @summary Test the OutputAnalyzer utility class
- * @library /testlibrary
  * @modules java.management
  * @build jdk.testlibrary.*
  * @run main jdk.testlibrary.OutputAnalyzerTest
--- a/jdk/test/lib/testlibrary/jdk/testlibrary/JarUtils.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/JarUtils.java	Wed Jul 05 20:37:09 2017 +0200
@@ -72,9 +72,9 @@
             // is in the updated list
             List<String> updatedFiles = new ArrayList<>();
             try (JarFile srcJarFile = new JarFile(src)) {
-                Enumeration entries = srcJarFile.entries();
+                Enumeration<JarEntry> entries = srcJarFile.entries();
                 while (entries.hasMoreElements()) {
-                    JarEntry entry = (JarEntry) entries.nextElement();
+                    JarEntry entry = entries.nextElement();
                     String name = entry.getName();
                     boolean found = false;
                     for (String file : files) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/OptimalCapacity.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.testlibrary;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+
+/**
+ * Utility functions to check that the static storages are pre-sized
+ * optimally.
+ */
+public final class OptimalCapacity {
+
+    private OptimalCapacity() {}
+
+    /**
+     * Checks adequacy of the initial capacity of a static field
+     * of type {@code ArrayList}.
+     *
+     * Having
+     * <pre>
+     * class XClass {
+     *     static ArrayList theList = new ArrayList(N);
+     * }
+     * </pre>
+     *
+     * you should call from the test
+     *
+     * <pre>
+     * OptimalCapacity.assertProperlySized(XClass.class, "theList", N);
+     * </pre>
+     */
+    public static void ofArrayList(Class<?> clazz, String fieldName,
+            int initialCapacity)
+    {
+        try {
+            Field field = clazz.getDeclaredField(fieldName);
+            field.setAccessible(true);
+            Object obj = field.get(null);
+            if (!ArrayList.class.equals(obj.getClass())) {
+                throw new RuntimeException("'" + field +
+                    "' expected to be of type ArrayList");
+            }
+            ArrayList<?> list = (ArrayList<?>)obj;
+
+            // For ArrayList the optimal capacity is its final size
+            if (list.size() != initialCapacity) {
+                throw new RuntimeException("Size of '" + field +
+                    "' is " + list.size() +
+                    ", but expected to be " + initialCapacity);
+            }
+            if (internalArraySize(list) != initialCapacity) {
+                throw new RuntimeException("Capacity of '" + field +
+                    "' is " + internalArraySize(list) +
+                    ", but expected to be " + initialCapacity);
+            }
+        } catch (ReflectiveOperationException roe) {
+            throw new RuntimeException(roe);
+        }
+    }
+
+    /**
+     * Checks adequacy of the initial capacity of a static field
+     * of type {@code HashMap}.
+     *
+     * Having
+     * <pre>
+     * class XClass {
+     *     static HashMap theMap = new HashMap(N);
+     * }
+     * </pre>
+     *
+     * you should call from the test
+     *
+     * <pre>
+     * OptimalCapacity.ofHashMap(XClass.class, "theMap", N);
+     * </pre>
+     */
+    public static void ofHashMap(Class<?> clazz, String fieldName,
+            int initialCapacity)
+    {
+        try {
+            Field field = clazz.getDeclaredField(fieldName);
+            field.setAccessible(true);
+            Object obj = field.get(null);
+            if (!HashMap.class.equals(obj.getClass())) {
+                throw new RuntimeException(field +
+                    " expected to be of type HashMap");
+            }
+            HashMap<?,?> map = (HashMap<?,?>)obj;
+
+            // Check that the map allocates only necessary amount of space
+            HashMap<Object, Object> tmp = new HashMap<>(map);
+            if (internalArraySize(map) != internalArraySize(tmp)) {
+                throw new RuntimeException("Final capacity of '" + field +
+                    "' is " + internalArraySize(map) +
+                    ", which exceeds necessary minimum " + internalArraySize(tmp));
+            }
+
+            // Check that map is initially properly sized
+            tmp = new HashMap<>(initialCapacity);
+            tmp.put(new Object(), new Object()); // trigger storage init
+            if (internalArraySize(map) != internalArraySize(tmp)) {
+                throw new RuntimeException("Requested capacity of '" + field +
+                    "' was " + initialCapacity +
+                    ", which resulted in final capacity " + internalArraySize(tmp) +
+                    ", which differs from necessary minimum " + internalArraySize(map));
+            }
+
+        } catch (ReflectiveOperationException roe) {
+            throw new RuntimeException(roe);
+        }
+    }
+
+    /**
+     * Checks adequacy of the expected maximum size of a static field
+     * of type {@code IdentityHashMap}.
+     *
+     * Having
+     * <pre>
+     * class XClass {
+     *     static IdentityHashMap theMap = new IdentityHashMap(M);
+     * }
+     * </pre>
+     *
+     * you should call from the test
+     *
+     * <pre>
+     * OptimalCapacity.ofIdentityHashMap(XClass.class, "theMap", M);
+     * </pre>
+     */
+    public static void ofIdentityHashMap(Class<?> clazz, String fieldName,
+            int expectedMaxSize)
+    {
+        try {
+            Field field = clazz.getDeclaredField(fieldName);
+            field.setAccessible(true);
+            Object obj = field.get(null);
+            if (!IdentityHashMap.class.equals(obj.getClass())) {
+                throw new RuntimeException("'" + field +
+                    "' expected to be of type IdentityHashMap");
+            }
+            IdentityHashMap<?,?> map = (IdentityHashMap<?,?>)obj;
+
+            // Check that size of map is what was expected
+            if (map.size() != expectedMaxSize) {
+                throw new RuntimeException("Size of '" + field +
+                    "' is " + map.size() +
+                    ", which differs from expected " + expectedMaxSize);
+            }
+
+            // Check that the map allocated only necessary amount of memory
+            IdentityHashMap<Object, Object> tmp = new IdentityHashMap<>(map);
+            if (internalArraySize(map) != internalArraySize(tmp)) {
+                throw new RuntimeException("Final capacity of '" + field +
+                    "' is " + internalArraySize(map) +
+                    ", which exceeds necessary minimum " + internalArraySize(tmp));
+            }
+
+            // Check that map was initially properly sized
+            tmp = new IdentityHashMap<>(expectedMaxSize);
+            tmp.put(new Object(), new Object()); // trigger storage init
+            if (internalArraySize(map) != internalArraySize(tmp)) {
+                throw new RuntimeException("Requested number of elements in '" + field +
+                    "' was " + expectedMaxSize +
+                    ", which resulted in final capacity " + internalArraySize(tmp) +
+                    ", which differs from necessary minimum " + internalArraySize(map));
+            }
+        } catch (ReflectiveOperationException roe) {
+            throw new RuntimeException(roe);
+        }
+    }
+
+    /**
+     * Returns size of the internal storage.
+     */
+    private static int internalArraySize(Object container)
+            throws ReflectiveOperationException {
+        Field field;
+        if (ArrayList.class.equals(container.getClass())) {
+            field = ArrayList.class.getDeclaredField("elementData");
+        } else if (HashMap.class.equals(container.getClass())) {
+            field = HashMap.class.getDeclaredField("table");
+        } else if (IdentityHashMap.class.equals(container.getClass())) {
+            field = IdentityHashMap.class.getDeclaredField("table");
+        } else {
+            throw new RuntimeException("Unexpected class " +
+                    container.getClass());
+        }
+        field.setAccessible(true);
+        return ((Object[])field.get(container)).length;
+    }
+}
--- a/jdk/test/lib/testlibrary/jdk/testlibrary/OutputBuffer.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/OutputBuffer.java	Wed Jul 05 20:37:09 2017 +0200
@@ -30,6 +30,8 @@
 
 class OutputBuffer {
     private static class OutputBufferException extends RuntimeException {
+        private static final long serialVersionUID = 8528687792643129571L;
+
         public OutputBufferException(Throwable cause) {
             super(cause);
         }
--- a/jdk/test/lib/testlibrary/jdk/testlibrary/ParentLastURLClassLoader.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/ParentLastURLClassLoader.java	Wed Jul 05 20:37:09 2017 +0200
@@ -38,7 +38,7 @@
     @Override
     public Class<?> loadClass(String name) throws ClassNotFoundException {
         try {
-            Class c = findClass(name);
+            Class<?> c = findClass(name);
             if (c != null) {
                 return c;
             }
--- a/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java	Wed Jul 05 20:37:09 2017 +0200
@@ -72,7 +72,7 @@
     public static Process startProcess(String name,
                                        ProcessBuilder processBuilder)
     throws IOException {
-        return startProcess(name, processBuilder, (Consumer)null);
+        return startProcess(name, processBuilder, (Consumer<String>)null);
     }
 
     /**
@@ -85,6 +85,7 @@
      * @return Returns the initialized process
      * @throws IOException
      */
+    @SuppressWarnings("overloads")
     public static Process startProcess(String name,
                                        ProcessBuilder processBuilder,
                                        Consumer<String> consumer)
@@ -239,6 +240,7 @@
      * @throws InterruptedException
      * @throws TimeoutException
      */
+    @SuppressWarnings("overloads")
     public static Process startProcess(String name,
                                        ProcessBuilder processBuilder,
                                        final Predicate<String> linePredicate)
--- a/jdk/test/lib/testlibrary/jdk/testlibrary/StreamPumper.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/StreamPumper.java	Wed Jul 05 20:37:09 2017 +0200
@@ -77,7 +77,7 @@
     private final Set<LinePump> linePumps = new HashSet<>();
 
     private final AtomicBoolean processing = new AtomicBoolean(false);
-    private final FutureTask<Void> processingTask = new FutureTask(this, null);
+    private final FutureTask<Void> processingTask = new FutureTask<>(this, null);
 
     public StreamPumper(InputStream in) {
         this.in = in;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/invoke/anon/ConstantPoolPatch/OptimalMapSize.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8080535
+ * @summary Static storages should be initialized with optimal capacity
+ * @library /lib/testlibrary
+ * @build jdk.testlibrary.OptimalCapacity
+ * @run main OptimalMapSize
+ */
+
+import jdk.testlibrary.OptimalCapacity;
+
+public class OptimalMapSize {
+    public static void main(String[] args) throws Throwable {
+        OptimalCapacity.ofIdentityHashMap(
+                Class.forName("sun.invoke.anon.ConstantPoolPatch"),
+                "CONSTANT_VALUE_CLASS_TAG", 6);
+    }
+}
--- a/jdk/test/sun/net/www/protocol/https/ChunkedOutputStream.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/sun/net/www/protocol/https/ChunkedOutputStream.java	Wed Jul 05 20:37:09 2017 +0200
@@ -25,7 +25,6 @@
  * @test
  * @bug 5026745
  * @modules java.base/sun.net.www
- * @library ../../httpstest/
  * @build TestHttpsServer HttpCallback
  * @run main/othervm ChunkedOutputStream
  *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/krb5/auto/Addresses.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8031111
+ * @summary fix krb5 caddr
+ * @compile -XDignore.symbol.file Addresses.java
+ * @run main/othervm Addresses
+ */
+
+import sun.security.krb5.Config;
+
+import javax.security.auth.kerberos.KerberosTicket;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+
+public class Addresses {
+
+    public static void main(String[] args) throws Exception {
+
+        KDC.saveConfig(OneKDC.KRB5_CONF, new OneKDC(null),
+                "noaddresses = false",
+                "extra_addresses = 10.0.0.10, 10.0.0.11 10.0.0.12");
+        Config.refresh();
+
+        KerberosTicket ticket =
+                Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false)
+                        .s().getPrivateCredentials(KerberosTicket.class)
+                        .iterator().next();
+
+        InetAddress loopback = InetAddress.getLoopbackAddress();
+        InetAddress extra1 = InetAddress.getByName("10.0.0.10");
+        InetAddress extra2 = InetAddress.getByName("10.0.0.11");
+        InetAddress extra3 = InetAddress.getByName("10.0.0.12");
+
+        boolean loopbackFound = false;
+        boolean extra1Found = false;
+        boolean extra2Found = false;
+        boolean extra3Found = false;
+        boolean networkFound = false;
+
+        for (InetAddress ia: ticket.getClientAddresses()) {
+            System.out.println(ia);
+            if (ia.equals(loopback)) {
+                loopbackFound = true;
+                System.out.println("  loopback found");
+            } else if (ia.equals(extra1)) {
+                extra1Found = true;
+                System.out.println("  extra1 found");
+            } else if (ia.equals(extra2)) {
+                extra2Found = true;
+                System.out.println("  extra2 found");
+            } else if (ia.equals(extra3)) {
+                extra3Found = true;
+                System.out.println("  extra3 found");
+            } else if (ia instanceof Inet4Address) {
+                networkFound = true;
+                System.out.println("  another address (" + ia +
+                        "), assumed real network");
+            }
+        }
+
+        if (!loopbackFound || !networkFound
+                || !extra1Found || !extra2Found || !extra3Found ) {
+            throw new Exception();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/krb5/auto/Forwarded.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8031111
+ * @summary fix krb5 caddr
+ * @compile -XDignore.symbol.file Forwarded.java
+ * @run main/othervm Forwarded
+ */
+
+import sun.security.jgss.GSSUtil;
+import sun.security.krb5.internal.KDCOptions;
+import sun.security.krb5.internal.KDCReqBody;
+import sun.security.krb5.internal.TGSReq;
+
+public class Forwarded {
+
+    public static void main(String[] args) throws Exception {
+
+        new OneKDC(null).setOption(KDC.Option.CHECK_ADDRESSES, true);
+
+        Context c;
+        c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false);
+
+        c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_KRB5_MECH_OID);
+        c.x().requestCredDeleg(true);
+
+        c.take(new byte[0]);
+    }
+}
--- a/jdk/test/sun/security/krb5/auto/KDC.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/sun/security/krb5/auto/KDC.java	Wed Jul 05 20:37:09 2017 +0200
@@ -205,6 +205,10 @@
          * Sensitive accounts can never be delegated.
          */
         SENSITIVE_ACCOUNTS,
+        /**
+         * If true, will check if TGS-REQ contains a non-null addresses field.
+         */
+        CHECK_ADDRESSES,
     };
 
     static {
@@ -734,6 +738,11 @@
                     bFlags[Krb5.TKT_OPTS_FORWARDABLE] = true;
                 }
             }
+            if (options.containsKey(Option.CHECK_ADDRESSES)
+                    && body.kdcOptions.get(KDCOptions.FORWARDED)
+                    && body.addresses == null) {
+                throw new KrbException(Krb5.KDC_ERR_BADOPTION);
+            }
             if (body.kdcOptions.get(KDCOptions.FORWARDED) ||
                     etp.flags.get(Krb5.TKT_OPTS_FORWARDED)) {
                 bFlags[Krb5.TKT_OPTS_FORWARDED] = true;
@@ -800,10 +809,8 @@
                     new KerberosTime(new Date()),
                     body.from,
                     till, body.rtime,
-                    body.addresses != null  // always set caddr
-                            ? body.addresses
-                            : new HostAddresses(
-                                new InetAddress[]{InetAddress.getLocalHost()}),
+                    body.addresses != null ? body.addresses
+                            : etp.caddr,
                     null);
             EncryptionKey skey = keyForUser(service, e3, true);
             if (skey == null) {
@@ -826,10 +833,7 @@
                     body.from,
                     till, body.rtime,
                     service,
-                    body.addresses != null  // always set caddr
-                            ? body.addresses
-                            : new HostAddresses(
-                                new InetAddress[]{InetAddress.getLocalHost()})
+                    body.addresses
                     );
             EncryptedData edata = new EncryptedData(ckey, enc_part.asn1Encode(), KeyUsage.KU_ENC_TGS_REP_PART_SESSKEY);
             TGSRep tgsRep = new TGSRep(null,
--- a/jdk/test/sun/security/krb5/auto/MSOID2.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/sun/security/krb5/auto/MSOID2.java	Wed Jul 05 20:37:09 2017 +0200
@@ -68,7 +68,14 @@
                 nt[0x1d] = (byte)0x82;  // change the 1st to MS OID
                 // Length bytes to be tweaked
                 for (int pos: new int[] {3, 0xf, 0x13, 0x15, 0x17}) {
-                    nt[pos] = (byte)(nt[pos] + 11);
+                    int newLen = (nt[pos]&0xff) + 11;
+                    // The length byte at nt[pos] might overflow. It's
+                    // unlikely for nt[pos-1] to overflow, which means the size
+                    // of token is bigger than 65535.
+                    if (newLen >= 256) {
+                        nt[pos-1] = (byte)(nt[pos-1] + 1);
+                    }
+                    nt[pos] = (byte)newLen;
                 }
                 t = nt;
                 new sun.misc.HexDumpEncoder().encodeBuffer(t, System.out);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/krb5/auto/SSLwithPerms.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8038089
+ * @summary TLS optional support for Kerberos cipher suites needs to be re-examined
+ * @library ../../../../java/security/testlibrary/
+ * @run main/othervm SSLwithPerms
+ */
+import java.io.*;
+import javax.net.ssl.*;
+import javax.security.auth.AuthPermission;
+import javax.security.auth.kerberos.ServicePermission;
+import java.net.SocketPermission;
+import java.nio.ByteBuffer;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.security.Principal;
+import java.security.Security;
+import java.security.SecurityPermission;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Locale;
+import java.util.PropertyPermission;
+
+import sun.security.jgss.GSSUtil;
+
+public class SSLwithPerms {
+
+    static String KRB5_CONF = "krb5.conf";
+    static String JAAS_CONF = "jaas.conf";
+    static String REALM = "REALM";
+    static String KTAB = "ktab";
+    static String HOST = "host." + REALM.toLowerCase(Locale.US);
+    static String SERVER = "host/" + HOST;
+    static String USER = "user";
+    static char[] PASS = "password".toCharArray();
+
+    public static void main(String[] args) throws Exception {
+
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+        if (args.length == 0) {
+            KDC kdc = KDC.create(REALM, HOST, 0, true);
+
+            kdc.addPrincipal(USER, PASS);
+            kdc.addPrincipalRandKey("krbtgt/" + REALM);
+            kdc.addPrincipalRandKey(SERVER);
+            KDC.saveConfig(KRB5_CONF, kdc);
+            kdc.writeKtab(KTAB);
+
+            File f = new File(JAAS_CONF);
+            FileOutputStream fos = new FileOutputStream(f);
+            fos.write((
+                    "ssl {\n" +
+                            "    com.sun.security.auth.module.Krb5LoginModule required\n" +
+                            "    principal=\"" + SERVER + "\"\n" +
+                            "    useKeyTab=true\n" +
+                            "    keyTab=" + KTAB + "\n" +
+                            "    isInitiator=false\n" +
+                            "    storeKey=true;\n};\n"
+            ).getBytes());
+            fos.close();
+
+            Proc pc = Proc.create("SSLwithPerms")
+                    .args("client")
+                    .inheritIO()
+                    .prop("java.security.manager", "")
+                    .prop("java.security.krb5.conf", KRB5_CONF)
+                    .prop("sun.net.spi.nameservice.provider.1", "ns,mock")
+                    .prop("javax.net.ssl", "handshake")
+                    .prop("sun.security.krb5.debug", "true")
+                    .perm(new SecurityPermission("setProperty.jdk.tls.disabledAlgorithms"))
+                    .perm(new PropertyPermission("sun.security.krb5.principal", "read"))
+                    .perm(new FilePermission("port", "read"))
+                    .perm(new FilePermission(KTAB, "read"))
+                    .perm(new RuntimePermission("accessClassInPackage.sun.net.spi.nameservice"))
+                    .perm(new AuthPermission("modifyPrincipals"))
+                    .perm(new AuthPermission("modifyPrivateCredentials"))
+                    .perm(new AuthPermission("doAs"))
+                    .perm(new SocketPermission("127.0.0.1", "connect"))
+                    .perm(new ServicePermission("host/host.realm@REALM", "initiate"))
+                    .start();
+
+            Proc ps = Proc.create("SSLwithPerms")
+                    .args("server")
+                    .inheritIO()
+                    .prop("java.security.manager", "")
+                    .prop("java.security.krb5.conf", KRB5_CONF)
+                    .prop("java.security.auth.login.config", JAAS_CONF)
+                    .prop("javax.net.ssl", "handshake")
+                    .prop("sun.security.krb5.debug", "true")
+                    .perm(new SecurityPermission("setProperty.jdk.tls.disabledAlgorithms"))
+                    .perm(new AuthPermission("createLoginContext.ssl"))
+                    .perm(new AuthPermission("doAs"))
+                    .perm(new FilePermission("port", "write"))
+                    .perm(new SocketPermission("127.0.0.1", "accept"))
+                    .perm(new ServicePermission("host/host.realm@REALM", "accept"))
+                    .start();
+
+            if (pc.waitFor() != 0) {
+                throw new Exception();
+            }
+            if (ps.waitFor() != 0) {
+                throw new Exception();
+            }
+        } else if (args[0].equals("client")) {
+            Context c;
+            c = Context.fromUserPass(USER, PASS, false);
+            c.doAs(new JsseClientAction(), null);
+        } else if (args[0].equals("server")) {
+            final Context s = Context.fromJAAS("ssl");
+            s.doAs(new JsseServerAction(), null);
+        }
+    }
+
+    private static class JsseClientAction implements Action {
+        public byte[] run(Context s, byte[] input) throws Exception {
+            SSLSocketFactory sslsf =
+                (SSLSocketFactory) SSLSocketFactory.getDefault();
+            while (!Files.exists(Paths.get("port"))) {
+                Thread.sleep(100);
+            }
+            int port = ByteBuffer.allocate(4)
+                    .put(Files.readAllBytes(Paths.get("port"))).getInt(0);
+            System.out.println("Connecting " + SERVER + ":" + port);
+            SSLSocket sslSocket = (SSLSocket) sslsf.createSocket(HOST, port);
+
+            // Enable only a KRB5 cipher suite.
+            String enabledSuites[] = {"TLS_KRB5_WITH_RC4_128_SHA"};
+            sslSocket.setEnabledCipherSuites(enabledSuites);
+
+            SSLParameters params = sslSocket.getSSLParameters();
+            params.setServerNames(Collections.singletonList(new SNIHostName(HOST)));
+            sslSocket.setSSLParameters(params);
+
+            BufferedReader in = new BufferedReader(new InputStreamReader(
+                sslSocket.getInputStream()));
+            BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
+                sslSocket.getOutputStream()));
+
+            String outStr = "Hello There!\n";
+            out.write(outStr);
+            out.flush();
+            System.out.print("Sending " + outStr);
+
+            String inStr = in.readLine();
+            System.out.println("Received " + inStr);
+
+            String cipherSuiteChosen = sslSocket.getSession().getCipherSuite();
+            System.out.println("Cipher suite in use: " + cipherSuiteChosen);
+            Principal self = sslSocket.getSession().getLocalPrincipal();
+            System.out.println("I am: " + self.toString());
+            Principal peer = sslSocket.getSession().getPeerPrincipal();
+            System.out.println("Server is: " + peer.toString());
+
+            sslSocket.close();
+            return null;
+        }
+    }
+
+    private static class JsseServerAction implements Action {
+        public byte[] run(Context s, byte[] input) throws Exception {
+            SSLServerSocketFactory sslssf =
+                (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
+            SSLServerSocket sslServerSocket =
+                (SSLServerSocket) sslssf.createServerSocket(0); // any port
+            int port = sslServerSocket.getLocalPort();
+            System.out.println("Listening on " + port);
+
+            String enabledSuites[] = {"TLS_KRB5_WITH_RC4_128_SHA"};
+            sslServerSocket.setEnabledCipherSuites(enabledSuites);
+
+            Files.write(Paths.get("port"), ByteBuffer.allocate(4).putInt(port).array());
+            System.out.println("Waiting for incoming connection...");
+
+            SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
+
+            System.out.println("Got connection from client "
+                + sslSocket.getInetAddress());
+
+            BufferedReader in = new BufferedReader(new InputStreamReader(
+                sslSocket.getInputStream()));
+            BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
+                sslSocket.getOutputStream()));
+
+            String inStr = in.readLine();
+            System.out.println("Received " + inStr);
+
+            String outStr = inStr + " " + new Date().toString() + "\n";
+            out.write(outStr);
+            System.out.println("Sending " + outStr);
+            out.flush();
+
+            String cipherSuiteChosen =
+                sslSocket.getSession().getCipherSuite();
+            System.out.println("Cipher suite in use: " + cipherSuiteChosen);
+            Principal self = sslSocket.getSession().getLocalPrincipal();
+            System.out.println("I am: " + self.toString());
+            Principal peer = sslSocket.getSession().getPeerPrincipal();
+            System.out.println("Client is: " + peer.toString());
+
+            sslSocket.close();
+            return null;
+        }
+    }
+}
--- a/jdk/test/sun/security/ssl/AppInputStream/ReadHandshake.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/sun/security/ssl/AppInputStream/ReadHandshake.java	Wed Jul 05 20:37:09 2017 +0200
@@ -21,19 +21,22 @@
  * questions.
  */
 
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
 /*
  * @test
  * @bug 4514971
  * @summary Verify applications do not read handshake data after failure
  * @run main/othervm ReadHandshake
- *
- *     SunJSSE does not support dynamic system properties, no way to re-use
- *     system properties in samevm/agentvm mode.
  */
 
 import java.io.*;
 import java.net.*;
 import javax.net.ssl.*;
+import java.security.Security;
 
 public class ReadHandshake {
 
@@ -219,6 +222,10 @@
     volatile Exception clientException = null;
 
     public static void main(String[] args) throws Exception {
+        // reset security properties to make sure that the algorithms
+        // and keys used in this test are not disabled.
+        Security.setProperty("jdk.tls.disabledAlgorithms", "");
+        Security.setProperty("jdk.certpath.disabledAlgorithms", "");
 
         if (debug)
             System.setProperty("javax.net.debug", "all");
--- a/jdk/test/sun/security/ssl/ClientHandshaker/LengthCheckTest.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/jdk/test/sun/security/ssl/ClientHandshaker/LengthCheckTest.java	Wed Jul 05 20:37:09 2017 +0200
@@ -233,7 +233,7 @@
             // sent back to the server.
             if (gotException == false ||
                 !isTlsMessage(cTOs, TLS_RECTYPE_ALERT, TLS_ALERT_LVL_FATAL,
-                        TLS_ALERT_INTERNAL_ERROR)) {
+                        TLS_ALERT_UNEXPECTED_MSG)) {
                 throw new SSLException(
                     "Client failed to throw Alert:fatal:internal_error");
             }
@@ -285,7 +285,7 @@
             // sent back to the client.
             if (gotException == false ||
                 !isTlsMessage(sTOc, TLS_RECTYPE_ALERT, TLS_ALERT_LVL_FATAL,
-                        TLS_ALERT_INTERNAL_ERROR)) {
+                        TLS_ALERT_UNEXPECTED_MSG)) {
                 throw new SSLException(
                     "Server failed to throw Alert:fatal:internal_error");
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/ssl/ExtensionType/OptimalListSize.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8080535
+ * @summary Expected size of Character.UnicodeBlock.map is not optimal
+ * @library /lib/testlibrary
+ * @build jdk.testlibrary.OptimalCapacity
+ * @run main OptimalListSize
+ */
+
+import jdk.testlibrary.OptimalCapacity;
+
+public class OptimalListSize {
+    public static void main(String[] args) throws Throwable {
+        OptimalCapacity.ofArrayList(
+                Class.forName("sun.security.ssl.ExtensionType"),
+                "knownExtensions", 13);
+    }
+}
--- a/make/StripBinaries.gmk	Thu Jun 04 18:50:30 2015 -0700
+++ b/make/StripBinaries.gmk	Wed Jul 05 20:37:09 2017 +0200
@@ -61,9 +61,12 @@
 COPY_LIBS_SRC := \
     $(shell $(FIND) $(SUPPORT_OUTPUTDIR)/modules_libs \
         \( ! -name '*$(SHARED_LIBRARY_SUFFIX)' -type f \) -o -type l)
+# OS X stores symbol information in a .dylib file inside a .dSYM directory -
+# that file should not be stripped, so we prune the tree at the .dSYM directory.
+# Example: support/modules_libs/java.base/libjsig.dylib.dSYM/Contents/Resources/DWARF/libjsig.dylib
 STRIP_LIBS_SRC := \
     $(shell $(FIND) $(SUPPORT_OUTPUTDIR)/modules_libs \
-        -name '*$(SHARED_LIBRARY_SUFFIX)' -type f)
+        -name '*$(SHARED_LIBRARY_SUFFIX)' -type f -print -o -name "*.dSYM" -prune)
 
 $(eval $(call SetupCopyFiles,STRIP_MODULES_CMDS, \
     SRC := $(SUPPORT_OUTPUTDIR)/modules_cmds, \
--- a/nashorn/.hgtags	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/.hgtags	Wed Jul 05 20:37:09 2017 +0200
@@ -300,3 +300,4 @@
 00df6e4fc75a83bdd958f9ef86d80e008c9ba967 jdk9-b64
 2054d01ae32649d3179e93d14108fdd6259c1c0d jdk9-b65
 9dd95cff9dae897e8dee712f1f0303c460262288 jdk9-b66
+f822b749821e364cae0b7bd7c8f667d9437e6d83 jdk9-b67
--- a/nashorn/README	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/README	Wed Jul 05 20:37:09 2017 +0200
@@ -72,14 +72,11 @@
 - Running tests
 
 Nashorn tests are TestNG based. Running tests requires downloading the
-TestNG library and placing its jar file into the lib subdirectory:
+TestNG library and placing its jar file into the test/lib subdirectory. This is
+done automatically when executing the "ant externals" command to get external
+test suites (see below).
 
-    # download and install TestNG
-    wget http://testng.org/testng-x.y.z.zip
-    unzip testng-x.y.z.zip
-    cp testng-x.y.z/testng-x.y.z.jar test/lib/testng.jar
-    
-After that, you can run the tests using:
+Once TestNG is properly installed, you can run the tests using:
     cd make
     ant clean test
     
--- a/nashorn/make/build.xml	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/make/build.xml	Wed Jul 05 20:37:09 2017 +0200
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 
 <!--
- Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 
  This code is free software; you can redistribute it and/or modify it
@@ -396,7 +396,7 @@
   </target>
 
   <target name="check-testng" unless="testng.available">
-    <echo message="WARNING: TestNG not available, will not run tests. Please copy testng.jar under test/lib directory."/>
+    <echo message="WARNING: TestNG not available, will not run tests. Please copy testng.jar under ${test.lib} directory."/>
   </target>
 
   <!-- only to be invoked as dependency of "test" target -->
@@ -469,7 +469,7 @@
     </testng>
   </target>
 
-  <target name="test" depends="javadoc, test-pessimistic, test-optimistic"/>
+  <target name="test" depends="get-testng, javadoc, test-pessimistic, test-optimistic"/>
 
   <target name="test-optimistic" depends="jar, -test-classes-all,-test-classes-single, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
     <echo message="Running test suite in OPTIMISTIC mode..."/>
@@ -499,7 +499,7 @@
     <echo message="WARNING: Jemmy or JavaFX or TestNG not available, will not run tests. Please copy testng.jar, JemmyCore.jar, JemmyFX.jar, JemmyAWTInput.jar under test${file.separator}lib directory. And make sure you have jfxrt.jar in ${java.home}${file.separator}lib${file.separator}ext dir."/>
   </target>
 
-  <target name="testjfx" depends="jar, check-jemmy.jfx.testng, compile-test" if="jemmy.jfx.testng.available">
+  <target name="testjfx" depends="jar, get-testng, check-jemmy.jfx.testng, compile-test" if="jemmy.jfx.testng.available">
     <fileset id="test.classes" dir="${build.test.classes.dir}">
        <include name="**/framework/*Test.class"/>
     </fileset>
@@ -527,7 +527,7 @@
     </testng>
   </target>
 
-  <target name="testmarkdown" depends="jar, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
+  <target name="testmarkdown" depends="jar, get-testng, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
     <fileset id="test.classes" dir="${build.test.classes.dir}">
        <include name="**/framework/*Test.class"/>
     </fileset>
@@ -546,7 +546,7 @@
     </testng>
   </target>
 
-  <target name="test262" depends="jar, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
+  <target name="test262" depends="jar, get-testng, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
     <fileset id="test.classes" dir="${build.test.classes.dir}">
        <include name="**/framework/*Test.class"/>
     </fileset>
@@ -570,7 +570,7 @@
 
   <target name="test262parallel" depends="test262-parallel"/>
 
-  <target name="test262-parallel" depends="jar, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
+  <target name="test262-parallel" depends="jar, get-testng, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
     <!-- use just build.test.classes.dir to avoid referring to TestNG -->
     <java classname="${parallel.test.runner}" dir="${basedir}" fork="true">
       <jvmarg line="${boot.class.path}"/>
@@ -589,7 +589,7 @@
 
   <target name="testparallel" depends="test-parallel"/>
 
-  <target name="test-parallel" depends="jar, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
+  <target name="test-parallel" depends="jar, get-testng, check-testng, check-external-tests, compile-test, generate-policy-file" if="testng.available">
       <!-- use just build.test.classes.dir to avoid referring to TestNG -->
       <java classname="${parallel.test.runner}" dir="${basedir}"
         failonerror="true"
@@ -694,7 +694,7 @@
   </target>
 
   <!-- get all external test scripts -->
-  <target name="externals" depends="init, check-external-tests, get-test262, get-octane, get-sunspider">
+  <target name="externals" depends="init, check-external-tests, get-test262, get-octane, get-sunspider, get-testng">
     <!-- make external test dir -->
     <mkdir dir="${test.external.dir}"/>
 
@@ -719,8 +719,8 @@
 
     <!-- showdown -->
     <mkdir dir="${test.external.dir}/showdown"/>
-    <get src="https://raw.github.com/coreyti/showdown/master/src/showdown.js" dest="${test.external.dir}/showdown" skipexisting="true" ignoreerrors="true"/>
-    <get src="https://raw.github.com/coreyti/showdown/master/src/extensions/table.js" dest="${test.external.dir}/showdown" skipexisting="true" ignoreerrors="true"/>
+    <get src="https://raw.githubusercontent.com/showdownjs/showdown/0.5.4/src/showdown.js" dest="${test.external.dir}/showdown" skipexisting="true" ignoreerrors="true"/>
+    <get src="https://raw.githubusercontent.com/showdownjs/showdown/0.5.4/src/extensions/table.js" dest="${test.external.dir}/showdown" skipexisting="true" ignoreerrors="true"/>
 
   </target>
 
@@ -730,12 +730,20 @@
   <!-- run all perf tests -->
   <target name="perf" depends="externals, update-externals, sunspider, octane"/>
 
-  <!-- run all tests -->
-  <target name="exit-if-no-testng" depends="init, check-testng" unless="${testng.available}">
-     <fail message="Exiting.."/>
+  <!-- download and install testng.jar -->
+  <target name="get-testng" depends="prepare" unless="testng.available">
+    <get src="http://testng.org/testng-6.8.zip" dest="${test.lib}" skipexisting="true" ignoreerrors="true"/>
+    <unzip src="${test.lib}${file.separator}testng-6.8.zip" dest="${test.lib}">
+      <patternset>
+        <include name="testng-6.8/testng-6.8.jar"/>
+      </patternset>
+    </unzip>
+    <move file="${test.lib}${file.separator}testng-6.8${file.separator}testng-6.8.jar" tofile="${test.lib}${file.separator}testng.jar"/>
+    <delete dir="${test.lib}${file.separator}testng-6.8"/>
   </target>
 
-  <target name="alltests" depends="exit-if-no-testng, externals, update-externals, test, test262parallel, perf"/>
+  <!-- run all tests -->
+  <target name="alltests" depends="get-testng, externals, update-externals, test, test262parallel, testmarkdown, perf"/>
 
   <import file="build-benchmark.xml"/>
 
--- a/nashorn/make/project.properties	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/make/project.properties	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -77,8 +77,11 @@
 # configuration for java flight recorder
 run.test.jvmargs.jfr=-XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:FlightRecorderOptions=defaultrecording=true,disk=true,dumponexit=true,dumponexitpath=${build.dir},stackdepth=128
 
+# test library location
+test.lib=${basedir}${file.separator}test${file.separator}lib
+
 # jars refererred
-file.reference.testng.jar=test/lib/testng.jar
+file.reference.testng.jar=${test.lib}${file.separator}testng.jar
 
 # Set testng verbose level
 # From TestNG docs: "the verbosity level (0 to 10 where 10 is most detailed)
@@ -243,9 +246,9 @@
     -fx \
     ${test.script.dir}${file.separator}jfx.js
 
-file.reference.jemmyfx.jar=test${file.separator}lib${file.separator}JemmyFX.jar
-file.reference.jemmycore.jar=test${file.separator}lib${file.separator}JemmyCore.jar
-file.reference.jemmyawtinput.jar=test${file.separator}lib${file.separator}JemmyAWTInput.jar
+file.reference.jemmyfx.jar=${test.lib}${file.separator}JemmyFX.jar
+file.reference.jemmycore.jar=${test.lib}${file.separator}JemmyCore.jar
+file.reference.jemmyawtinput.jar=${test.lib}${file.separator}JemmyAWTInput.jar
 file.reference.jfxrt.jar=${java.home}${file.separator}lib${file.separator}ext${file.separator}jfxrt.jar
 testjfx.run.test.classpath=\
     ${file.reference.jemmyfx.jar}${path.separator}\
--- a/nashorn/samples/find_nonfinals.js	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/samples/find_nonfinals.js	Wed Jul 05 20:37:09 2017 +0200
@@ -39,6 +39,7 @@
 
 var Class = Java.type("java.lang.Class");
 var System = Java.type("java.lang.System");
+var Thread = Java.type("java.lang.Thread");
 var File = Java.type("java.io.File");
 var JarFile = Java.type("java.util.jar.JarFile");
 var Modifier = Java.type("java.lang.reflect.Modifier");
@@ -58,6 +59,10 @@
 function analyzeClass(cls) {
     var methods = cls.getDeclaredMethods();
     for each (var method in methods) {
+        var methodModifiers = method.modifiers;
+        if (Modifier.isAbstract(methodModifiers) || Modifier.isNative(methodModifiers)) {
+            continue;
+        }
         // this requires -parameters option when compiling java sources
         var params = method.parameters;
         for each (var p in params) {
@@ -73,6 +78,8 @@
 }
 
 var jarFile = findNashorn();
+var ctxtLoader = Thread.currentThread().contextClassLoader;
+
 // load each class and use reflection to analyze each Class
 new JarFile(jarFile).stream().forEach(
     function(entry) {
@@ -80,8 +87,15 @@
         if (name.endsWith(".class")) {
             var clsName = name.substring(0, name.lastIndexOf('.class'));
             clsName = clsName.replace(/\//g, '.');
-            var cls = Class.forName(clsName);
-            analyzeClass(cls);
+            try {
+                // don't initialize to avoid for possible initialization errors 
+                var cls = Class.forName(clsName, false, ctxtLoader);
+                analyzeClass(cls);
+            } catch (e) {
+                // print exception and continue analysis for other classes
+                print("Failed to analyze " + clsName);
+                e.printStackTrace();
+            }
         }
     }
 )
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornScriptEngine.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornScriptEngine.java	Wed Jul 05 20:37:09 2017 +0200
@@ -354,8 +354,7 @@
             }
         }, CREATE_GLOBAL_ACC_CTXT);
 
-        nashornContext.initGlobal(newGlobal, this);
-        newGlobal.setScriptContext(ctxt);
+        nashornContext.initGlobal(newGlobal, this, ctxt);
 
         return newGlobal;
     }
@@ -404,7 +403,7 @@
         return evalImpl(script, ctxt, getNashornGlobalFrom(ctxt));
     }
 
-    private static Object evalImpl(final Context.MultiGlobalCompiledScript mgcs, final ScriptContext ctxt, final Global ctxtGlobal) throws ScriptException {
+    private Object evalImpl(final Context.MultiGlobalCompiledScript mgcs, final ScriptContext ctxt, final Global ctxtGlobal) throws ScriptException {
         final Global oldGlobal = Context.getGlobal();
         final boolean globalChanged = (oldGlobal != ctxtGlobal);
         try {
@@ -413,8 +412,13 @@
             }
 
             final ScriptFunction script = mgcs.getFunction(ctxtGlobal);
+            final ScriptContext oldCtxt = ctxtGlobal.getScriptContext();
             ctxtGlobal.setScriptContext(ctxt);
-            return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(ScriptRuntime.apply(script, ctxtGlobal), ctxtGlobal));
+            try {
+                return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(ScriptRuntime.apply(script, ctxtGlobal), ctxtGlobal));
+            } finally {
+                ctxtGlobal.setScriptContext(oldCtxt);
+            }
         } catch (final Exception e) {
             throwAsScriptException(e, ctxtGlobal);
             throw new AssertionError("should not reach here");
@@ -425,7 +429,7 @@
         }
     }
 
-    private static Object evalImpl(final ScriptFunction script, final ScriptContext ctxt, final Global ctxtGlobal) throws ScriptException {
+    private Object evalImpl(final ScriptFunction script, final ScriptContext ctxt, final Global ctxtGlobal) throws ScriptException {
         if (script == null) {
             return null;
         }
@@ -436,8 +440,13 @@
                 Context.setGlobal(ctxtGlobal);
             }
 
+            final ScriptContext oldCtxt = ctxtGlobal.getScriptContext();
             ctxtGlobal.setScriptContext(ctxt);
-            return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(ScriptRuntime.apply(script, ctxtGlobal), ctxtGlobal));
+            try {
+                return ScriptObjectMirror.translateUndefined(ScriptObjectMirror.wrap(ScriptRuntime.apply(script, ctxtGlobal), ctxtGlobal));
+            } finally {
+                ctxtGlobal.setScriptContext(oldCtxt);
+            }
         } catch (final Exception e) {
             throwAsScriptException(e, ctxtGlobal);
             throw new AssertionError("should not reach here");
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/ScriptObjectMirror.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/ScriptObjectMirror.java	Wed Jul 05 20:37:09 2017 +0200
@@ -47,6 +47,7 @@
 import jdk.nashorn.internal.runtime.ConsString;
 import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.ECMAException;
+import jdk.nashorn.internal.runtime.JSONListAdapter;
 import jdk.nashorn.internal.runtime.JSType;
 import jdk.nashorn.internal.runtime.ScriptFunction;
 import jdk.nashorn.internal.runtime.ScriptObject;
@@ -72,6 +73,7 @@
     private final ScriptObject sobj;
     private final Global  global;
     private final boolean strict;
+    private final boolean jsonCompatible;
 
     @Override
     public boolean equals(final Object other) {
@@ -110,9 +112,9 @@
             }
 
             if (sobj instanceof ScriptFunction) {
-                final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
-                final Object self = globalChanged? wrap(thiz, oldGlobal) : thiz;
-                return wrap(ScriptRuntime.apply((ScriptFunction)sobj, unwrap(self, global), unwrapArray(modArgs, global)), global);
+                final Object[] modArgs = globalChanged? wrapArrayLikeMe(args, oldGlobal) : args;
+                final Object self = globalChanged? wrapLikeMe(thiz, oldGlobal) : thiz;
+                return wrapLikeMe(ScriptRuntime.apply((ScriptFunction)sobj, unwrap(self, global), unwrapArray(modArgs, global)));
             }
 
             throw new RuntimeException("not a function: " + toString());
@@ -140,8 +142,8 @@
             }
 
             if (sobj instanceof ScriptFunction) {
-                final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
-                return wrap(ScriptRuntime.construct((ScriptFunction)sobj, unwrapArray(modArgs, global)), global);
+                final Object[] modArgs = globalChanged? wrapArrayLikeMe(args, oldGlobal) : args;
+                return wrapLikeMe(ScriptRuntime.construct((ScriptFunction)sobj, unwrapArray(modArgs, global)));
             }
 
             throw new RuntimeException("not a constructor: " + toString());
@@ -170,7 +172,7 @@
                                 return Context.getContext();
                             }
                         }, GET_CONTEXT_ACC_CTXT);
-                return wrap(context.eval(global, s, sobj, null, false), global);
+                return wrapLikeMe(context.eval(global, s, sobj, null, false));
             }
         });
     }
@@ -193,8 +195,8 @@
 
             final Object val = sobj.get(functionName);
             if (val instanceof ScriptFunction) {
-                final Object[] modArgs = globalChanged? wrapArray(args, oldGlobal) : args;
-                return wrap(ScriptRuntime.apply((ScriptFunction)val, sobj, unwrapArray(modArgs, global)), global);
+                final Object[] modArgs = globalChanged? wrapArrayLikeMe(args, oldGlobal) : args;
+                return wrapLikeMe(ScriptRuntime.apply((ScriptFunction)val, sobj, unwrapArray(modArgs, global)));
             } else if (val instanceof JSObject && ((JSObject)val).isFunction()) {
                 return ((JSObject)val).call(sobj, args);
             }
@@ -218,7 +220,7 @@
         Objects.requireNonNull(name);
         return inGlobal(new Callable<Object>() {
             @Override public Object call() {
-                return wrap(sobj.get(name), global);
+                return wrapLikeMe(sobj.get(name));
             }
         });
     }
@@ -227,7 +229,7 @@
     public Object getSlot(final int index) {
         return inGlobal(new Callable<Object>() {
             @Override public Object call() {
-                return wrap(sobj.get(index), global);
+                return wrapLikeMe(sobj.get(index));
             }
         });
     }
@@ -368,7 +370,7 @@
 
                 while (iter.hasNext()) {
                     final String key   = iter.next();
-                    final Object value = translateUndefined(wrap(sobj.get(key), global));
+                    final Object value = translateUndefined(wrapLikeMe(sobj.get(key)));
                     entries.add(new AbstractMap.SimpleImmutableEntry<>(key, value));
                 }
 
@@ -382,7 +384,7 @@
         checkKey(key);
         return inGlobal(new Callable<Object>() {
             @Override public Object call() {
-                return translateUndefined(wrap(sobj.get(key), global));
+                return translateUndefined(wrapLikeMe(sobj.get(key)));
             }
         });
     }
@@ -419,8 +421,8 @@
         final boolean globalChanged = (oldGlobal != global);
         return inGlobal(new Callable<Object>() {
             @Override public Object call() {
-                final Object modValue = globalChanged? wrap(value, oldGlobal) : value;
-                return translateUndefined(wrap(sobj.put(key, unwrap(modValue, global), strict), global));
+                final Object modValue = globalChanged? wrapLikeMe(value, oldGlobal) : value;
+                return translateUndefined(wrapLikeMe(sobj.put(key, unwrap(modValue, global), strict)));
             }
         });
     }
@@ -434,7 +436,7 @@
             @Override public Object call() {
                 for (final Map.Entry<? extends String, ? extends Object> entry : map.entrySet()) {
                     final Object value = entry.getValue();
-                    final Object modValue = globalChanged? wrap(value, oldGlobal) : value;
+                    final Object modValue = globalChanged? wrapLikeMe(value, oldGlobal) : value;
                     final String key = entry.getKey();
                     checkKey(key);
                     sobj.set(key, unwrap(modValue, global), getCallSiteFlags());
@@ -449,7 +451,7 @@
         checkKey(key);
         return inGlobal(new Callable<Object>() {
             @Override public Object call() {
-                return translateUndefined(wrap(sobj.remove(key, strict), global));
+                return translateUndefined(wrapLikeMe(sobj.remove(key, strict)));
             }
         });
     }
@@ -486,7 +488,7 @@
                 final Iterator<Object> iter   = sobj.valueIterator();
 
                 while (iter.hasNext()) {
-                    values.add(translateUndefined(wrap(iter.next(), global)));
+                    values.add(translateUndefined(wrapLikeMe(iter.next())));
                 }
 
                 return Collections.unmodifiableList(values);
@@ -503,7 +505,7 @@
     public Object getProto() {
         return inGlobal(new Callable<Object>() {
             @Override public Object call() {
-                return wrap(sobj.getProto(), global);
+                return wrapLikeMe(sobj.getProto());
             }
         });
     }
@@ -532,7 +534,7 @@
     public Object getOwnPropertyDescriptor(final String key) {
         return inGlobal(new Callable<Object>() {
             @Override public Object call() {
-                return wrap(sobj.getOwnPropertyDescriptor(key), global);
+                return wrapLikeMe(sobj.getOwnPropertyDescriptor(key));
             }
         });
     }
@@ -661,16 +663,76 @@
      * @return wrapped/converted object
      */
     public static Object wrap(final Object obj, final Object homeGlobal) {
+        return wrap(obj, homeGlobal, false);
+    }
+
+    /**
+     * Make a script object mirror on given object if needed. Also converts ConsString instances to Strings. The
+     * created wrapper will implement the Java {@code List} interface if {@code obj} is a JavaScript
+     * {@code Array} object; this is compatible with Java JSON libraries expectations. Arrays retrieved through its
+     * properties (transitively) will also implement the list interface.
+     *
+     * @param obj object to be wrapped/converted
+     * @param homeGlobal global to which this object belongs. Not used for ConsStrings.
+     * @return wrapped/converted object
+     */
+    public static Object wrapAsJSONCompatible(final Object obj, final Object homeGlobal) {
+        return wrap(obj, homeGlobal, true);
+    }
+
+    /**
+     * Make a script object mirror on given object if needed. Also converts ConsString instances to Strings.
+     *
+     * @param obj object to be wrapped/converted
+     * @param homeGlobal global to which this object belongs. Not used for ConsStrings.
+     * @param jsonCompatible if true, the created wrapper will implement the Java {@code List} interface if
+     * {@code obj} is a JavaScript {@code Array} object. Arrays retrieved through its properties (transitively)
+     * will also implement the list interface.
+     * @return wrapped/converted object
+     */
+    private static Object wrap(final Object obj, final Object homeGlobal, final boolean jsonCompatible) {
         if(obj instanceof ScriptObject) {
-            return homeGlobal instanceof Global ? new ScriptObjectMirror((ScriptObject)obj, (Global)homeGlobal) : obj;
-        }
-        if(obj instanceof ConsString) {
+            if (!(homeGlobal instanceof Global)) {
+                return obj;
+            }
+            final ScriptObject sobj = (ScriptObject)obj;
+            final Global global = (Global)homeGlobal;
+            final ScriptObjectMirror mirror = new ScriptObjectMirror(sobj, global, jsonCompatible);
+            if (jsonCompatible && sobj.isArray()) {
+                return new JSONListAdapter(mirror, global);
+            }
+            return mirror;
+        } else if(obj instanceof ConsString) {
             return obj.toString();
+        } else if (jsonCompatible && obj instanceof ScriptObjectMirror) {
+            // Since choosing JSON compatible representation is an explicit decision on user's part, if we're asked to
+            // wrap a mirror that was not JSON compatible, explicitly create its compatible counterpart following the
+            // principle of least surprise.
+            return ((ScriptObjectMirror)obj).asJSONCompatible();
         }
         return obj;
     }
 
     /**
+     * Wraps the passed object with the same jsonCompatible flag as this mirror.
+     * @param obj the object
+     * @param homeGlobal the object's home global.
+     * @return a wrapper for the object.
+     */
+    private Object wrapLikeMe(final Object obj, final Object homeGlobal) {
+        return wrap(obj, homeGlobal, jsonCompatible);
+    }
+
+    /**
+     * Wraps the passed object with the same home global and jsonCompatible flag as this mirror.
+     * @param obj the object
+     * @return a wrapper for the object.
+     */
+    private Object wrapLikeMe(final Object obj) {
+        return wrapLikeMe(obj, global);
+    }
+
+    /**
      * Unwrap a script object mirror if needed.
      *
      * @param obj object to be unwrapped
@@ -681,6 +743,8 @@
         if (obj instanceof ScriptObjectMirror) {
             final ScriptObjectMirror mirror = (ScriptObjectMirror)obj;
             return (mirror.global == homeGlobal)? mirror.sobj : obj;
+        } else if (obj instanceof JSONListAdapter) {
+            return ((JSONListAdapter)obj).unwrap(homeGlobal);
         }
 
         return obj;
@@ -694,6 +758,10 @@
      * @return wrapped array
      */
     public static Object[] wrapArray(final Object[] args, final Object homeGlobal) {
+        return wrapArray(args, homeGlobal, false);
+    }
+
+    private static Object[] wrapArray(final Object[] args, final Object homeGlobal, final boolean jsonCompatible) {
         if (args == null || args.length == 0) {
             return args;
         }
@@ -701,12 +769,16 @@
         final Object[] newArgs = new Object[args.length];
         int index = 0;
         for (final Object obj : args) {
-            newArgs[index] = wrap(obj, homeGlobal);
+            newArgs[index] = wrap(obj, homeGlobal, jsonCompatible);
             index++;
         }
         return newArgs;
     }
 
+    private Object[] wrapArrayLikeMe(final Object[] args, final Object homeGlobal) {
+        return wrapArray(args, homeGlobal, jsonCompatible);
+    }
+
     /**
      * Unwrap an array of script object mirrors if needed.
      *
@@ -748,12 +820,17 @@
     // package-privates below this.
 
     ScriptObjectMirror(final ScriptObject sobj, final Global global) {
+        this(sobj, global, false);
+    }
+
+    private ScriptObjectMirror(final ScriptObject sobj, final Global global, final boolean jsonCompatible) {
         assert sobj != null : "ScriptObjectMirror on null!";
         assert global != null : "home Global is null";
 
         this.sobj = sobj;
         this.global = global;
         this.strict = global.isStrictContext();
+        this.jsonCompatible = jsonCompatible;
     }
 
     // accessors for script engine
@@ -838,4 +915,11 @@
             }
         });
     }
+
+    private ScriptObjectMirror asJSONCompatible() {
+        if (this.jsonCompatible) {
+            return this;
+        }
+        return new ScriptObjectMirror(sobj, global, true);
+    }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ArrayAccessTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ArrayAccessTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -53,7 +53,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitArrayAccess(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ArrayLiteralTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ArrayLiteralTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -47,7 +47,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitArrayLiteral(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/AssignmentTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/AssignmentTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -55,7 +55,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitAssignment(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/BinaryTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/BinaryTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -55,7 +55,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitBinary(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/BlockTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/BlockTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -53,7 +53,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitBlock(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/BreakTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/BreakTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -46,7 +46,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitBreak(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/CaseTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/CaseTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -56,7 +56,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitCase(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/CatchTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/CatchTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -63,7 +63,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitCatch(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/CompilationUnitTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/CompilationUnitTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -67,7 +67,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitCompilationUnit(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/CompoundAssignmentTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/CompoundAssignmentTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -57,7 +57,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitCompoundAssignment(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ConditionalExpressionTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ConditionalExpressionTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -61,7 +61,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitConditionalExpression(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ContinueTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ContinueTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -46,7 +46,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitContinue(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/DebuggerTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/DebuggerTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -38,7 +38,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitDebugger(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/DoWhileLoopTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/DoWhileLoopTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -54,7 +54,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitDoWhileLoop(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/EmptyStatementTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/EmptyStatementTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -38,7 +38,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitEmptyStatement(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ErroneousTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ErroneousTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -38,7 +38,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitErroneous(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ExpressionStatementTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ExpressionStatementTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -46,7 +46,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitExpressionStatement(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ForInLoopTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ForInLoopTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -71,7 +71,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitForInLoop(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ForLoopTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ForLoopTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -72,7 +72,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitForLoop(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/FunctionCallTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/FunctionCallTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -55,7 +55,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitFunctionCall(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/FunctionDeclarationTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/FunctionDeclarationTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -74,7 +74,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitFunctionDeclaration(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/FunctionExpressionTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/FunctionExpressionTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -79,7 +79,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitFunctionExpression(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/IdentifierTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/IdentifierTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -47,7 +47,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitIdentifier(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/IfTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/IfTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -63,7 +63,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitIf(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/InstanceOfTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/InstanceOfTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -52,7 +52,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitInstanceOf(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/LabeledStatementTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/LabeledStatementTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -54,7 +54,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitLabeledStatement(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/LineMapImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/LineMapImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -35,12 +35,12 @@
     }
 
     @Override
-    public long getLineNumber(long pos) {
+    public long getLineNumber(final long pos) {
         return source.getLine((int)pos);
     }
 
     @Override
-    public long getColumnNumber(long pos) {
+    public long getColumnNumber(final long pos) {
         return source.getColumn((int)pos);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/LiteralTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/LiteralTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -61,7 +61,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitLiteral(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/MemberSelectTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/MemberSelectTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -53,7 +53,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitMemberSelect(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/NewTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/NewTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -47,7 +47,7 @@
     }
 
     @Override
-    public <R, D> R accept(TreeVisitor<R, D> visitor, D data) {
+    public <R, D> R accept(final TreeVisitor<R, D> visitor, final D data) {
         return visitor.visitNew(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ObjectLiteralTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ObjectLiteralTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -47,7 +47,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitObjectLiteral(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/PropertyTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/PropertyTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -70,7 +70,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitProperty(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/RegExpLiteralTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/RegExpLiteralTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -56,7 +56,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitRegExpLiteral(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ReturnTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ReturnTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -46,7 +46,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitReturn(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/SimpleTreeVisitorES5_1.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/SimpleTreeVisitorES5_1.java	Wed Jul 05 20:37:09 2017 +0200
@@ -48,28 +48,28 @@
  */
 public class SimpleTreeVisitorES5_1<R, P> implements TreeVisitor<R, P> {
     @Override
-    public R visitAssignment(AssignmentTree node, P r) {
+    public R visitAssignment(final AssignmentTree node, final P r) {
         node.getVariable().accept(this, r);
         node.getExpression().accept(this, r);
         return null;
     }
 
     @Override
-    public R visitCompoundAssignment(CompoundAssignmentTree node, P r) {
+    public R visitCompoundAssignment(final CompoundAssignmentTree node, final P r) {
         node.getVariable().accept(this, r);
         node.getExpression().accept(this, r);
         return null;
     }
 
     @Override
-    public R visitBinary(BinaryTree node, P r) {
+    public R visitBinary(final BinaryTree node, final P r) {
         node.getLeftOperand().accept(this, r);
         node.getRightOperand().accept(this, r);
         return null;
     }
 
     @Override
-    public R visitBlock(BlockTree node, P r) {
+    public R visitBlock(final BlockTree node, final P r) {
         node.getStatements().forEach((tree) -> {
             tree.accept(this, r);
         });
@@ -77,12 +77,12 @@
     }
 
     @Override
-    public R visitBreak(BreakTree node, P r) {
+    public R visitBreak(final BreakTree node, final P r) {
         return null;
     }
 
     @Override
-    public R visitCase(CaseTree node, P r) {
+    public R visitCase(final CaseTree node, final P r) {
         final Tree caseVal = node.getExpression();
         if (caseVal != null) {
             caseVal.accept(this, r);
@@ -95,7 +95,7 @@
     }
 
     @Override
-    public R visitCatch(CatchTree node, P r) {
+    public R visitCatch(final CatchTree node, final P r) {
         final Tree cond = node.getCondition();
         if (cond != null) {
             cond.accept(this, r);
@@ -106,7 +106,7 @@
     }
 
     @Override
-    public R visitConditionalExpression(ConditionalExpressionTree node, P r) {
+    public R visitConditionalExpression(final ConditionalExpressionTree node, final P r) {
         node.getCondition().accept(this, r);
         node.getTrueExpression().accept(this, r);
         node.getFalseExpression().accept(this, r);
@@ -114,35 +114,35 @@
     }
 
     @Override
-    public R visitContinue(ContinueTree node, P r) {
+    public R visitContinue(final ContinueTree node, final P r) {
         return null;
     }
 
     @Override
-    public R visitDebugger(DebuggerTree node, P r) {
+    public R visitDebugger(final DebuggerTree node, final P r) {
         return null;
     }
 
     @Override
-    public R visitDoWhileLoop(DoWhileLoopTree node, P r) {
+    public R visitDoWhileLoop(final DoWhileLoopTree node, final P r) {
         node.getStatement().accept(this, r);
         node.getCondition().accept(this, r);
         return null;
     }
 
     @Override
-    public R visitErroneous(ErroneousTree node, P r) {
+    public R visitErroneous(final ErroneousTree node, final P r) {
         return null;
     }
 
     @Override
-    public R visitExpressionStatement(ExpressionStatementTree node, P r) {
+    public R visitExpressionStatement(final ExpressionStatementTree node, final P r) {
         node.getExpression().accept(this, r);
         return null;
     }
 
     @Override
-    public R visitForLoop(ForLoopTree node, P r) {
+    public R visitForLoop(final ForLoopTree node, final P r) {
         final Tree init = node.getInitializer();
         if (init != null) {
             init.accept(this, r);
@@ -163,7 +163,7 @@
     }
 
     @Override
-    public R visitForInLoop(ForInLoopTree node, P r) {
+    public R visitForInLoop(final ForInLoopTree node, final P r) {
         node.getVariable().accept(this, r);
         node.getExpression().accept(this, r);
         final StatementTree stat = node.getStatement();
@@ -174,7 +174,7 @@
     }
 
     @Override
-    public R visitFunctionCall(FunctionCallTree node, P r) {
+    public R visitFunctionCall(final FunctionCallTree node, final P r) {
         node.getFunctionSelect().accept(this, r);
         node.getArguments().forEach((tree) -> {
             tree.accept(this, r);
@@ -183,7 +183,7 @@
     }
 
     @Override
-    public R visitFunctionDeclaration(FunctionDeclarationTree node, P r) {
+    public R visitFunctionDeclaration(final FunctionDeclarationTree node, final P r) {
         node.getParameters().forEach((tree) -> {
             tree.accept(this, r);
         });
@@ -192,7 +192,7 @@
     }
 
     @Override
-    public R visitFunctionExpression(FunctionExpressionTree node, P r) {
+    public R visitFunctionExpression(final FunctionExpressionTree node, final P r) {
         node.getParameters().forEach((tree) -> {
             tree.accept(this, r);
         });
@@ -201,12 +201,12 @@
     }
 
     @Override
-    public R visitIdentifier(IdentifierTree node, P r) {
+    public R visitIdentifier(final IdentifierTree node, final P r) {
         return null;
     }
 
     @Override
-    public R visitIf(IfTree node, P r) {
+    public R visitIf(final IfTree node, final P r) {
         node.getCondition().accept(this, r);
         node.getThenStatement().accept(this, r);
         final Tree elseStat = node.getElseStatement();
@@ -217,14 +217,14 @@
     }
 
     @Override
-    public R visitArrayAccess(ArrayAccessTree node, P r) {
+    public R visitArrayAccess(final ArrayAccessTree node, final P r) {
         node.getExpression().accept(this, r);
         node.getIndex().accept(this, r);
         return null;
     }
 
     @Override
-    public R visitArrayLiteral(ArrayLiteralTree node, P r) {
+    public R visitArrayLiteral(final ArrayLiteralTree node, final P r) {
         node.getElements().stream().filter((tree) -> (tree != null)).forEach((tree) -> {
             tree.accept(this, r);
         });
@@ -232,24 +232,24 @@
     }
 
     @Override
-    public R visitLabeledStatement(LabeledStatementTree node, P r) {
+    public R visitLabeledStatement(final LabeledStatementTree node, final P r) {
         node.getStatement().accept(this, r);
         return null;
     }
 
     @Override
-    public R visitLiteral(LiteralTree node, P r) {
+    public R visitLiteral(final LiteralTree node, final P r) {
         return null;
     }
 
     @Override
-    public R visitParenthesized(ParenthesizedTree node, P r) {
+    public R visitParenthesized(final ParenthesizedTree node, final P r) {
         node.getExpression().accept(this, r);
         return null;
     }
 
     @Override
-    public R visitReturn(ReturnTree node, P r) {
+    public R visitReturn(final ReturnTree node, final P r) {
         final Tree retExpr = node.getExpression();
         if (retExpr != null) {
             retExpr.accept(this, r);
@@ -258,19 +258,19 @@
     }
 
     @Override
-    public R visitMemberSelect(MemberSelectTree node, P r) {
+    public R visitMemberSelect(final MemberSelectTree node, final P r) {
         node.getExpression().accept(this, r);
         return null;
     }
 
     @Override
-    public R visitNew(NewTree node, P r) {
+    public R visitNew(final NewTree node, final P r) {
         node.getConstructorExpression().accept(this, r);
         return null;
     }
 
     @Override
-    public R visitObjectLiteral(ObjectLiteralTree node, P r) {
+    public R visitObjectLiteral(final ObjectLiteralTree node, final P r) {
         node.getProperties().forEach((tree) -> {
             tree.accept(this, r);
         });
@@ -278,7 +278,7 @@
     }
 
     @Override
-    public R visitProperty(PropertyTree node, P r) {
+    public R visitProperty(final PropertyTree node, final P r) {
         FunctionExpressionTree getter = node.getGetter();
         if (getter != null) {
             getter.accept(this, r);
@@ -301,17 +301,17 @@
     }
 
     @Override
-    public R visitRegExpLiteral(RegExpLiteralTree node, P r) {
+    public R visitRegExpLiteral(final RegExpLiteralTree node, final P r) {
         return null;
     }
 
     @Override
-    public R visitEmptyStatement(EmptyStatementTree node, P r) {
+    public R visitEmptyStatement(final EmptyStatementTree node, final P r) {
         return null;
     }
 
     @Override
-    public R visitSwitch(SwitchTree node, P r) {
+    public R visitSwitch(final SwitchTree node, final P r) {
         node.getExpression().accept(this, r);
         node.getCases().forEach((tree) -> {
             tree.accept(this, r);
@@ -320,13 +320,13 @@
     }
 
     @Override
-    public R visitThrow(ThrowTree node, P r) {
+    public R visitThrow(final ThrowTree node, final P r) {
         node.getExpression().accept(this, r);
         return null;
     }
 
     @Override
-    public R visitCompilationUnit(CompilationUnitTree node, P r) {
+    public R visitCompilationUnit(final CompilationUnitTree node, final P r) {
         node.getSourceElements().forEach((tree) -> {
             tree.accept(this, r);
         });
@@ -334,7 +334,7 @@
     }
 
     @Override
-    public R visitTry(TryTree node, P r) {
+    public R visitTry(final TryTree node, final P r) {
         node.getBlock().accept(this, r);
         node.getCatches().forEach((tree) -> {
             tree.accept(this, r);
@@ -348,20 +348,20 @@
     }
 
     @Override
-    public R visitInstanceOf(InstanceOfTree node, P r) {
+    public R visitInstanceOf(final InstanceOfTree node, final P r) {
         node.getType().accept(this, r);
         node.getExpression().accept(this, r);
         return null;
     }
 
     @Override
-    public R visitUnary(UnaryTree node, P r) {
+    public R visitUnary(final UnaryTree node, final P r) {
         node.getExpression().accept(this, r);
         return null;
     }
 
     @Override
-    public R visitVariable(VariableTree node, P r) {
+    public R visitVariable(final VariableTree node, final P r) {
         if (node.getInitializer() != null) {
             node.getInitializer().accept(this, r);
         }
@@ -369,21 +369,21 @@
     }
 
     @Override
-    public R visitWhileLoop(WhileLoopTree node, P r) {
+    public R visitWhileLoop(final WhileLoopTree node, final P r) {
         node.getCondition().accept(this, r);
         node.getStatement().accept(this, r);
         return null;
     }
 
     @Override
-    public R visitWith(WithTree node, P r) {
+    public R visitWith(final WithTree node, final P r) {
         node.getScope().accept(this, r);
         node.getStatement().accept(this, r);
         return null;
     }
 
     @Override
-    public R visitUnknown(Tree node, P r) {
+    public R visitUnknown(final Tree node, final P r) {
         // unknown in ECMAScript 5.1 edition
         throw new UnknownTreeException(node, r);
     }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/SwitchTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/SwitchTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -55,7 +55,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitSwitch(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ThrowTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ThrowTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -45,7 +45,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitThrow(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/TreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/TreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -47,7 +47,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitUnknown(this, data);
     }
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/TryTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/TryTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -63,7 +63,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitTry(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/UnaryTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/UnaryTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -47,7 +47,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitUnary(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/VariableTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/VariableTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -53,7 +53,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitVariable(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/WhileLoopTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/WhileLoopTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -54,7 +54,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitWhileLoop(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/WithTreeImpl.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/WithTreeImpl.java	Wed Jul 05 20:37:09 2017 +0200
@@ -53,7 +53,7 @@
     }
 
     @Override
-    public <R,D> R accept(TreeVisitor<R,D> visitor, D data) {
+    public <R,D> R accept(final TreeVisitor<R,D> visitor, final D data) {
         return visitor.visitWith(this, data);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompilationPhase.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompilationPhase.java	Wed Jul 05 20:37:09 2017 +0200
@@ -363,7 +363,7 @@
             //partial code generation
             final FunctionNode newFunctionNode = transformFunction(fn, new ReplaceCompileUnits() {
                 @Override
-                CompileUnit getReplacement(CompileUnit original) {
+                CompileUnit getReplacement(final CompileUnit original) {
                     return map.get(original);
                 }
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java	Wed Jul 05 20:37:09 2017 +0200
@@ -567,7 +567,7 @@
         final MessageDigest digest = MessageDigest.getInstance("SHA-1");
         Files.walk(nashorn).forEach(new Consumer<Path>() {
             @Override
-            public void accept(Path p) {
+            public void accept(final Path p) {
                 // take only the .class resources.
                 if (Files.isRegularFile(p) && p.toString().endsWith(".class")) {
                     try {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SplitIntoFunctions.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SplitIntoFunctions.java	Wed Jul 05 20:37:09 2017 +0200
@@ -102,7 +102,7 @@
     public SplitIntoFunctions(final Compiler compiler) {
         super(new BlockLexicalContext() {
             @Override
-            protected Block afterSetStatements(Block block) {
+            protected Block afterSetStatements(final Block block) {
                 for(Statement stmt: block.getStatements()) {
                     assert !(stmt instanceof SplitNode);
                 }
@@ -305,7 +305,7 @@
     }
 
     @Override
-    public boolean enterVarNode(VarNode varNode) {
+    public boolean enterVarNode(final VarNode varNode) {
         if (!inSplitNode()) {
             return super.enterVarNode(varNode);
         }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/SplitReturn.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/SplitReturn.java	Wed Jul 05 20:37:09 2017 +0200
@@ -54,7 +54,7 @@
     }
 
     @Override
-    public void toString(StringBuilder sb, boolean printType) {
+    public void toString(final StringBuilder sb, final boolean printType) {
         sb.append(":splitreturn;");
     }
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/TryNode.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/TryNode.java	Wed Jul 05 20:37:09 2017 +0200
@@ -122,7 +122,7 @@
      * @param visitor IR navigating visitor.
      */
     @Override
-    public Node accept(final LexicalContext lc, NodeVisitor<? extends LexicalContext> visitor) {
+    public Node accept(final LexicalContext lc, final NodeVisitor<? extends LexicalContext> visitor) {
         if (visitor.enterTryNode(this)) {
             // Need to do finallybody first for termination analysis. TODO still necessary?
             final Block newFinallyBody = finallyBody == null ? null : (Block)finallyBody.accept(visitor);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/NashornTextifier.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/NashornTextifier.java	Wed Jul 05 20:37:09 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1109,7 +1109,7 @@
                 }
                 final String ex = catches.get(node);
                 if (ex != null) {
-                    sb.append("*** CATCH: ").append(ex).append(" ***\n");
+                    sb.append("*** CATCH: ").append(ex).append(" ***\\l");
                 }
                 sb.append(c);
                 sb.append("\"]\n");
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java	Wed Jul 05 20:37:09 2017 +0200
@@ -928,9 +928,11 @@
     private final Context context;
 
     // current ScriptContext to use - can be null.
-    private ScriptContext scontext;
+    private ThreadLocal<ScriptContext> scontext;
     // current ScriptEngine associated - can be null.
     private ScriptEngine engine;
+    // initial ScriptContext - can be null
+    private volatile ScriptContext initscontext;
 
     // ES6 global lexical scope.
     private final LexicalScope lexicalScope;
@@ -940,10 +942,25 @@
 
     /**
      * Set the current script context
-     * @param scontext script context
+     * @param ctxt script context
      */
-    public void setScriptContext(final ScriptContext scontext) {
-        this.scontext = scontext;
+    public void setScriptContext(final ScriptContext ctxt) {
+        assert scontext != null;
+        scontext.set(ctxt);
+    }
+
+    /**
+     * Get the current script context
+     * @return current script context
+     */
+    public ScriptContext getScriptContext() {
+        assert scontext != null;
+        return scontext.get();
+    }
+
+    private ScriptContext currentContext() {
+        final ScriptContext sc = scontext != null? scontext.get() : null;
+        return sc == null? initscontext : sc;
     }
 
     @Override
@@ -1056,14 +1073,19 @@
      * of the global scope object.
      *
      * @param eng ScriptEngine to initialize
+     * @param ctxt ScriptContext to initialize
      */
-    public void initBuiltinObjects(final ScriptEngine eng) {
+    public void initBuiltinObjects(final ScriptEngine eng, final ScriptContext ctxt) {
         if (this.builtinObject != null) {
             // already initialized, just return
             return;
         }
 
         this.engine = eng;
+        this.initscontext = ctxt;
+        if (this.engine != null) {
+            this.scontext = new ThreadLocal<>();
+        }
         init(eng);
     }
 
@@ -1392,7 +1414,7 @@
      */
     public static Object __noSuchProperty__(final Object self, final Object name) {
         final Global global = Global.instance();
-        final ScriptContext sctxt = global.scontext;
+        final ScriptContext sctxt = global.currentContext();
         final String nameStr = name.toString();
 
         if (sctxt != null) {
@@ -2737,8 +2759,9 @@
     }
 
     private Object printImpl(final boolean newLine, final Object... objects) {
+        final ScriptContext sc = currentContext();
         @SuppressWarnings("resource")
-        final PrintWriter out = scontext != null? new PrintWriter(scontext.getWriter()) : getContext().getEnv().getOut();
+        final PrintWriter out = sc != null? new PrintWriter(sc.getWriter()) : getContext().getEnv().getOut();
         final StringBuilder sb = new StringBuilder();
 
         for (final Object obj : objects) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJava.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJava.java	Wed Jul 05 20:37:09 2017 +0200
@@ -33,10 +33,12 @@
 import java.util.Collection;
 import java.util.Deque;
 import java.util.List;
+import java.util.Map;
 import java.util.Queue;
 import jdk.internal.dynalink.beans.StaticClass;
 import jdk.internal.dynalink.support.TypeUtilities;
 import jdk.nashorn.api.scripting.JSObject;
+import jdk.nashorn.api.scripting.ScriptObjectMirror;
 import jdk.nashorn.internal.objects.annotations.Attribute;
 import jdk.nashorn.internal.objects.annotations.Function;
 import jdk.nashorn.internal.objects.annotations.ScriptClass;
@@ -656,4 +658,20 @@
     public static Object _super(final Object self, final Object adapter) {
         return Bootstrap.createSuperAdapter(adapter);
     }
+
+    /**
+     * Returns an object that is compatible with Java JSON libraries expectations; namely, that if it itself, or any
+     * object transitively reachable through it is a JavaScript array, then such objects will be exposed as
+     * {@link JSObject} that also implements the {@link List} interface for exposing the array elements. An explicit
+     * API is required as otherwise Nashorn exposes all objects externally as {@link JSObject}s that also implement the
+     * {@link Map} interface instead. By using this method, arrays will be exposed as {@link List}s and all other
+     * objects as {@link Map}s.
+     * @param self not used
+     * @param obj the object to be exposed in a Java JSON library compatible manner.
+     * @return a wrapper around the object that will enforce Java JSON library compatible exposure.
+     */
+    @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
+    public static Object asJSONCompatible(final Object self, final Object obj) {
+        return ScriptObjectMirror.wrapAsJSONCompatible(obj, Context.getGlobal());
+    }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CompiledFunction.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CompiledFunction.java	Wed Jul 05 20:37:09 2017 +0200
@@ -528,8 +528,9 @@
 
         final int fnParamCountNoCallee = fnParamCount - thisThisIndex;
         final int minParams = Math.min(csParamCount - 1, fnParamCountNoCallee); // callSiteType always has callee, so subtract 1
-        // We must match all incoming parameters, except "this". Starting from 1 to skip "this".
-        for(int i = 1; i < minParams; ++i) {
+        // We must match all incoming parameters, including "this". "this" will usually be Object, but there
+        // are exceptions, e.g. when calling functions with primitive "this" in strict mode or through call/apply.
+        for(int i = 0; i < minParams; ++i) {
             final Type fnType = Type.typeFor(type.parameterType(i + thisThisIndex));
             final Type csType = csIsVarArg ? Type.OBJECT : Type.typeFor(other.parameterType(i + 1));
             if(!fnType.isEquivalentTo(csType)) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java	Wed Jul 05 20:37:09 2017 +0200
@@ -66,6 +66,7 @@
 import java.util.function.Consumer;
 import java.util.function.Supplier;
 import java.util.logging.Level;
+import javax.script.ScriptContext;
 import javax.script.ScriptEngine;
 import jdk.internal.org.objectweb.asm.ClassReader;
 import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
@@ -1095,16 +1096,17 @@
      *
      * @param global the global
      * @param engine the associated ScriptEngine instance, can be null
+     * @param ctxt the initial ScriptContext, can be null
      * @return the initialized global scope object.
      */
-    public Global initGlobal(final Global global, final ScriptEngine engine) {
+    public Global initGlobal(final Global global, final ScriptEngine engine, final ScriptContext ctxt) {
         // Need only minimal global object, if we are just compiling.
         if (!env._compile_only) {
             final Global oldGlobal = Context.getGlobal();
             try {
                 Context.setGlobal(global);
                 // initialize global scope with builtin global objects
-                global.initBuiltinObjects(engine);
+                global.initBuiltinObjects(engine, ctxt);
             } finally {
                 Context.setGlobal(oldGlobal);
             }
@@ -1120,7 +1122,7 @@
      * @return the initialized global scope object.
      */
     public Global initGlobal(final Global global) {
-        return initGlobal(global, null);
+        return initGlobal(global, null, null);
     }
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSONListAdapter.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.runtime;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import jdk.nashorn.api.scripting.JSObject;
+import jdk.nashorn.api.scripting.ScriptObjectMirror;
+import jdk.nashorn.internal.objects.Global;
+
+/**
+ * A {@link ListAdapter} that also implements {@link JSObject}. Named {@code JSONListAdapter} as it is used as a
+ * {@code JSObject} implementing the {@link List} interface, which is the expected interface to be implemented by
+ * JSON-parsed arrays when they are handled in Java. We aren't implementing {@link JSObject} on {@link ListAdapter}
+ * directly since that'd have implications for other uses of list adapter (e.g. interferences of JSObject default
+ * value calculation vs. List's {@code toString()} etc.)
+ */
+public final class JSONListAdapter extends ListAdapter implements JSObject {
+    /**
+     * Creates a new JSON list adapter.
+     * @param obj the underlying object being exposed as a list.
+     * @param global the home global of the underlying object.
+     */
+    public JSONListAdapter(final JSObject obj, final Global global) {
+        super(obj, global);
+    }
+
+    /**
+     * Unwraps this adapter into its underlying non-JSObject representative.
+     * @param homeGlobal the home global for unwrapping
+     * @return either the unwrapped object or this if it should not be unwrapped in the specified global.
+     */
+    public Object unwrap(final Object homeGlobal) {
+        final Object unwrapped = ScriptObjectMirror.unwrap(obj, homeGlobal);
+        return unwrapped != obj ? unwrapped : this;
+    }
+
+    @Override
+    public Object call(final Object thiz, final Object... args) {
+        return obj.call(thiz, args);
+    }
+
+    @Override
+    public Object newObject(final Object... args) {
+        return obj.newObject(args);
+    }
+
+    @Override
+    public Object eval(final String s) {
+        return obj.eval(s);
+    }
+
+    @Override
+    public Object getMember(final String name) {
+        return obj.getMember(name);
+    }
+
+    @Override
+    public Object getSlot(final int index) {
+        return obj.getSlot(index);
+    }
+
+    @Override
+    public boolean hasMember(final String name) {
+        return obj.hasMember(name);
+    }
+
+    @Override
+    public boolean hasSlot(final int slot) {
+        return obj.hasSlot(slot);
+    }
+
+    @Override
+    public void removeMember(final String name) {
+        obj.removeMember(name);
+    }
+
+    @Override
+    public void setMember(final String name, final Object value) {
+        obj.setMember(name, value);
+    }
+
+    @Override
+    public void setSlot(final int index, final Object value) {
+        obj.setSlot(index, value);
+    }
+
+    @Override
+    public Set<String> keySet() {
+        return obj.keySet();
+    }
+
+    @Override
+    public Collection<Object> values() {
+        return obj.values();
+    }
+
+    @Override
+    public boolean isInstance(final Object instance) {
+        return obj.isInstance(instance);
+    }
+
+    @Override
+    public boolean isInstanceOf(final Object clazz) {
+        return obj.isInstanceOf(clazz);
+    }
+
+    @Override
+    public String getClassName() {
+        return obj.getClassName();
+    }
+
+    @Override
+    public boolean isFunction() {
+        return obj.isFunction();
+    }
+
+    @Override
+    public boolean isStrictFunction() {
+        return obj.isStrictFunction();
+    }
+
+    @Override
+    public boolean isArray() {
+        return obj.isArray();
+    }
+
+    @Override @Deprecated
+    public double toNumber() {
+        return obj.toNumber();
+    }
+
+    @Override
+    public Object getDefaultValue(Class<?> hint) throws UnsupportedOperationException {
+        return obj.getDefaultValue(hint);
+    }
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ListAdapter.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ListAdapter.java	Wed Jul 05 20:37:09 2017 +0200
@@ -52,7 +52,7 @@
  * operations respectively, while {@link #addLast(Object)} and {@link #removeLast()} will translate to {@code push} and
  * {@code pop}.
  */
-public final class ListAdapter extends AbstractList<Object> implements RandomAccess, Deque<Object> {
+public class ListAdapter extends AbstractList<Object> implements RandomAccess, Deque<Object> {
     // Invoker creator for methods that add to the start or end of the list: PUSH and UNSHIFT. Takes fn, this, and value, returns void.
     private static final Callable<MethodHandle> ADD_INVOKER_CREATOR = invokerCreator(void.class, Object.class, JSObject.class, Object.class);
 
@@ -78,21 +78,17 @@
     private static final Callable<MethodHandle> SPLICE_REMOVE_INVOKER_CREATOR = invokerCreator(void.class, Object.class, JSObject.class, int.class, int.class);
 
     /** wrapped object */
-    private final JSObject obj;
+    final JSObject obj;
     private final Global global;
 
     // allow subclasses only in this package
-    ListAdapter(final JSObject obj) {
-        this.obj = obj;
-        this.global = getGlobalNonNull();
-    }
+    ListAdapter(final JSObject obj, final Global global) {
+        if (global == null) {
+            throw new IllegalStateException(ECMAErrors.getMessage("list.adapter.null.global"));
+        }
 
-    private static Global getGlobalNonNull() {
-        final Global global = Context.getGlobal();
-        if (global != null) {
-            return global;
-        }
-        throw new IllegalStateException(ECMAErrors.getMessage("list.adapter.null.global"));
+        this.obj = obj;
+        this.global = global;
     }
 
     /**
@@ -102,12 +98,13 @@
      * @return A ListAdapter wrapper object
      */
     public static ListAdapter create(final Object obj) {
-        return new ListAdapter(getJSObject(obj));
+        final Global global = Context.getGlobal();
+        return new ListAdapter(getJSObject(obj, global), global);
     }
 
-    private static JSObject getJSObject(final Object obj) {
+    private static JSObject getJSObject(final Object obj, final Global global) {
         if (obj instanceof ScriptObject) {
-            return (JSObject)ScriptObjectMirror.wrap(obj, Context.getGlobal());
+            return (JSObject)ScriptObjectMirror.wrap(obj, global);
         } else if (obj instanceof JSObject) {
             return (JSObject)obj;
         }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java	Wed Jul 05 20:37:09 2017 +0200
@@ -137,7 +137,7 @@
         final ScriptObject global = Context.getGlobal();
 
         // Set up initial process.
-        final ProcessBuilder processBuilder = new ProcessBuilder(tokenizeCommandLine(JSType.toString(string)));
+        final ProcessBuilder processBuilder = new ProcessBuilder(tokenizeString(JSType.toString(string)));
 
         // Current ENV property state.
         final Object env = global.get(ENV_NAME);
@@ -237,23 +237,22 @@
     }
 
     /**
-     * Break an exec string into tokens, honoring quoted arguments and escaped
-     * spaces.
+     * Break a string into tokens, honoring quoted arguments and escaped spaces.
      *
-     * @param execString a {@link String} with the command line to execute.
+     * @param str a {@link String} to tokenize.
      * @return a {@link List} of {@link String}s representing the tokens that
-     * constitute the command line.
+     * constitute the string.
      * @throws IOException in case {@link StreamTokenizer#nextToken()} raises it.
      */
-    public static List<String> tokenizeCommandLine(final String execString) throws IOException {
-        final StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(execString));
+    public static List<String> tokenizeString(final String str) throws IOException {
+        final StreamTokenizer tokenizer = new StreamTokenizer(new StringReader(str));
         tokenizer.resetSyntax();
         tokenizer.wordChars(0, 255);
         tokenizer.whitespaceChars(0, ' ');
         tokenizer.commentChar('#');
         tokenizer.quoteChar('"');
         tokenizer.quoteChar('\'');
-        final List<String> cmdList = new ArrayList<>();
+        final List<String> tokenList = new ArrayList<>();
         final StringBuilder toAppend = new StringBuilder();
         while (tokenizer.nextToken() != StreamTokenizer.TT_EOF) {
             final String s = tokenizer.sval;
@@ -265,13 +264,13 @@
                 // omit trailing \, append space instead
                 toAppend.append(s.substring(0, s.length() - 1)).append(' ');
             } else {
-                cmdList.add(toAppend.append(s).toString());
+                tokenList.add(toAppend.append(s).toString());
                 toAppend.setLength(0);
             }
         }
         if (toAppend.length() != 0) {
-            cmdList.add(toAppend.toString());
+            tokenList.add(toAppend.toString());
         }
-        return cmdList;
+        return tokenList;
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Source.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Source.java	Wed Jul 05 20:37:09 2017 +0200
@@ -934,14 +934,16 @@
             start = 2;
             cs = StandardCharsets.UTF_16BE;
         } else if (bytes.length > 1 && bytes[0] == (byte) 0xFF && bytes[1] == (byte) 0xFE) {
-            start = 2;
-            cs = StandardCharsets.UTF_16LE;
+            if (bytes.length > 3 && bytes[2] == 0 && bytes[3] == 0) {
+                start = 4;
+                cs = Charset.forName("UTF-32LE");
+            } else {
+                start = 2;
+                cs = StandardCharsets.UTF_16LE;
+            }
         } else if (bytes.length > 2 && bytes[0] == (byte) 0xEF && bytes[1] == (byte) 0xBB && bytes[2] == (byte) 0xBF) {
             start = 3;
             cs = StandardCharsets.UTF_8;
-        } else if (bytes.length > 3 && bytes[0] == (byte) 0xFF && bytes[1] == (byte) 0xFE && bytes[2] == 0 && bytes[3] == 0) {
-            start = 4;
-            cs = Charset.forName("UTF-32LE");
         } else if (bytes.length > 3 && bytes[0] == 0 && bytes[1] == 0 && bytes[2] == (byte) 0xFE && bytes[3] == (byte) 0xFF) {
             start = 4;
             cs = Charset.forName("UTF-32BE");
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java	Wed Jul 05 20:37:09 2017 +0200
@@ -246,7 +246,7 @@
         }
 
         @Override
-        public MethodHandle filterInternalObjects(MethodHandle target) {
+        public MethodHandle filterInternalObjects(final MethodHandle target) {
             return linkerServices.filterInternalObjects(target);
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/ProblemList.txt	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,26 @@
+###########################################################################
+#
+# Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+###########################################################################
+
+# No nashorn tests are on the problem list.
--- a/nashorn/test/TEST.ROOT	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/test/TEST.ROOT	Wed Jul 05 20:37:09 2017 +0200
@@ -1,6 +1,11 @@
 # This file identifies the root of the test-suite hierarchy.
 # It also contains test-suite configuration information.
-# DO NOT EDIT without first contacting jdk-regtest@sun.com.
 
 # The list of keywords supported in the entire test suite
-keys=2d dnd i18n
+keys=intermittent randomness
+
+# Group definitions
+groups=TEST.groups
+
+# Minimum jtreg version
+requiredVersion=4.1 b11
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/TEST.groups	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,29 @@
+#  Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+#  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+#  This code is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU General Public License version 2 only, as
+#  published by the Free Software Foundation.
+#
+#  This code is distributed in the hope that it will be useful, but WITHOUT
+#  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+#  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+#  version 2 for more details (a copy is included in the LICENSE file that
+#  accompanied this code).
+#
+#  You should have received a copy of the GNU General Public License version
+#  2 along with this work; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+#  Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+#  or visit www.oracle.com if you need additional information or have any
+#  questions.
+#
+
+# Tiered testing definitions
+
+# No nashorn tests are tier 1.
+tier1 =
+
+# All nashorn tests are tier 2.
+tier2 = src
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8066220.js	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8066220: Fuzzing bug: MethodHandle bug (Object,Object) != (boolean)Object
+ *
+ * @test
+ * @run
+ */
+
+
+function f() {}
+// Call f with primitive this first, then as constructor
+f.call(1);
+new f();
+
+// Same as above in strict mode
+eval('"use strict"; function e() { print(typeof this); } e.call(1); new e();');
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8066220.js.EXPECTED	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,2 @@
+number
+object
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/JSONCompatibleTest.java	Wed Jul 05 20:37:09 2017 +0200
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.api.scripting;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import javax.script.ScriptEngine;
+import javax.script.ScriptException;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class JSONCompatibleTest {
+
+    /**
+     * Wrap a top-level array as a list.
+     */
+    @Test
+    public void testWrapArray() throws ScriptException {
+        final ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine();
+        final Object val = engine.eval("Java.asJSONCompatible([1, 2, 3])");
+        assertEquals(asList(val), Arrays.asList(1, 2, 3));
+    }
+
+    /**
+     * Wrap an embedded array as a list.
+     */
+    @Test
+    public void testWrapObjectWithArray() throws ScriptException {
+        final ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine();
+        final Object val = engine.eval("Java.asJSONCompatible({x: [1, 2, 3]})");
+        assertEquals(asList(asMap(val).get("x")), Arrays.asList(1, 2, 3));
+    }
+
+    /**
+     * Check it all works transitively several more levels down.
+     */
+    @Test
+    public void testDeepWrapping() throws ScriptException {
+        final ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine();
+        final Object val = engine.eval("Java.asJSONCompatible({x: [1, {y: [2, {z: [3]}]}, [4, 5]]})");
+        final Map<String, Object> root = asMap(val);
+        final List<Object> x = asList(root.get("x"));
+        assertEquals(x.get(0), 1);
+        final Map<String, Object> x1 = asMap(x.get(1));
+        final List<Object> y = asList(x1.get("y"));
+        assertEquals(y.get(0), 2);
+        final Map<String, Object> y1 = asMap(y.get(1));
+        assertEquals(asList(y1.get("z")), Arrays.asList(3));
+        assertEquals(asList(x.get(2)), Arrays.asList(4, 5));
+    }
+
+    /**
+     * Ensure that the old behaviour (every object is a Map) is unchanged.
+     */
+    @Test
+    public void testNonWrapping() throws ScriptException {
+        final ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine();
+        final Object val = engine.eval("({x: [1, {y: [2, {z: [3]}]}, [4, 5]]})");
+        final Map<String, Object> root = asMap(val);
+        final Map<String, Object> x = asMap(root.get("x"));
+        assertEquals(x.get("0"), 1);
+        final Map<String, Object> x1 = asMap(x.get("1"));
+        final Map<String, Object> y = asMap(x1.get("y"));
+        assertEquals(y.get("0"), 2);
+        final Map<String, Object> y1 = asMap(y.get("1"));
+        final Map<String, Object> z = asMap(y1.get("z"));
+        assertEquals(z.get("0"), 3);
+        final Map<String, Object> x2 = asMap(x.get("2"));
+        assertEquals(x2.get("0"), 4);
+        assertEquals(x2.get("1"), 5);
+    }
+
+    private static List<Object> asList(final Object obj) {
+        assertJSObject(obj);
+        Assert.assertTrue(obj instanceof List);
+        return (List)obj;
+    }
+
+    private static Map<String, Object> asMap(final Object obj) {
+        assertJSObject(obj);
+        Assert.assertTrue(obj instanceof Map);
+        return (Map)obj;
+    }
+
+    private static void assertJSObject(final Object obj) {
+        assertTrue(obj instanceof JSObject);
+    }
+}
--- a/nashorn/test/src/jdk/nashorn/api/scripting/test/ScopeTest.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/test/ScopeTest.java	Wed Jul 05 20:37:09 2017 +0200
@@ -31,10 +31,12 @@
 import javax.script.Bindings;
 import javax.script.ScriptContext;
 import javax.script.ScriptEngine;
+import javax.script.ScriptEngineFactory;
 import javax.script.ScriptEngineManager;
 import javax.script.ScriptException;
 import javax.script.SimpleBindings;
 import javax.script.SimpleScriptContext;
+import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
 import jdk.nashorn.api.scripting.ScriptObjectMirror;
 import jdk.nashorn.api.scripting.URLReader;
 import org.testng.Assert;
@@ -778,4 +780,44 @@
             throw new AssertionError("should have thrown NPE");
         } catch (NullPointerException npe5) {}
     }
+
+    public static class RecursiveEval {
+        private final ScriptEngineFactory factory = new NashornScriptEngineFactory();
+        private final ScriptEngine engine = factory.getScriptEngine();
+        private final Bindings engineBindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
+
+        public void program() throws ScriptException {
+            ScriptContext sc = new SimpleScriptContext();
+            Bindings global = new SimpleBindings();
+            sc.setBindings(global, ScriptContext.GLOBAL_SCOPE);
+            sc.setBindings(engineBindings, ScriptContext.ENGINE_SCOPE);
+            global.put("text", "programText");
+            String value = engine.eval("text", sc).toString();
+            Assert.assertEquals(value, "programText");
+            engine.put("program", this);
+            engine.eval("program.method()");
+            // eval again from here!
+            value = engine.eval("text", sc).toString();
+            Assert.assertEquals(value, "programText");
+        }
+
+        public void method() throws ScriptException {
+            // a context with a new global bindings, same engine bindings
+            final ScriptContext sc = new SimpleScriptContext();
+            final Bindings global = new SimpleBindings();
+            sc.setBindings(global, ScriptContext.GLOBAL_SCOPE);
+            sc.setBindings(engineBindings, ScriptContext.ENGINE_SCOPE);
+            global.put("text", "methodText");
+            String value = engine.eval("text", sc).toString();
+            Assert.assertEquals(value, "methodText");
+        }
+    }
+
+    // @bug 8081609: engine.eval call from a java method which
+    // was called from a previous engine.eval results in wrong
+    // ScriptContext being used.
+    @Test
+    public void recursiveEvalCallScriptContextTest() throws ScriptException {
+        new RecursiveEval().program();
+    }
 }
--- a/nashorn/test/src/jdk/nashorn/internal/test/framework/TestFinder.java	Thu Jun 04 18:50:30 2015 -0700
+++ b/nashorn/test/src/jdk/nashorn/internal/test/framework/TestFinder.java	Wed Jul 05 20:37:09 2017 +0200
@@ -225,7 +225,7 @@
         boolean explicitOptimistic = false;
 
         String allContent = new String(Files.readAllBytes(testFile));
-        Iterator<String> scanner = ScriptingFunctions.tokenizeCommandLine(allContent).iterator();
+        Iterator<String> scanner = ScriptingFunctions.tokenizeString(allContent).iterator();
         while (scanner.hasNext()) {
             // TODO: Scan for /ref=file qualifiers, etc, to determine run
             // behavior