Merge jdk9-b68
authorduke
Wed, 05 Jul 2017 20:37:12 +0200
changeset 31008 5b500c93ce48
parent 31007 b2ea0d3316ef (diff)
parent 30851 1c0a1cee6054 (current diff)
child 31009 965bd3a5e571
child 31010 e534b1345860
child 31013 03705c62af66
child 31017 fd247ac3803f
child 31052 4c45af8f8225
child 31056 07cd15548b1b
child 31057 babdeee3c007
child 31088 a1fc22937bd1
child 31089 cd89935b86f3
child 31092 385ce1a46f76
child 31093 52472f1b56e4
child 31103 46eaed57b8c8
child 31104 79a0696bbd7c
child 31108 6f2e0bf866bc
child 31109 a542f8dcbbf8
child 31112 07c4c0354289
child 31113 646511cb5873
child 31308 97ab382f3311
child 33927 567b299aa689
child 33958 8d838be4f4ec
child 33985 6a01dc9458f7
child 34021 8ef2b9585f25
child 34044 4c5494af1359
child 34071 654e1a23e215
Merge
--- a/.hgtags-top-repo	Wed Jul 05 20:36:16 2017 +0200
+++ b/.hgtags-top-repo	Wed Jul 05 20:37:12 2017 +0200
@@ -309,3 +309,4 @@
 82cf9aab9a83e41c8194ba01af9666afdb856cbe jdk9-b64
 7c31f9d7b932f7924f1258d52885b1c7c3e078c2 jdk9-b65
 dc6e8336f51bb6b67b7245766179eab5ca7720b4 jdk9-b66
+f546760134eb861fcfecd4ce611b0040b0d25a6a jdk9-b67
--- a/common/autoconf/flags.m4	Wed Jul 05 20:36:16 2017 +0200
+++ b/common/autoconf/flags.m4	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/common/autoconf/generated-configure.sh	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/corba/.hgtags	Wed Jul 05 20:37:12 2017 +0200
@@ -309,3 +309,4 @@
 0a5e5a7c3539e8bde73d9fe55750e49a49cb8dac jdk9-b64
 afc1e295c4bf83f9a5dd539c29914edd4a754a3f jdk9-b65
 44ee68f7dbacab24a45115fd6a8ccdc7eb6e8f0b jdk9-b66
+4418697e56f1f43597f55c7cb6573549c6117868 jdk9-b67
--- a/hotspot/.hgtags	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/.hgtags	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/cpu/aarch64/vm/aarch64.ad	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/cpu/aarch64/vm/assembler_aarch64.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/cpu/aarch64/vm/globals_aarch64.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/cpu/aarch64/vm/macroAssembler_aarch64.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/cpu/aarch64/vm/register_aarch64.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/cpu/aarch64/vm/templateTable_aarch64.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/os/windows/vm/os_windows.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/cms/cmsOopClosures.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/cms/compactibleFreeListSpace.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/cms/parCardTableModRefBS.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/cms/parOopClosures.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/cms/yieldingWorkgroup.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/collectionSetChooser.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/collectionSetChooser.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/concurrentG1Refine.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/concurrentMark.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1MarkSweep.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1RootProcessor.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1RootProcessor.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1StringDedup.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1StringDedupQueue.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/g1/g1StringDedupTable.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/parallel/psScavenge.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/serial/defNewGeneration.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/adaptiveSizePolicy.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/cardGeneration.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/cardGeneration.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/cardTableModRefBS.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/cardTableModRefBS.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/cardTableRS.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/cardTableRS.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/collectedHeap.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/collectedHeap.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/genCollectedHeap.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/genOopClosures.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/genRemSet.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/generation.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/generation.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/space.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/space.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/strongRootsScope.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/strongRootsScope.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/taskqueue.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/workgroup.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/gc/shared/workgroup.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/memory/iterator.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/oops/arrayKlass.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/oops/instanceClassLoaderKlass.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/oops/instanceClassLoaderKlass.inline.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/oops/instanceKlass.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/oops/instanceKlass.inline.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/oops/instanceMirrorKlass.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/oops/instanceMirrorKlass.inline.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/oops/instanceRefKlass.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/oops/instanceRefKlass.inline.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/oops/klass.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/oops/objArrayKlass.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/oops/objArrayKlass.inline.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/oops/oop.inline.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/oops/typeArrayKlass.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/oops/typeArrayKlass.inline.hpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/runtime/arguments.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/src/share/vm/utilities/elfFile.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/hotspot/test/compiler/stable/StableConfiguration.java	Wed Jul 05 20:37:12 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:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jaxp/.hgtags	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/dtm/ref/DTMNodeProxy.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jaxp/src/java.xml/share/classes/com/sun/org/apache/xml/internal/dtm/ref/sax2dtm/SAX2DTM2.java	Wed Jul 05 20:37:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jaxp/test/TEST.ROOT	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jaxp/test/TEST.groups	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jaxp/test/javax/xml/jaxp/unittest/javax/xml/transform/DocumentExtFunc.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jaxws/.hgtags	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/assembler/MetroConfigLoader.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/jxc/ConfigReader.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/SchemaCache.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/reader/dtd/bindinfo/BindInfo.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jaxws/src/jdk.xml.bind/share/classes/com/sun/tools/internal/xjc/reader/xmlschema/bindinfo/BindInfo.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jaxws/src/jdk.xml.bind/share/classes/com/sun/xml/internal/xsom/impl/parser/ParserContext.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/.hgtags	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/make/mapfiles/libjava/mapfile-vers	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/make/mapfiles/libnet/mapfile-vers	Wed Jul 05 20:37:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/io/InputStream.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/io/ObjectStreamClass.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/lang/Character.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/lang/Process.java	Wed Jul 05 20:37:12 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:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/lang/RuntimePermission.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/lang/String.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/net/AbstractPlainSocketImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/net/DatagramSocket.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/net/Socket.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/time/zone/ZoneOffsetTransition.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/time/zone/ZoneOffsetTransitionRule.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/Enumeration.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/java/util/Iterator.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/ExtendedSSLSession.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SNIServerName.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLContext.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLContextSpi.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLEngine.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLEngineResult.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLParameters.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLSession.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/X509ExtendedTrustManager.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/invoke/anon/ConstantPoolPatch.java	Wed Jul 05 20:37:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ /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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/misc/SharedSecrets.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ /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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/AppInputStream.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/AppOutputStream.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/Authenticator.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/CipherBox.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/CipherSuite.java	Wed Jul 05 20:37:12 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:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java	Wed Jul 05 20:37:12 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:12 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:12 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:12 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:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/Debug.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ /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	Wed Jul 05 20:36:16 2017 +0200
+++ /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	Wed Jul 05 20:36:16 2017 +0200
+++ /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	Wed Jul 05 20:36:16 2017 +0200
+++ /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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ExtensionType.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeHash.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeInStream.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeMessage.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeOutStream.java	Wed Jul 05 20:37:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/Handshaker.java	Wed Jul 05 20:37:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/HelloExtensions.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/InputRecord.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/JsseJce.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ /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	Wed Jul 05 20:36:16 2017 +0200
+++ /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	Wed Jul 05 20:36:16 2017 +0200
+++ /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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/MAC.java	Wed Jul 05 20:37:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/OutputRecord.java	Wed Jul 05 20:37:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ProtocolList.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ProtocolVersion.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/RSAClientKeyExchange.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/RandomCookie.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/Record.java	Wed Jul 05 20:37:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLAlgorithmConstraints.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java	Wed Jul 05 20:37:12 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:12 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:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLServerSocketImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java	Wed Jul 05 20:37:12 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:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SunJSSE.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/X509KeyManagerImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/classes/sun/security/util/HostnameChecker.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/share/conf/security/java.security	Wed Jul 05 20:37:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/unix/classes/java/net/PlainSocketImpl.java	Wed Jul 05 20:37:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/unix/native/libjava/ProcessImpl_md.c	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/unix/native/libnet/PlainSocketImpl.c	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/unix/native/libnet/net_util_md.c	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/windows/classes/java/lang/ProcessImpl.java	Wed Jul 05 20:37:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.base/windows/native/libjli/java_md.c	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaComboBoxPopup.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaSpinnerUI.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWMouseInfoPeer.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWTextAreaPeer.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWToolkit.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/PlatformWindow.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformEmbeddedFrame.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformLWWindow.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPlatformWindow.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CRobot.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CViewPlatformEmbeddedFrame.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/macosx/native/include/jawt_md.h	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.h	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/AWTWindow.m	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CCursorManager.m	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobot.m	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/beans/decoder/ArrayElementHandler.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKEngine.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_de.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_es.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_fr.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_it.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_ja.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_ko.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_pt_BR.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_sv.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_zh_CN.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources/gtk_zh_TW.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_de.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_es.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_fr.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_it.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_pt_BR.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/basic/resources/basic_sv.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_de.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_es.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_fr.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_it.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_ja.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_ko.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_pt_BR.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_sv.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_zh_CN.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/com/sun/swing/internal/plaf/metal/resources/metal_zh_TW.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/java/awt/Component.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/java/awt/Container.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/java/awt/Menu.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/java/awt/MenuBar.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/java/awt/MenuComponent.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/java/awt/WaitDispatchSupport.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/java/awt/font/OpenType.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/java/beans/Introspector.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/javax/sound/sampled/spi/AudioFileWriter.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/javax/swing/GroupLayout.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/javax/swing/JApplet.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/javax/swing/JDialog.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/javax/swing/JFrame.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/javax/swing/JSpinner.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/javax/swing/RepaintManager.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicComboBoxUI.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicComboPopup.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLabelUI.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicRadioButtonUI.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSpinnerUI.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTextUI.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/metal/MetalRootPaneUI.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthSplitPaneUI.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletClassLoader.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/applet/AppletSecurity.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/awt/AppContext.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/awt/DefaultMouseInfoPeer.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/awt/EmbeddedFrame.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/awt/HToolkit.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/awt/SunToolkit.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/awt/datatransfer/SunClipboard.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/awt/geom/PathConsumer2D.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/awt/im/ExecutableInputMethodManager.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ByteBandedRaster.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ByteComponentRaster.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ByteInterleavedRaster.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/awt/image/BytePackedRaster.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ImageFetchable.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/awt/image/IntegerComponentRaster.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/awt/image/IntegerInterleavedRaster.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ShortBandedRaster.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ShortComponentRaster.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/awt/image/ShortInterleavedRaster.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/awt/shell/ShellFolderColumnInfo.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/awt/util/IdentityArrayList.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/awt/util/IdentityLinkedList.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/font/ScriptRun.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/font/StandardTextSource.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/font/TextLabelFactory.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/NullSurfaceData.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/SunCompositeContext.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/SunGraphics2D.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/SurfaceData.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/pipe/PixelToParallelogramConverter.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/pipe/RenderingEngine.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/pipe/hw/AccelDeviceEventNotifier.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/pipe/hw/AccelGraphicsConfig.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/pipe/hw/ContextCapabilities.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/pisces/PiscesCache.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/print/DialogOwner.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/print/OpenBook.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/print/PSPathGraphics.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/print/PeekGraphics.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/print/PrintJob2D.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/print/ProxyGraphics2D.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/print/ProxyPrintGraphics.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/swing/CachedPainter.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/swing/UIAction.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/swing/plaf/synth/DefaultSynthStyle.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/swing/plaf/synth/Paint9Painter.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/share/classes/sun/swing/text/TextComponentPrintable.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/FcFontManager.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XAtom.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XComponentPeer.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XListPeer.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMenuBarPeer.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMenuItemPeer.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XMenuWindow.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XScrollbar.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11FontManager.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsConfig.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsEnvironment.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11InputMethod.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/unix/classes/sun/font/FontConfigManager.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/unix/native/common/awt/utility/rect.h	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_InputMethod.c	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.c	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/gtk2_interface.h	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/windows/classes/sun/awt/Win32FontManager.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/windows/classes/sun/awt/Win32GraphicsDevice.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/windows/classes/sun/awt/Win32GraphicsEnvironment.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolder2.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WComponentPeer.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WObjectPeer.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPathGraphics.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DScreenUpdateManager.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DSurfaceData.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/windows/classes/sun/java2d/opengl/WGLSurfaceData.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/ShellFolder2.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_Menu.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_MenuBar.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_MenuItem.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_new.cpp	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.management/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.management/share/classes/com/sun/jmx/mbeanserver/Introspector.java	Wed Jul 05 20:37:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.naming/share/classes/com/sun/jndi/ldap/Connection.java	Wed Jul 05 20:37:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/Config.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/KrbCred.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/java.security.jgss/share/classes/sun/security/krb5/internal/HostAddresses.java	Wed Jul 05 20:37:12 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:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ /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	Wed Jul 05 20:36:16 2017 +0200
+++ /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	Wed Jul 05 20:36:16 2017 +0200
+++ /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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/jdk.charsets/share/classes/sun/nio/cs/ext/ExtendedCharsets.java.template	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeGCMCipher.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/ProblemList.txt	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/TEST.ROOT	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/com/sun/jdi/AllLineLocations.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/com/sun/jdi/ClassesByName.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/com/sun/jdi/ExceptionEvents.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/com/sun/jdi/FilterMatch.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/com/sun/jdi/FilterNoMatch.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/com/sun/jdi/LaunchCommandLine.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/com/sun/jdi/ModificationWatchpoints.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/com/sun/jdi/NativeInstanceFilter.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/com/sun/jdi/UnpreparedByName.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/com/sun/jdi/UnpreparedClasses.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/com/sun/jdi/Vars.java	Wed Jul 05 20:37:12 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:12 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:12 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:12 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:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/java/awt/Frame/SetMaximizedBounds/SetMaximizedBounds.java	Wed Jul 05 20:37:12 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:12 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:12 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:12 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:12 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:12 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:12 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:12 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:12 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:12 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:12 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:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ /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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/java/lang/ProcessBuilder/Basic.java	Wed Jul 05 20:37:12 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:12 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:12 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:12 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:12 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:12 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:12 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:12 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:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/java/net/SocketOption/OptionsTest.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/java/rmi/activation/rmidViaInheritedChannel/RmidViaInheritedChannel.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/java/time/tck/java/time/zone/TCKZoneOffsetTransitionRule.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/java/util/Arrays/ParallelPrefix.java	Wed Jul 05 20:37:12 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:12 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:12 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:12 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:12 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:12 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:12 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:12 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:12 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:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/javax/net/ssl/SSLEngine/CheckStatus.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/javax/net/ssl/SSLEngine/LargeBufs.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/javax/net/ssl/TLS/CipherTestUtils.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/javax/net/ssl/TLSv11/ExportableBlockCipher.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/javax/net/ssl/TLSv11/ExportableStreamCipher.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/javax/net/ssl/templates/SSLSocketSSLEngineTemplate.java	Wed Jul 05 20:37:12 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:12 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:12 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:12 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:12 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:12 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:12 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:12 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:12 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:12 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:12 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:12 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:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/javax/xml/jaxp/common/8032908/TestFunc.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/javax/xml/jaxp/common/8032908/XSLT.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/lib/security/CheckBlacklistedCerts.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/lib/testlibrary/AssertsTest.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/lib/testlibrary/OutputAnalyzerReportingTest.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/lib/testlibrary/OutputAnalyzerTest.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/JarUtils.java	Wed Jul 05 20:37:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/OutputBuffer.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/ParentLastURLClassLoader.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/ProcessTools.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/lib/testlibrary/jdk/testlibrary/StreamPumper.java	Wed Jul 05 20:37:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/sun/net/www/protocol/https/ChunkedOutputStream.java	Wed Jul 05 20:37:12 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:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/sun/security/krb5/auto/KDC.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/sun/security/krb5/auto/MSOID2.java	Wed Jul 05 20:37:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/sun/security/ssl/AppInputStream/ReadHandshake.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/jdk/test/sun/security/ssl/ClientHandshaker/LengthCheckTest.java	Wed Jul 05 20:37:12 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:12 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/langtools/.hgtags	Wed Jul 05 20:36:16 2017 +0200
+++ b/langtools/.hgtags	Wed Jul 05 20:37:12 2017 +0200
@@ -309,3 +309,4 @@
 809d66512998789b620d08c335d7c31211a0cf29 jdk9-b64
 4fcf722b811406a7db8f206d88446c82cda1b5f4 jdk9-b65
 fd6bda430d96fc5ab421161de016412f2ddd9082 jdk9-b66
+fd782cd69b0497299269952d30a6b88cad960fcf jdk9-b67
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Scope.java	Wed Jul 05 20:36:16 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Scope.java	Wed Jul 05 20:37:12 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2014, 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
@@ -407,12 +407,11 @@
             }
         }
 
-        /** Remove symbol from this scope.  Used when an inner class
-         *  attribute tells us that the class isn't a package member.
+        /** Remove symbol from this scope.
          */
         public void remove(Symbol sym) {
             Assert.check(shared == 0);
-            Entry e = lookup(sym.name);
+            Entry e = lookup(sym.name, candidate -> candidate == sym);
             if (e.scope == null) return;
 
             // remove e from table and shadowed list;
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Wed Jul 05 20:36:16 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Wed Jul 05 20:37:12 2017 +0200
@@ -2659,73 +2659,92 @@
     // </editor-fold>
 
     // <editor-fold defaultstate="collapsed" desc="compute transitive closure of all members in given site">
-    class MembersClosureCache extends SimpleVisitor<CompoundScope, Boolean> {
-
-        private WeakHashMap<TypeSymbol, Entry> _map = new WeakHashMap<>();
-
-        class Entry {
-            final boolean skipInterfaces;
-            final CompoundScope compoundScope;
-
-            public Entry(boolean skipInterfaces, CompoundScope compoundScope) {
-                this.skipInterfaces = skipInterfaces;
-                this.compoundScope = compoundScope;
+    class MembersClosureCache extends SimpleVisitor<Scope.CompoundScope, Void> {
+
+        private Map<TypeSymbol, CompoundScope> _map = new HashMap<>();
+
+        Set<TypeSymbol> seenTypes = new HashSet<>();
+
+        class MembersScope extends CompoundScope {
+
+            CompoundScope scope;
+
+            public MembersScope(CompoundScope scope) {
+                super(scope.owner);
+                this.scope = scope;
             }
 
-            boolean matches(boolean skipInterfaces) {
-                return this.skipInterfaces == skipInterfaces;
+            Filter<Symbol> combine(Filter<Symbol> sf) {
+                return s -> !s.owner.isInterface() && (sf == null || sf.accepts(s));
+            }
+
+            @Override
+            public Iterable<Symbol> getSymbols(Filter<Symbol> sf, LookupKind lookupKind) {
+                return scope.getSymbols(combine(sf), lookupKind);
+            }
+
+            @Override
+            public Iterable<Symbol> getSymbolsByName(Name name, Filter<Symbol> sf, LookupKind lookupKind) {
+                return scope.getSymbolsByName(name, combine(sf), lookupKind);
+            }
+
+            @Override
+            public int getMark() {
+                return scope.getMark();
             }
         }
 
-        List<TypeSymbol> seenTypes = List.nil();
+        CompoundScope nilScope;
 
         /** members closure visitor methods **/
 
-        public CompoundScope visitType(Type t, Boolean skipInterface) {
-            return null;
+        public CompoundScope visitType(Type t, Void _unused) {
+            if (nilScope == null) {
+                nilScope = new CompoundScope(syms.noSymbol);
+            }
+            return nilScope;
         }
 
         @Override
-        public CompoundScope visitClassType(ClassType t, Boolean skipInterface) {
-            if (seenTypes.contains(t.tsym)) {
+        public CompoundScope visitClassType(ClassType t, Void _unused) {
+            if (!seenTypes.add(t.tsym)) {
                 //this is possible when an interface is implemented in multiple
-                //superclasses, or when a classs hierarchy is circular - in such
+                //superclasses, or when a class hierarchy is circular - in such
                 //cases we don't need to recurse (empty scope is returned)
                 return new CompoundScope(t.tsym);
             }
             try {
-                seenTypes = seenTypes.prepend(t.tsym);
+                seenTypes.add(t.tsym);
                 ClassSymbol csym = (ClassSymbol)t.tsym;
-                Entry e = _map.get(csym);
-                if (e == null || !e.matches(skipInterface)) {
-                    CompoundScope membersClosure = new CompoundScope(csym);
-                    if (!skipInterface) {
-                        for (Type i : interfaces(t)) {
-                            membersClosure.prependSubScope(visit(i, skipInterface));
-                        }
+                CompoundScope membersClosure = _map.get(csym);
+                if (membersClosure == null) {
+                    membersClosure = new CompoundScope(csym);
+                    for (Type i : interfaces(t)) {
+                        membersClosure.prependSubScope(visit(i, null));
                     }
-                    membersClosure.prependSubScope(visit(supertype(t), skipInterface));
+                    membersClosure.prependSubScope(visit(supertype(t), null));
                     membersClosure.prependSubScope(csym.members());
-                    e = new Entry(skipInterface, membersClosure);
-                    _map.put(csym, e);
+                    _map.put(csym, membersClosure);
                 }
-                return e.compoundScope;
+                return membersClosure;
             }
             finally {
-                seenTypes = seenTypes.tail;
+                seenTypes.remove(t.tsym);
             }
         }
 
         @Override
-        public CompoundScope visitTypeVar(TypeVar t, Boolean skipInterface) {
-            return visit(t.getUpperBound(), skipInterface);
+        public CompoundScope visitTypeVar(TypeVar t, Void _unused) {
+            return visit(t.getUpperBound(), null);
         }
     }
 
     private MembersClosureCache membersCache = new MembersClosureCache();
 
     public CompoundScope membersClosure(Type site, boolean skipInterface) {
-        return membersCache.visit(site, skipInterface);
+        CompoundScope cs = membersCache.visit(site, null);
+        Assert.checkNonNull(cs, () -> "type " + site);
+        return skipInterface ? membersCache.new MembersScope(cs) : cs;
     }
     // </editor-fold>
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Wed Jul 05 20:36:16 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Wed Jul 05 20:37:12 2017 +0200
@@ -2270,6 +2270,7 @@
             final Bits prevUninits = new Bits(uninits);
             final Bits prevInits = new Bits(inits);
             int returnadrPrev = returnadr;
+            int nextadrPrev = nextadr;
             ListBuffer<AssignPendingExit> prevPending = pendingExits;
             try {
                 returnadr = nextadr;
@@ -2291,6 +2292,7 @@
                 uninits.assign(prevUninits);
                 inits.assign(prevInits);
                 pendingExits = prevPending;
+                nextadr = nextadrPrev;
             }
         }
 
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Wed Jul 05 20:36:16 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Wed Jul 05 20:37:12 2017 +0200
@@ -3185,10 +3185,8 @@
                 findDiamond(env, site, argtypes, typeargtypes, phase.isBoxingRequired(), phase.isVarargsRequired()) :
                 findMethod(env, site, name, argtypes, typeargtypes,
                         phase.isBoxingRequired(), phase.isVarargsRequired());
-            return (sym.kind != MTH ||
-                    site.getEnclosingType().hasTag(NONE) ||
-                    hasEnclosingInstance(env, site)) ?
-                    sym : new BadConstructorReferenceError(sym);
+            return site.getEnclosingType().hasTag(CLASS) && !hasEnclosingInstance(env, site) ?
+                        new BadConstructorReferenceError(sym) : sym;
         }
 
         @Override
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Wed Jul 05 20:36:16 2017 +0200
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Wed Jul 05 20:37:12 2017 +0200
@@ -470,6 +470,10 @@
                         clinitTAs.addAll(getAndRemoveNonFieldTAs(sym));
                     } else {
                         checkStringConstant(vdef.init.pos(), sym.getConstValue());
+                        /* if the init contains a reference to an external class, add it to the
+                         * constant's pool
+                         */
+                        vdef.init.accept(classReferenceVisitor);
                     }
                 }
                 break;
@@ -2337,9 +2341,11 @@
             ClassSymbol c = cdef.sym;
             this.toplevel = env.toplevel;
             this.endPosTable = toplevel.endPositions;
-            cdef.defs = normalizeDefs(cdef.defs, c);
             c.pool = pool;
             pool.reset();
+            /* method normalizeDefs() can add references to external classes into the constant pool
+             */
+            cdef.defs = normalizeDefs(cdef.defs, c);
             generateReferencesToPrunedTree(c, pool);
             Env<GenContext> localEnv = new Env<>(cdef, new GenContext());
             localEnv.toplevel = env.toplevel;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/ProblemList.txt	Wed Jul 05 20:37:12 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 langtools tests are on the problem list.
--- a/langtools/test/TEST.ROOT	Wed Jul 05 20:36:16 2017 +0200
+++ b/langtools/test/TEST.ROOT	Wed Jul 05 20:37:12 2017 +0200
@@ -1,6 +1,18 @@
 # 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
+# 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
+
+# Group definitions
+groups=TEST.groups
+
+# Tests using jtreg 4.1 b11 features
+requiredVersion=4.1 b11
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/TEST.groups	Wed Jul 05 20:37:12 2017 +0200
@@ -0,0 +1,32 @@
+#  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
+
+# All langtools tests are tier 1
+tier1 = \
+    tools \
+    com \
+    lib
+
+# No langtools tests are tier 2
+tier2 = 
--- a/langtools/test/tools/javac/4846262/CheckEBCDICLocaleTest.java	Wed Jul 05 20:36:16 2017 +0200
+++ b/langtools/test/tools/javac/4846262/CheckEBCDICLocaleTest.java	Wed Jul 05 20:37:12 2017 +0200
@@ -34,9 +34,12 @@
  */
 
 import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.io.PrintWriter;
 import java.nio.charset.Charset;
 import java.nio.file.Files;
-import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Arrays;
 import java.util.List;
@@ -68,16 +71,19 @@
         tb.writeFile("Test.java", TestSrc);
         tb.createDirectories("output");
 
-        Native2Ascii n2a = new Native2Ascii(Charset.forName("IBM1047"));
+        Charset ebcdic = Charset.forName("IBM1047");
+        Native2Ascii n2a = new Native2Ascii(ebcdic);
         n2a.asciiToNative(Paths.get("Test.java"), Paths.get("output", "Test.java"));
 
-        tb.new JavacTask(ToolBox.Mode.EXEC)
-                .redirect(ToolBox.OutputKind.STDERR, "Test.tmp")
-                .options("-J-Duser.language=en",
-                        "-J-Duser.region=US",
-                        "-J-Dfile.encoding=IBM1047")
-                .files("output/Test.java")
-                .run(ToolBox.Expect.FAIL);
+        // Use -encoding to specify the encoding with which to read source files
+        // Use a suitable configured output stream for javac diagnostics
+        int rc;
+        try (PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream("Test.tmp"), ebcdic))) {
+            String[] args = { "-encoding", ebcdic.name(), "output/Test.java" };
+            rc = com.sun.tools.javac.Main.compile(args, out);
+            if (rc != 1)
+                throw new Exception("unexpected exit from javac: " + rc);
+        }
 
         n2a.nativeToAscii(Paths.get("Test.tmp"), Paths.get("Test.out"));
 
@@ -87,16 +93,21 @@
         try {
             tb.checkEqual(expectLines, actualLines);
         } catch (Throwable tt) {
-            System.err.println("current ouput don't have the expected number of lines. See output below");
+            PrintStream out = tb.out;
+            out.println("Output mismatch:");
 
-            System.err.println("Expected output:");
-            System.err.println(TestOutTemplate);
-            System.err.println();
-            System.err.println("Actual output:");
+            out.println("Expected output:");
+            for (String s: expectLines) {
+                out.println(s);
+            }
+            out.println();
+
+            out.println("Actual output:");
             for (String s : actualLines) {
-                System.err.println(s);
+                out.println(s);
             }
-            System.err.println();
+            out.println();
+
             throw tt;
         }
     }
--- a/langtools/test/tools/javac/7153958/CPoolRefClassContainingInlinedCts.java	Wed Jul 05 20:36:16 2017 +0200
+++ b/langtools/test/tools/javac/7153958/CPoolRefClassContainingInlinedCts.java	Wed Jul 05 20:37:12 2017 +0200
@@ -25,10 +25,10 @@
 
 /*
  * @test
- * @bug 7153958
+ * @bug 7153958 8073372
  * @summary add constant pool reference to class containing inlined constants
  * @modules jdk.jdeps/com.sun.tools.classfile
- * @compile pkg/ClassToBeStaticallyImported.java CPoolRefClassContainingInlinedCts.java
+ * @compile pkg/ClassToBeStaticallyImportedA.java pkg/ClassToBeStaticallyImportedB.java CPoolRefClassContainingInlinedCts.java
  * @run main CPoolRefClassContainingInlinedCts
  */
 
@@ -39,7 +39,8 @@
 import java.io.File;
 import java.io.IOException;
 
-import static pkg.ClassToBeStaticallyImported.staticField;
+import static pkg.ClassToBeStaticallyImportedA.staticFieldA;
+import static pkg.ClassToBeStaticallyImportedB.staticFieldB;
 
 public class CPoolRefClassContainingInlinedCts {
 
@@ -55,10 +56,14 @@
 
     void checkClassName(String className) {
         switch (className) {
-            case "SimpleAssignClass" : case "BinaryExpClass":
-            case "UnaryExpClass" : case "CastClass":
-            case "ParensClass" : case "CondClass":
-            case "IfClass" : case "pkg/ClassToBeStaticallyImported":
+            case "SimpleAssignClassA" : case "BinaryExpClassA":
+            case "UnaryExpClassA" : case "CastClassA":
+            case "ParensClassA" : case "CondClassA":
+            case "IfClassA" : case "pkg/ClassToBeStaticallyImportedA":
+            case "SimpleAssignClassB" : case "BinaryExpClassB":
+            case "UnaryExpClassB" : case "CastClassB":
+            case "ParensClassB" : case "CondClassB":
+            case "IfClassB" : case "pkg/ClassToBeStaticallyImportedB":
                 numberOfReferencedClassesToBeChecked++;
         }
     }
@@ -77,59 +82,111 @@
             }
             i += cpInfo.size();
         }
-        if (numberOfReferencedClassesToBeChecked != 8) {
+        if (numberOfReferencedClassesToBeChecked != 16) {
             throw new AssertionError("Class reference missing in the constant pool");
         }
     }
 
-    private int assign = SimpleAssignClass.x;
-    private int binary = BinaryExpClass.x + 1;
-    private int unary = -UnaryExpClass.x;
-    private int cast = (int)CastClass.x;
-    private int parens = (ParensClass.x);
-    private int cond = (CondClass.x == 1) ? 1 : 2;
-    private static int ifConstant;
-    private static int importStatic;
+    private int assignA = SimpleAssignClassA.x;
+    private int binaryA = BinaryExpClassA.x + 1;
+    private int unaryA = -UnaryExpClassA.x;
+    private int castA = (int)CastClassA.x;
+    private int parensA = (ParensClassA.x);
+    private int condA = (CondClassA.x == 1) ? 1 : 2;
+    private static int ifConstantA;
+    private static int importStaticA;
     static {
-        if (IfClass.x == 1) {
-            ifConstant = 1;
+        if (IfClassA.x == 1) {
+            ifConstantA = 1;
         } else {
-            ifConstant = 2;
+            ifConstantA = 2;
         }
     }
     static {
-        if (staticField == 1) {
-            importStatic = 1;
+        if (staticFieldA == 1) {
+            importStaticA = 1;
         } else {
-            importStatic = 2;
+            importStaticA = 2;
+        }
+    }
+
+    // now as final constants
+    private static final int assignB = SimpleAssignClassB.x;
+    private static final int binaryB = BinaryExpClassB.x + 1;
+    private static final int unaryB = -UnaryExpClassB.x;
+    private static final int castB = (int)CastClassB.x;
+    private static final int parensB = (ParensClassB.x);
+    private static final int condB = (CondClassB.x == 1) ? 1 : 2;
+    private static final int ifConstantB;
+    private static final int importStaticB;
+    static {
+        if (IfClassB.x == 1) {
+            ifConstantB = 1;
+        } else {
+            ifConstantB = 2;
+        }
+    }
+    static {
+        if (staticFieldB == 1) {
+            importStaticB = 1;
+        } else {
+            importStaticB = 2;
         }
     }
 }
 
-class SimpleAssignClass {
+class SimpleAssignClassA {
+    public static final int x = 1;
+}
+
+class SimpleAssignClassB {
+    public static final int x = 1;
+}
+
+class BinaryExpClassA {
     public static final int x = 1;
 }
 
-class BinaryExpClass {
+class BinaryExpClassB {
     public static final int x = 1;
 }
 
-class UnaryExpClass {
+class UnaryExpClassA {
+    public static final int x = 1;
+}
+
+class UnaryExpClassB {
+    public static final int x = 1;
+}
+
+class CastClassA {
     public static final int x = 1;
 }
 
-class CastClass {
+class CastClassB {
     public static final int x = 1;
 }
 
-class ParensClass {
+class ParensClassA {
+    public static final int x = 1;
+}
+
+class ParensClassB {
     public static final int x = 1;
 }
 
-class CondClass {
+class CondClassA {
+    public static final int x = 1;
+}
+
+class CondClassB {
     public static final int x = 1;
 }
 
-class IfClass {
+class IfClassA {
     public static final int x = 1;
 }
+
+class IfClassB {
+    public static final int x = 1;
+}
--- a/langtools/test/tools/javac/7153958/pkg/ClassToBeStaticallyImported.java	Wed Jul 05 20:36:16 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  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 pkg;
-
-public class ClassToBeStaticallyImported {
-    public static final int staticField = 1;
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/7153958/pkg/ClassToBeStaticallyImportedA.java	Wed Jul 05 20:37:12 2017 +0200
@@ -0,0 +1,29 @@
+/*
+ * 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
+ * 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 pkg;
+
+public class ClassToBeStaticallyImportedA {
+    public static final int staticFieldA = 1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/7153958/pkg/ClassToBeStaticallyImportedB.java	Wed Jul 05 20:37:12 2017 +0200
@@ -0,0 +1,29 @@
+/*
+ * 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
+ * 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 pkg;
+
+public class ClassToBeStaticallyImportedB {
+    public static final int staticFieldB = 1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/LambdaParameterNeedsNoInitTest.java	Wed Jul 05 20:37:12 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.
+ */
+
+/*
+ * @test
+ * @bug 8077667
+ * @summary Eliminate bogus error about lambda parameter not being initialized.
+ * @compile LambdaParameterNeedsNoInitTest.java
+ */
+import java.util.function.Predicate;
+
+public class LambdaParameterNeedsNoInitTest {
+
+    public static void main(String[] args) {
+        new Inner();
+    }
+
+    private static class Inner {
+        Predicate<String> synonymComparator = a -> a.isEmpty();
+        Inner() {
+            if (true) {
+                return;
+            }
+            synonymComparator.test("");
+        }
+    }
+}
--- a/langtools/test/tools/javac/lambda/MethodReference23.java	Wed Jul 05 20:36:16 2017 +0200
+++ b/langtools/test/tools/javac/lambda/MethodReference23.java	Wed Jul 05 20:37:12 2017 +0200
@@ -1,6 +1,6 @@
 /*
  * @test /nodynamiccopyright/
- * @bug 8003280 8075184
+ * @bug 8003280 8075184 8081271
  * @summary Add lambda tests
  *  check that pair of bound/non-bound constructor references is flagged as ambiguous
  * @author  Maurizio Cimadamore
@@ -49,8 +49,8 @@
     static void call3(SAM22 s) {   }
 
     static void test11() {
-        SAM11 s = MethodReference23.Inner1::new; //ok
-        call11(MethodReference23.Inner1::new); //ok
+        SAM11 s = MethodReference23.Inner1::new; // fail.
+        call11(MethodReference23.Inner1::new); // fail.
     }
 
     static void test12() {
--- a/langtools/test/tools/javac/lambda/MethodReference23.out	Wed Jul 05 20:36:16 2017 +0200
+++ b/langtools/test/tools/javac/lambda/MethodReference23.out	Wed Jul 05 20:37:12 2017 +0200
@@ -1,5 +1,5 @@
 MethodReference23.java:52:19: compiler.err.invalid.mref: kindname.constructor, (compiler.misc.cant.access.inner.cls.constr: Inner1, MethodReference23, MethodReference23)
-MethodReference23.java:53:16: compiler.err.invalid.mref: kindname.constructor, (compiler.misc.cant.access.inner.cls.constr: Inner1, MethodReference23, MethodReference23)
+MethodReference23.java:53:16: compiler.err.invalid.mref: kindname.constructor, (compiler.misc.cant.access.inner.cls.constr: Inner1, , MethodReference23)
 MethodReference23.java:57:19: compiler.err.invalid.mref: kindname.constructor, (compiler.misc.cant.access.inner.cls.constr: Inner1, , MethodReference23)
 MethodReference23.java:58:16: compiler.err.invalid.mref: kindname.constructor, (compiler.misc.cant.access.inner.cls.constr: Inner1, , MethodReference23)
 MethodReference23.java:72:9: compiler.err.ref.ambiguous: call3, kindname.method, call3(MethodReference23.SAM21), MethodReference23, kindname.method, call3(MethodReference23.SAM22), MethodReference23
--- a/langtools/test/tools/javac/lambda/MethodReference37.java	Wed Jul 05 20:36:16 2017 +0200
+++ b/langtools/test/tools/javac/lambda/MethodReference37.java	Wed Jul 05 20:37:12 2017 +0200
@@ -1,6 +1,6 @@
 /*
  * @test /nodynamiccopyright/
- * @bug 8003280
+ * @bug 8003280 8081271
  * @summary Add lambda tests
  *  spurious exceptions when checking references to inner constructors where
  *          the enclosing class is not defined in any outer context
@@ -20,7 +20,7 @@
     static class Outer {
         class Inner { }
 
-        static void test1() {
+        void test1() {
             SAM2<Inner, Outer> sam = Inner::new;
         }
 
--- a/langtools/test/tools/javac/lambda/MethodReference37.out	Wed Jul 05 20:36:16 2017 +0200
+++ b/langtools/test/tools/javac/lambda/MethodReference37.out	Wed Jul 05 20:37:12 2017 +0200
@@ -1,5 +1,5 @@
 MethodReference37.java:24:38: compiler.err.prob.found.req: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.apply.symbol: kindname.constructor, Inner, compiler.misc.no.args, MethodReference37.Outer, kindname.class, MethodReference37.Outer.Inner, (compiler.misc.arg.length.mismatch)))
 MethodReference37.java:29:39: compiler.err.prob.found.req: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.apply.symbol: kindname.constructor, Inner, compiler.misc.no.args, MethodReference37.Outer, kindname.class, MethodReference37.Outer.Inner, (compiler.misc.arg.length.mismatch)))
-MethodReference37.java:34:40: compiler.err.prob.found.req: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.apply.symbol: kindname.constructor, Inner, compiler.misc.no.args, MethodReference37.Outer, kindname.class, MethodReference37.Outer.Inner, (compiler.misc.arg.length.mismatch)))
-MethodReference37.java:38:41: compiler.err.prob.found.req: (compiler.misc.invalid.mref: kindname.constructor, (compiler.misc.cant.apply.symbol: kindname.constructor, Inner, compiler.misc.no.args, MethodReference37.Outer, kindname.class, MethodReference37.Outer.Inner, (compiler.misc.arg.length.mismatch)))
+MethodReference37.java:34:40: compiler.err.invalid.mref: kindname.constructor, (compiler.misc.cant.access.inner.cls.constr: Inner, MethodReference37.Outer, MethodReference37.Outer)
+MethodReference37.java:38:41: compiler.err.invalid.mref: kindname.constructor, (compiler.misc.cant.access.inner.cls.constr: Inner, MethodReference37.Outer, MethodReference37.Outer)
 4 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/methodReference/MethodRefToInnerWithoutOuter.java	Wed Jul 05 20:37:12 2017 +0200
@@ -0,0 +1,24 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8081271
+ * @summary NPE while compiling a program with erroneous use of constructor reference expressions.
+ * @compile/fail/ref=MethodRefToInnerWithoutOuter.out -XDrawDiagnostics MethodRefToInnerWithoutOuter.java
+*/
+
+import java.util.List;
+import java.util.ArrayList;
+
+class MethodRefToInnerBase {
+    class TestString {
+        String str;
+        TestString(String strin) {
+            str = strin;
+        }
+    }
+}
+public class MethodRefToInnerWithoutOuter extends MethodRefToInnerBase {
+    public static void main(String[] args) {
+        List<String> list = new ArrayList<>();
+        list.stream().forEach(TestString::new);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/methodReference/MethodRefToInnerWithoutOuter.out	Wed Jul 05 20:37:12 2017 +0200
@@ -0,0 +1,2 @@
+MethodRefToInnerWithoutOuter.java:22:31: compiler.err.invalid.mref: kindname.constructor, (compiler.misc.cant.access.inner.cls.constr: TestString, , MethodRefToInnerBase)
+1 error
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/scope/RemoveSymbolTest.java	Wed Jul 05 20:37:12 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.
+ *
+ * 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 8080842
+ * @summary Ensure Scope impl can cope with remove() when a field and method share the name.
+ * @run main RemoveSymbolTest
+ */
+
+import java.util.Iterator;
+import java.util.LinkedList;
+
+public class RemoveSymbolTest<W> implements Iterable<W> {
+    static class Widget {
+        private String name;
+        Widget(String s) { name = s; }
+        @Override public String toString() { return name; }
+    }
+
+    private LinkedList<W> data;
+    // Instantiate an Iterable instance using a Lambda expression.
+    // Causes ClassFormatError if a local variable of type Widget is named after one of the methods.
+    private final Iterable<W> myIterator1 = () -> new Iterator<W>() {
+        private W hasNext = null;
+        private int index = 0;
+        @Override public boolean hasNext() { return index < data.size(); }
+        @Override public W next() { return data.get(index++); }
+    };
+
+    // Instantiate an Iterable instance using an anonymous class.
+    // Always works fine regardless of the name of the local variable.
+    private final Iterable<W> myIterator2 =
+        new Iterable<W>() {
+        @Override
+        public Iterator<W> iterator() {
+            return new Iterator<W>() {
+                private W hasNext = null;
+                private int index = 0;
+                @Override public boolean hasNext() { return index < data.size(); }
+                @Override public W next() { return data.get(index++); }
+            };
+        }
+    };
+    public RemoveSymbolTest() { data = new LinkedList<>(); }
+    public void add(W e) { data.add(e); }
+    @Override public String toString() { return data.toString(); }
+    @Override public Iterator<W> iterator() { return myIterator1.iterator(); }
+    public static void main(String[] args) {
+        RemoveSymbolTest<Widget> widgets = new RemoveSymbolTest<>();
+        widgets.add(new Widget("W1"));
+        widgets.add(new Widget("W2"));
+        widgets.add(new Widget("W3"));
+        System.out.println(".foreach() call: ");
+        widgets.forEach(w -> System.out.println(w + " "));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/scope/RemoveSymbolUnitTest.java	Wed Jul 05 20:37:12 2017 +0200
@@ -0,0 +1,98 @@
+/*
+ * 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 8080842
+ * @summary Ensure Scope impl can cope with remove() when a field and method share the name.
+ * @modules jdk.compiler/com.sun.tools.javac.code
+ *          jdk.compiler/com.sun.tools.javac.file
+ *          jdk.compiler/com.sun.tools.javac.util
+ */
+
+import com.sun.tools.javac.util.*;
+import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.code.Scope.*;
+import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.file.JavacFileManager;
+
+public class RemoveSymbolUnitTest {
+
+    Context context;
+    Names names;
+    Symtab symtab;
+
+    public static void main(String... args) throws Exception {
+        new RemoveSymbolUnitTest().run();
+    }
+
+    public void run() {
+        context = new Context();
+        JavacFileManager.preRegister(context); // required by ClassReader which is required by Symtab
+        names = Names.instance(context);
+        symtab = Symtab.instance(context);
+
+        Name hasNext =  names.fromString("hasNext");
+        ClassSymbol clazz = new ClassSymbol(0,
+                                            names.fromString("X"),
+                                            Type.noType,
+                                            symtab.unnamedPackage);
+
+        VarSymbol v = new VarSymbol(0, hasNext, Type.noType, clazz);
+        MethodSymbol m = new MethodSymbol(0, hasNext, Type.noType, clazz);
+
+        // Try enter and remove in different shuffled combinations.
+        // working with fresh scope each time.
+        WriteableScope cs = WriteableScope.create(clazz);
+        cs.enter(v);
+        cs.enter(m);
+        cs.remove(v);
+        Symbol s = cs.findFirst(hasNext);
+        if (s != m)
+            throw new AssertionError("Wrong symbol");
+
+        cs = WriteableScope.create(clazz);
+        cs.enter(m);
+        cs.enter(v);
+        cs.remove(v);
+        s = cs.findFirst(hasNext);
+        if (s != m)
+            throw new AssertionError("Wrong symbol");
+
+        cs = WriteableScope.create(clazz);
+        cs.enter(v);
+        cs.enter(m);
+        cs.remove(m);
+        s = cs.findFirst(hasNext);
+        if (s != v)
+            throw new AssertionError("Wrong symbol");
+
+        cs = WriteableScope.create(clazz);
+        cs.enter(m);
+        cs.enter(v);
+        cs.remove(m);
+        s = cs.findFirst(hasNext);
+        if (s != v)
+            throw new AssertionError("Wrong symbol");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/types/ScopeListenerTest.java	Wed Jul 05 20:37:12 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.
+ */
+
+/*
+ * @test
+ * @bug 8039262
+ * @summary Ensure that using Types.membersClosure does not increase the number of listeners on the
+ *          class's members Scope.
+ */
+
+import com.sun.tools.javac.code.Scope;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symtab;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.file.JavacFileManager;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.Names;
+import java.lang.reflect.Field;
+import java.util.Collection;
+
+public class ScopeListenerTest {
+
+    public static void main(String[] args) throws Exception {
+        new ScopeListenerTest().run();
+    }
+
+    void run() throws Exception {
+        Context context = new Context();
+        JavacFileManager.preRegister(context);
+        Types types = Types.instance(context);
+        Symtab syms = Symtab.instance(context);
+        Names names = Names.instance(context);
+        types.membersClosure(syms.stringType, true);
+        types.membersClosure(syms.stringType, false);
+
+        Field listenersField = Scope.class.getDeclaredField("listeners");
+
+        listenersField.setAccessible(true);
+
+        int listenerCount =
+                ((Collection) listenersField.get(syms.stringType.tsym.members())).size();
+
+        for (int i = 0; i < 100; i++) {
+            types.membersClosure(syms.stringType, true);
+            types.membersClosure(syms.stringType, false);
+        }
+
+        int newListenerCount
+                = ((Collection) listenersField.get(syms.stringType.tsym.members())).size();
+
+        if (listenerCount != newListenerCount) {
+            throw new AssertionError("Orig listener count: " + listenerCount +
+                                     "; new listener count: " + newListenerCount);
+        }
+
+        for (Symbol s : types.membersClosure(syms.stringType, true).getSymbols())
+            ;
+        for (Symbol s : types.membersClosure(syms.stringType, false).getSymbolsByName(names.fromString("substring")))
+            ;
+    }
+
+}
--- a/langtools/test/tools/javadoc/api/basic/GetTask_DocletClassTest.java	Wed Jul 05 20:36:16 2017 +0200
+++ b/langtools/test/tools/javadoc/api/basic/GetTask_DocletClassTest.java	Wed Jul 05 20:37:12 2017 +0200
@@ -28,6 +28,7 @@
  * @modules jdk.javadoc
  * @build APITest
  * @run main GetTask_DocletClassTest
+ * @key randomness
  */
 
 import com.sun.javadoc.DocErrorReporter;
--- a/make/StripBinaries.gmk	Wed Jul 05 20:36:16 2017 +0200
+++ b/make/StripBinaries.gmk	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/.hgtags	Wed Jul 05 20:37:12 2017 +0200
@@ -300,3 +300,4 @@
 00df6e4fc75a83bdd958f9ef86d80e008c9ba967 jdk9-b64
 2054d01ae32649d3179e93d14108fdd6259c1c0d jdk9-b65
 9dd95cff9dae897e8dee712f1f0303c460262288 jdk9-b66
+f822b749821e364cae0b7bd7c8f667d9437e6d83 jdk9-b67
--- a/nashorn/README	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/README	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/make/build.xml	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/make/project.properties	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/samples/find_nonfinals.js	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/NashornScriptEngine.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/scripting/ScriptObjectMirror.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ArrayAccessTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ArrayLiteralTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/AssignmentTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/BinaryTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/BlockTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/BreakTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/CaseTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/CatchTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/CompilationUnitTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/CompoundAssignmentTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ConditionalExpressionTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ContinueTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/DebuggerTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/DoWhileLoopTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/EmptyStatementTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ErroneousTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ExpressionStatementTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ForInLoopTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ForLoopTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/FunctionCallTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/FunctionDeclarationTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/FunctionExpressionTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/IdentifierTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/IfTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/InstanceOfTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/LabeledStatementTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/LineMapImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/LiteralTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/MemberSelectTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/NewTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ObjectLiteralTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/PropertyTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/RegExpLiteralTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ReturnTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/SimpleTreeVisitorES5_1.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/SwitchTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/ThrowTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/TreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/TryTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/UnaryTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/VariableTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/WhileLoopTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/api/tree/WithTreeImpl.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompilationPhase.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SplitIntoFunctions.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/SplitReturn.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/TryNode.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/NashornTextifier.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/Global.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJava.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CompiledFunction.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java	Wed Jul 05 20:37:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ListAdapter.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptingFunctions.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Source.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/NashornBeansLinker.java	Wed Jul 05 20:37:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/test/TEST.ROOT	Wed Jul 05 20:37:12 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:12 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:12 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:12 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:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/test/ScopeTest.java	Wed Jul 05 20:37:12 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	Wed Jul 05 20:36:16 2017 +0200
+++ b/nashorn/test/src/jdk/nashorn/internal/test/framework/TestFinder.java	Wed Jul 05 20:37:12 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