changeset 41344:11390434331a

Merge
author amurillo
date Wed, 05 Oct 2016 06:28:22 -0700
parents e42e78cd7c6f 65200988b2ee
children d65794815f60
files hotspot/make/Dist.gmk hotspot/make/gensrc/GensrcJvmti.gmk jdk/src/java.base/aix/native/libnio/ch/AixNativeThread.c jdk/test/java/beans/XMLEncoder/EnumPrivate.java jdk/test/java/beans/XMLEncoder/EnumPublic.java jdk/test/java/beans/XMLEncoder/java_util_Collections_CheckedCollection.java jdk/test/java/beans/XMLEncoder/java_util_Collections_CheckedList.java jdk/test/java/beans/XMLEncoder/java_util_Collections_CheckedMap.java jdk/test/java/beans/XMLEncoder/java_util_Collections_CheckedRandomAccessList.java jdk/test/java/beans/XMLEncoder/java_util_Collections_CheckedSet.java jdk/test/java/beans/XMLEncoder/java_util_Collections_CheckedSortedMap.java jdk/test/java/beans/XMLEncoder/java_util_Collections_CheckedSortedSet.java jdk/test/java/beans/XMLEncoder/java_util_EnumMap.java jdk/test/java/beans/XMLEncoder/java_util_JumboEnumSet.java jdk/test/java/beans/XMLEncoder/java_util_RegularEnumSet.java langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/file/ModuleNameReader.java
diffstat 177 files changed, 9288 insertions(+), 3422 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Fri Sep 30 02:52:38 2016 -0700
+++ b/.hgtags	Wed Oct 05 06:28:22 2016 -0700
@@ -380,3 +380,4 @@
 e384420383a5b79fa0012ebcb25d8f83cff7f777 jdk-9+135
 1b4b5d01aa11edf24b6fadbe3d2f3e411e3b02cd jdk-9+136
 9cb87c88ed851c0575b8ead753ea238ed5b544e9 jdk-9+137
+d273dfe9a126d3bffe92072547fef2cd1361b0eb jdk-9+138
--- a/.hgtags-top-repo	Fri Sep 30 02:52:38 2016 -0700
+++ b/.hgtags-top-repo	Wed Oct 05 06:28:22 2016 -0700
@@ -380,3 +380,4 @@
 82b94cb5f342319d2cda77f9fa59703ad7fde576 jdk-9+135
 3ec350f5f32af249b59620d7e37b54bdcd77b233 jdk-9+136
 d7f519b004254b19e384131d9f0d0e40e31a0fd3 jdk-9+137
+67c4388142bdf58aec8fefa4475faaa8a5d7380c jdk-9+138
--- a/common/autoconf/buildjdk-spec.gmk.in	Fri Sep 30 02:52:38 2016 -0700
+++ b/common/autoconf/buildjdk-spec.gmk.in	Wed Oct 05 06:28:22 2016 -0700
@@ -33,6 +33,7 @@
 CC := @BUILD_CC@
 CXX := @BUILD_CXX@
 LD := @BUILD_LD@
+LDCXX := @BUILD_LDCXX@
 AS := @BUILD_AS@
 NM := @BUILD_NM@
 AR := @BUILD_AR@
--- a/common/autoconf/generated-configure.sh	Fri Sep 30 02:52:38 2016 -0700
+++ b/common/autoconf/generated-configure.sh	Wed Oct 05 06:28:22 2016 -0700
@@ -687,7 +687,6 @@
 MSVCP_DLL
 MSVCR_DLL
 LIBCXX
-STATIC_CXX_SETTING
 FIXPATH_DETACH_FLAG
 FIXPATH
 BUILD_GTEST
@@ -5092,7 +5091,7 @@
 #CUSTOM_AUTOCONF_INCLUDE
 
 # Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1474894604
+DATE_WHEN_GENERATED=1475218974
 
 ###############################################################################
 #
@@ -53087,49 +53086,10 @@
 
 
   if test "x$OPENJDK_TARGET_OS" = xlinux; then
-    # Test if -lstdc++ works.
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking if dynamic link of stdc++ is possible" >&5
-$as_echo_n "checking if dynamic link of stdc++ is possible... " >&6; }
-    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
-
-    OLD_CXXFLAGS="$CXXFLAGS"
-    CXXFLAGS="$CXXFLAGS -lstdc++"
-    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-return 0;
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
-  has_dynamic_libstdcxx=yes
-else
-  has_dynamic_libstdcxx=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-    CXXFLAGS="$OLD_CXXFLAGS"
-    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
-
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $has_dynamic_libstdcxx" >&5
-$as_echo "$has_dynamic_libstdcxx" >&6; }
-
     # Test if stdc++ can be linked statically.
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking if static link of stdc++ is possible" >&5
 $as_echo_n "checking if static link of stdc++ is possible... " >&6; }
-    STATIC_STDCXX_FLAGS="-Wl,-Bstatic -lstdc++ -lgcc -Wl,-Bdynamic"
+    STATIC_STDCXX_FLAGS="-static-libstdc++ -static-libgcc"
     ac_ext=cpp
 ac_cpp='$CXXCPP $CPPFLAGS'
 ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -53137,9 +53097,7 @@
 ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
 
     OLD_LIBS="$LIBS"
-    OLD_CXX="$CXX"
     LIBS="$STATIC_STDCXX_FLAGS"
-    CXX="$CC"
     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -53159,7 +53117,6 @@
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
     LIBS="$OLD_LIBS"
-    CXX="$OLD_CXX"
     ac_ext=cpp
 ac_cpp='$CXXCPP $CPPFLAGS'
 ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -53169,59 +53126,34 @@
     { $as_echo "$as_me:${as_lineno-$LINENO}: result: $has_static_libstdcxx" >&5
 $as_echo "$has_static_libstdcxx" >&6; }
 
-    if test "x$has_static_libstdcxx" = xno && test "x$has_dynamic_libstdcxx" = xno; then
-      as_fn_error $? "Cannot link to stdc++, neither dynamically nor statically!" "$LINENO" 5
-    fi
-
     if test "x$with_stdc__lib" = xstatic && test "x$has_static_libstdcxx" = xno; then
       as_fn_error $? "Static linking of libstdc++ was not possible!" "$LINENO" 5
     fi
 
-    if test "x$with_stdc__lib" = xdynamic && test "x$has_dynamic_libstdcxx" = xno; then
-      as_fn_error $? "Dynamic linking of libstdc++ was not possible!" "$LINENO" 5
-    fi
-
     # If dynamic was requested, it's available since it would fail above otherwise.
     # If dynamic wasn't requested, go with static unless it isn't available.
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libstdc++" >&5
 $as_echo_n "checking how to link with libstdc++... " >&6; }
-    if test "x$with_stdc__lib" = xdynamic || test "x$has_static_libstdcxx" = xno ||   [[ " $JVM_VARIANTS " =~ " zeroshark " ]]  ; then
-      LIBCXX="$LIBCXX -lstdc++"
-      # To help comparisons with old build, put stdc++ first in JVM_LIBS
-      JVM_LIBS="-lstdc++ $JVM_LIBS"
-      # Ideally, we should test stdc++ for the BUILD toolchain separately. For now
-      # just use the same setting as for the TARGET toolchain.
-      OPENJDK_BUILD_JVM_LIBS="-lstdc++ $OPENJDK_BUILD_JVM_LIBS"
-      LDCXX="$CXX"
-      STATIC_CXX_SETTING="STATIC_CXX=false"
+    if test "x$with_stdc__lib" = xdynamic || test "x$has_static_libstdcxx" = xno \
+        ||   [[ " $JVM_VARIANTS " =~ " zeroshark " ]]  ; then
       { $as_echo "$as_me:${as_lineno-$LINENO}: result: dynamic" >&5
 $as_echo "dynamic" >&6; }
     else
       LIBCXX="$LIBCXX $STATIC_STDCXX_FLAGS"
-      JVM_LDFLAGS="$JVM_LDFLAGS -static-libgcc"
-      # To help comparisons with old build, put stdc++ first in JVM_LIBS
-      JVM_LIBS="-Wl,-Bstatic -lstdc++ -Wl,-Bdynamic $JVM_LIBS"
+      JVM_LDFLAGS="$JVM_LDFLAGS $STATIC_STDCXX_FLAGS"
       # Ideally, we should test stdc++ for the BUILD toolchain separately. For now
       # just use the same setting as for the TARGET toolchain.
-      OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS -static-libgcc"
-      OPENJDK_BUILD_JVM_LIBS="-Wl,-Bstatic -lstdc++ -Wl,-Bdynamic $OPENJDK_BUILD_JVM_LIBS"
-      LDCXX="$CC"
-      STATIC_CXX_SETTING="STATIC_CXX=true"
+      OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS $STATIC_STDCXX_FLAGS"
       { $as_echo "$as_me:${as_lineno-$LINENO}: result: static" >&5
 $as_echo "static" >&6; }
     fi
   fi
 
-
   # libCrun is the c++ runtime-library with SunStudio (roughly the equivalent of gcc's libstdc++.so)
   if test "x$TOOLCHAIN_TYPE" = xsolstudio && test "x$LIBCXX" = x; then
     LIBCXX="${SYSROOT}/usr/lib${OPENJDK_TARGET_CPU_ISADIR}/libCrun.so.1"
   fi
 
-  # TODO better (platform agnostic) test
-  if test "x$OPENJDK_TARGET_OS" = xmacosx && test "x$LIBCXX" = x && test "x$TOOLCHAIN_TYPE" = xgcc; then
-    LIBCXX="-lstdc++"
-  fi
 
 
   # Setup Windows runtime dlls
--- a/common/autoconf/lib-std.m4	Fri Sep 30 02:52:38 2016 -0700
+++ b/common/autoconf/lib-std.m4	Wed Oct 05 06:28:22 2016 -0700
@@ -45,84 +45,44 @@
   )
 
   if test "x$OPENJDK_TARGET_OS" = xlinux; then
-    # Test if -lstdc++ works.
-    AC_MSG_CHECKING([if dynamic link of stdc++ is possible])
-    AC_LANG_PUSH(C++)
-    OLD_CXXFLAGS="$CXXFLAGS"
-    CXXFLAGS="$CXXFLAGS -lstdc++"
-    AC_LINK_IFELSE([AC_LANG_PROGRAM([], [return 0;])],
-        [has_dynamic_libstdcxx=yes],
-        [has_dynamic_libstdcxx=no])
-    CXXFLAGS="$OLD_CXXFLAGS"
-    AC_LANG_POP(C++)
-    AC_MSG_RESULT([$has_dynamic_libstdcxx])
-
     # Test if stdc++ can be linked statically.
     AC_MSG_CHECKING([if static link of stdc++ is possible])
-    STATIC_STDCXX_FLAGS="-Wl,-Bstatic -lstdc++ -lgcc -Wl,-Bdynamic"
+    STATIC_STDCXX_FLAGS="-static-libstdc++ -static-libgcc"
     AC_LANG_PUSH(C++)
     OLD_LIBS="$LIBS"
-    OLD_CXX="$CXX"
     LIBS="$STATIC_STDCXX_FLAGS"
-    CXX="$CC"
     AC_LINK_IFELSE([AC_LANG_PROGRAM([], [return 0;])],
         [has_static_libstdcxx=yes],
         [has_static_libstdcxx=no])
     LIBS="$OLD_LIBS"
-    CXX="$OLD_CXX"
     AC_LANG_POP(C++)
     AC_MSG_RESULT([$has_static_libstdcxx])
 
-    if test "x$has_static_libstdcxx" = xno && test "x$has_dynamic_libstdcxx" = xno; then
-      AC_MSG_ERROR([Cannot link to stdc++, neither dynamically nor statically!])
-    fi
-
     if test "x$with_stdc__lib" = xstatic && test "x$has_static_libstdcxx" = xno; then
       AC_MSG_ERROR([Static linking of libstdc++ was not possible!])
     fi
 
-    if test "x$with_stdc__lib" = xdynamic && test "x$has_dynamic_libstdcxx" = xno; then
-      AC_MSG_ERROR([Dynamic linking of libstdc++ was not possible!])
-    fi
-
     # If dynamic was requested, it's available since it would fail above otherwise.
     # If dynamic wasn't requested, go with static unless it isn't available.
     AC_MSG_CHECKING([how to link with libstdc++])
-    if test "x$with_stdc__lib" = xdynamic || test "x$has_static_libstdcxx" = xno || HOTSPOT_CHECK_JVM_VARIANT(zeroshark); then
-      LIBCXX="$LIBCXX -lstdc++"
-      # To help comparisons with old build, put stdc++ first in JVM_LIBS
-      JVM_LIBS="-lstdc++ $JVM_LIBS"
-      # Ideally, we should test stdc++ for the BUILD toolchain separately. For now
-      # just use the same setting as for the TARGET toolchain.
-      OPENJDK_BUILD_JVM_LIBS="-lstdc++ $OPENJDK_BUILD_JVM_LIBS"
-      LDCXX="$CXX"
-      STATIC_CXX_SETTING="STATIC_CXX=false"
+    if test "x$with_stdc__lib" = xdynamic || test "x$has_static_libstdcxx" = xno \
+        || HOTSPOT_CHECK_JVM_VARIANT(zeroshark); then
       AC_MSG_RESULT([dynamic])
     else
       LIBCXX="$LIBCXX $STATIC_STDCXX_FLAGS"
-      JVM_LDFLAGS="$JVM_LDFLAGS -static-libgcc"
-      # To help comparisons with old build, put stdc++ first in JVM_LIBS
-      JVM_LIBS="-Wl,-Bstatic -lstdc++ -Wl,-Bdynamic $JVM_LIBS"
+      JVM_LDFLAGS="$JVM_LDFLAGS $STATIC_STDCXX_FLAGS"
       # Ideally, we should test stdc++ for the BUILD toolchain separately. For now
       # just use the same setting as for the TARGET toolchain.
-      OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS -static-libgcc"
-      OPENJDK_BUILD_JVM_LIBS="-Wl,-Bstatic -lstdc++ -Wl,-Bdynamic $OPENJDK_BUILD_JVM_LIBS"
-      LDCXX="$CC"
-      STATIC_CXX_SETTING="STATIC_CXX=true"
+      OPENJDK_BUILD_JVM_LDFLAGS="$OPENJDK_BUILD_JVM_LDFLAGS $STATIC_STDCXX_FLAGS"
       AC_MSG_RESULT([static])
     fi
   fi
-  AC_SUBST(STATIC_CXX_SETTING)
 
   # libCrun is the c++ runtime-library with SunStudio (roughly the equivalent of gcc's libstdc++.so)
   if test "x$TOOLCHAIN_TYPE" = xsolstudio && test "x$LIBCXX" = x; then
     LIBCXX="${SYSROOT}/usr/lib${OPENJDK_TARGET_CPU_ISADIR}/libCrun.so.1"
   fi
 
-  # TODO better (platform agnostic) test
-  if test "x$OPENJDK_TARGET_OS" = xmacosx && test "x$LIBCXX" = x && test "x$TOOLCHAIN_TYPE" = xgcc; then
-    LIBCXX="-lstdc++"
-  fi
   AC_SUBST(LIBCXX)
 
   # Setup Windows runtime dlls
--- a/corba/.hgtags	Fri Sep 30 02:52:38 2016 -0700
+++ b/corba/.hgtags	Wed Oct 05 06:28:22 2016 -0700
@@ -380,3 +380,4 @@
 094d0db606db976045f594dba47d4593b715cc81 jdk-9+135
 aa053a3faf266c12b4fd5272da431a3e08e4a3e3 jdk-9+136
 258cf18fa7fc59359b874f8743b7168dc48baf73 jdk-9+137
+27bb44be32076861a0951bcefb07a1d92509a4b6 jdk-9+138
--- a/corba/make/gensrc/Gensrc-java.corba.gmk	Fri Sep 30 02:52:38 2016 -0700
+++ b/corba/make/gensrc/Gensrc-java.corba.gmk	Wed Oct 05 06:28:22 2016 -0700
@@ -38,7 +38,7 @@
     SRC := $(CORBA_TOPDIR)/make/src/classes, \
     BIN := $(BUILDTOOLS_OUTPUTDIR)/corba_tools_classes))
 
-TOOL_LOGUTIL_CMD := $(JAVA) -cp $(BUILDTOOLS_OUTPUTDIR)/corba_tools_classes \
+TOOL_LOGUTIL_CMD := $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/corba_tools_classes \
     build.tools.logutil.MC
 
 $(eval $(call SetupJavaCompilation,BUILD_IDLJ, \
@@ -50,7 +50,7 @@
     EXCLUDE_FILES := ResourceBundleUtil.java module-info.java))
 
 # Force the language to english for predictable source code generation.
-TOOL_IDLJ_CMD := $(JAVA) -cp $(BUILDTOOLS_OUTPUTDIR)/idlj_classes \
+TOOL_IDLJ_CMD := $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/idlj_classes \
     -Duser.language=en com.sun.tools.corba.se.idl.toJavaPortable.Compile
 
 ################################################################################
--- a/hotspot/make/BuildHotspot.gmk	Fri Sep 30 02:52:38 2016 -0700
+++ b/hotspot/make/BuildHotspot.gmk	Wed Oct 05 06:28:22 2016 -0700
@@ -45,10 +45,7 @@
 jsig:
 	+$(MAKE) -f lib/CompileLibjsig.gmk
 
-dist: $(VARIANT_TARGETS) jsig
-	+$(MAKE) -f Dist.gmk
-
-all: dist
+all: $(VARIANT_TARGETS) jsig
 
 .PHONY: $(VARIANT_TARGETS) $(VARIANT_GENSRC_TARGETS) $(VARIANT_LIBS_TARGETS) \
-    jsig dist all
+    jsig all
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/make/CopyToExplodedJdk.gmk	Wed Oct 05 06:28:22 2016 -0700
@@ -0,0 +1,55 @@
+#
+# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  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.
+#
+
+# Copy all built libraries into exploded jdk
+LIB_TARGETS := $(filter $(LIB_OUTPUTDIR)/%, $(TARGETS))
+ifeq ($(OPENJDK_TARGET_OS), windows)
+  $(eval $(call SetupCopyFiles, COPY_LIBS_BIN, \
+      SRC := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base, \
+      DEST := $(JDK_OUTPUTDIR)/bin, \
+      FILES := $(filter-out %.lib, $(LIB_TARGETS)), \
+  ))
+
+  $(eval $(call SetupCopyFiles, COPY_LIBS_LIB, \
+      SRC := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base, \
+      DEST := $(JDK_OUTPUTDIR)/lib, \
+      FILES := $(filter %.lib, $(LIB_TARGETS))))
+
+  TARGETS += $(COPY_LIBS_BIN) $(COPY_LIBS_LIB)
+else
+  $(eval $(call SetupCopyFiles, COPY_LIBS, \
+      SRC := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base, \
+      DEST := $(JDK_OUTPUTDIR)/lib, \
+      FILES := $(filter %$(SHARED_LIBRARY_SUFFIX), $(LIB_TARGETS)), \
+  ))
+  $(eval $(call SetupCopyFiles, LINK_LIBS, \
+      SRC := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base, \
+      DEST := $(JDK_OUTPUTDIR)/lib, \
+      FILES := $(filter-out %$(SHARED_LIBRARY_SUFFIX), $(LIB_TARGETS)), \
+      MACRO := link-file-relative, \
+  ))
+
+  TARGETS += $(COPY_LIBS) $(LINK_LIBS)
+endif
--- a/hotspot/make/Dist.gmk	Fri Sep 30 02:52:38 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,223 +0,0 @@
-#
-# Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.  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.
-#
-
-################################################################################
-# Copy the generated output into well-defined places in the dist directory.
-
-# This must be the first rule
-default: all
-
-include $(SPEC)
-include MakeBase.gmk
-
-$(eval $(call IncludeCustomExtension, hotspot, Dist.gmk))
-
-DIST_OUTPUTDIR := $(HOTSPOT_OUTPUTDIR)/dist
-
-# Unfortunately, all platforms have different target subdirs.
-ifeq ($(OPENJDK_TARGET_OS), windows)
-  LIB_SUBDIR := bin
-else ifeq ($(OPENJDK_TARGET_OS), macosx)
-  LIB_SUBDIR := lib
-else
-  LIB_SUBDIR := lib$(OPENJDK_TARGET_CPU_LIBDIR)
-endif
-
-################################################################################
-# Setup make rules to copy a native library and associated data.
-#
-# Parameter 1 is the name of the rule. This name is used as variable prefix,
-# and the targets generated are listed in a variable by that name.
-#
-# Remaining parameters are named arguments. These include:
-#   NAME -- The base name of the native library (e.g. 'jvm')
-#   VARIANT -- The variant to copy from
-#   VARIANT_TARGET_DIR -- The variant target sub dir, with trailing slash, optional
-SetupDistLibFile = $(NamedParamsMacroTemplate)
-define SetupDistLibFileBody
-  ifneq ($$($1_VARIANT), )
-    $1_SRC_DIR := $$(HOTSPOT_OUTPUTDIR)/variant-$$($1_VARIANT)/lib$$($1_NAME)
-  else
-    $1_SRC_DIR := $$(HOTSPOT_OUTPUTDIR)/lib$$($1_NAME)
-  endif
-  $1_LIB_NAME := $(LIBRARY_PREFIX)$$($1_NAME)
-  $1_TARGET_DIR := $$(DIST_OUTPUTDIR)/$$(LIB_SUBDIR)/$$($1_VARIANT_TARGET_DIR)
-
-  # Copy the the native library.
-  $$(eval $$(call SetupCopyFiles, $1_COPY_LIB, \
-      DEST := $$($1_TARGET_DIR), \
-      FILES := $$(wildcard \
-          $$($1_SRC_DIR)/$$($1_LIB_NAME)$(SHARED_LIBRARY_SUFFIX)), \
-  ))
-
-  TARGETS += $$($1_COPY_LIB)
-
-  # Copy related data (debug symbols, static-build symbols file etc)
-  $$(eval $$(call SetupCopyFiles, $1_COPY_FILES, \
-      DEST := $$($1_TARGET_DIR), \
-      FILES := $$(wildcard \
-          $$(addprefix $$($1_SRC_DIR)/$$($1_LIB_NAME), \
-          .diz .debuginfo .pdb .map .symbols)), \
-  ))
-
-  TARGETS += $$($1_COPY_FILES)
-
-  ifeq ($(OPENJDK_TARGET_OS), macosx)
-    # Debug symbols on macosx is a directory, not a single file, per library.
-    $1_DSYM_SRC := $$($1_SRC_DIR)/$$($1_LIB_NAME)$(SHARED_LIBRARY_SUFFIX).dSYM)
-    ifneq ($$(wildcard $$($1_DSYM_SRC)), )
-      $$(eval $$(call SetupCopyFiles, $1_COPY_DSYM_DIR, \
-          DEST := $$($1_TARGET_DIR), \
-          SRC := $$($1_SRC_DIR), \
-          FILES := $$(shell $(FIND) $$($1_DSYM_SRC) -type f), \
-       ))
-       TARGETS += $$($1_COPY_DSYM_DIR)
-    endif
-  endif
-endef
-
-################################################################################
-# Copy common files, which are independent on the jvm variant(s) being built.
-# For files that were generated during the build, we assume all versions of
-# these files are identical, and just pick one arbitrarily to use as source.
-
-ANY_JVM_VARIANT := $(firstword $(JVM_VARIANTS))
-JVM_VARIANT_OUTPUTDIR := $(HOTSPOT_OUTPUTDIR)/variant-$(ANY_JVM_VARIANT)
-
-### Copy platform-independent .h files
-INCLUDE_FILES_SRC_DIR := $(HOTSPOT_TOPDIR)/src/share/vm
-$(eval $(call SetupCopyFiles, COPY_INCLUDE, \
-    SRC := $(INCLUDE_FILES_SRC_DIR), \
-    DEST := $(DIST_OUTPUTDIR)/include, \
-    FLATTEN := true, \
-    FILES := $(INCLUDE_FILES_SRC_DIR)/prims/jni.h \
-        $(INCLUDE_FILES_SRC_DIR)/code/jvmticmlr.h \
-        $(INCLUDE_FILES_SRC_DIR)/services/jmm.h))
-
-TARGETS += $(COPY_INCLUDE)
-
-### Copy jni_md.h
-
-# This might have been defined in a custom extension
-ifeq ($(JNI_MD_H_SRC), )
-  JNI_MD_H_SRC := $(HOTSPOT_TOPDIR)/src/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/vm/jni_$(HOTSPOT_TARGET_CPU_ARCH).h
-endif
-
-ifeq ($(OPENJDK_TARGET_OS), macosx)
-  # NOTE: This should most likely be darwin, but the old hotspot build uses bsd
-  JNI_MD_SUBDIR := bsd
-else ifeq ($(OPENJDK_TARGET_OS), windows)
-  JNI_MD_SUBDIR := win32
-else
-  JNI_MD_SUBDIR := $(OPENJDK_TARGET_OS)
-endif
-
-# SetupCopyFiles is not used here since it's non-trivial to copy a single
-# file with a different target name.
-$(DIST_OUTPUTDIR)/include/$(JNI_MD_SUBDIR)/jni_md.h: $(JNI_MD_H_SRC)
-	$(call LogInfo, Copying hotspot/dist/include/$(JNI_MD_SUBDIR)/jni_md.h)
-	$(install-file)
-
-TARGETS += $(DIST_OUTPUTDIR)/include/$(JNI_MD_SUBDIR)/jni_md.h
-
-$(eval $(call SetupCopyFiles, COPY_JVMTI_H, \
-    DEST := $(DIST_OUTPUTDIR)/include, \
-    FLATTEN := true, \
-    FILES := $(JVM_VARIANT_OUTPUTDIR)/gensrc/jvmtifiles/jvmti.h))
-
-TARGETS += $(COPY_JVMTI_H)
-
-# NOTE: In the old build, this file was not copied on Windows.
-ifneq ($(OPENJDK_TARGET_OS), windows)
-  $(eval $(call SetupCopyFiles, COPY_JVMTI_HTML, \
-      DEST := $(DIST_OUTPUTDIR)/docs/platform/jvmti, \
-      FILES := $(JVM_VARIANT_OUTPUTDIR)/gensrc/jvmtifiles/jvmti.html))
-endif
-
-TARGETS += $(COPY_JVMTI_HTML)
-
-ifeq ($(OPENJDK_TARGET_OS), windows)
-  $(eval $(call SetupCopyFiles, COPY_JVM_LIB, \
-      DEST := $(DIST_OUTPUTDIR)/lib, \
-      FILES :=$(JVM_VARIANT_OUTPUTDIR)/libjvm/objs/jvm.lib))
-
-  TARGETS += $(COPY_JVM_LIB)
-endif
-
-# Copy libjsig, if it exists
-$(eval $(call SetupDistLibFile, DIST_jsig, \
-    NAME := jsig, \
-))
-
-################################################################################
-# Copy variant-specific files
-
-# Setup make rules to copy a single variant to dist.
-# $1: The name of the variant
-define SetupDistForVariant
-  ifneq ($$(filter client minimal, $1), )
-    VARIANT_TARGET_DIR := $1
-  else
-    # Use 'server' as default target directory name for all other variants.
-    VARIANT_TARGET_DIR := server
-  endif
-
-  $$(eval $$(call SetupDistLibFile, DIST_$(strip $1)_jvm, \
-      NAME := jvm, \
-      VARIANT := $1, \
-      VARIANT_TARGET_DIR := $$(VARIANT_TARGET_DIR)/, \
-  ))
-
-  # Copy the dtrace libraries, if they exist
-  $$(eval $$(call SetupDistLibFile, DIST_$(strip $1)_jvm_db, \
-      NAME := jvm_db, \
-      VARIANT := $1, \
-      VARIANT_TARGET_DIR := $$(VARIANT_TARGET_DIR)/, \
-  ))
-
-  $$(eval $$(call SetupDistLibFile, DIST_$(strip $1)_jvm_dtrace, \
-      NAME := jvm_dtrace, \
-      VARIANT := $1, \
-      VARIANT_TARGET_DIR := $$(VARIANT_TARGET_DIR)/, \
-  ))
-
-  # Copy the Xusage.txt file
-  $$(eval $$(call SetupCopyFiles, DIST_$(strip $1)_Xusage, \
-      DEST := $$(DIST_OUTPUTDIR)/$$(LIB_SUBDIR)/$(strip $1), \
-      FILES := $$(HOTSPOT_OUTPUTDIR)/variant-$(strip $1)/support/misc/Xusage.txt, \
-  ))
-
-  TARGETS += $$(DIST_$(strip $1)_Xusage)
-endef
-
-$(foreach variant, $(JVM_VARIANTS), \
-  $(eval $(call SetupDistForVariant, $(variant))) \
-)
-
-################################################################################
-
-all: $(TARGETS)
-
-.PHONY: all
--- a/hotspot/make/HotspotCommon.gmk	Fri Sep 30 02:52:38 2016 -0700
+++ b/hotspot/make/HotspotCommon.gmk	Wed Oct 05 06:28:22 2016 -0700
@@ -33,6 +33,15 @@
 
 DTRACE_SUPPORT_DIR := $(JVM_SUPPORT_DIR)/dtrace
 
+LIB_OUTPUTDIR := $(call FindLibDirForModule, java.base)
+ifneq ($(filter client minimal, $(JVM_VARIANT)), )
+  JVM_VARIANT_SUBDIR := $(JVM_VARIANT)
+else
+  # Use 'server' as default target directory name for all other variants.
+  JVM_VARIANT_SUBDIR := server
+endif
+JVM_LIB_OUTPUTDIR := $(LIB_OUTPUTDIR)/$(JVM_VARIANT_SUBDIR)
+
 ################################################################################
 
 # Test if a feature is available in the present build of JVM_VARIANT. Will return
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/make/copy/Copy-java.base.gmk	Wed Oct 05 06:28:22 2016 -0700
@@ -0,0 +1,67 @@
+#
+# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  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.
+#
+
+# These include files are currently being copied from the jdk repository for
+# historical reasons. Disable copying from here until this has been cleaned up.
+# The files in hotspot differ slightly from the corresponding files in jdk.
+# See JDK-8167078.
+
+INCLUDE_DST_DIR := $(SUPPORT_OUTPUTDIR)/modules_include/$(MODULE)
+
+################################################################################
+# Copy platform-independent .h files
+$(eval $(call SetupCopyFiles, COPY_INCLUDE_FILES, \
+    SRC := $(HOTSPOT_TOPDIR)/src/share/vm, \
+    DEST := $(INCLUDE_DST_DIR), \
+    FLATTEN := true, \
+    FILES := prims/jni.h code/jvmticmlr.h \
+))
+
+#TARGETS += $(COPY_INCLUDE_FILES)
+
+################################################################################
+# Copy jni_md.h
+
+# This might have been defined in a custom extension
+JNI_MD_H_SRC ?= $(HOTSPOT_TOPDIR)/src/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/vm/jni_$(HOTSPOT_TARGET_CPU_ARCH).h
+
+ifeq ($(OPENJDK_TARGET_OS), macosx)
+  # NOTE: This should most likely be darwin, but the old hotspot build uses bsd
+  JNI_MD_SUBDIR := bsd
+else ifeq ($(OPENJDK_TARGET_OS), windows)
+  JNI_MD_SUBDIR := win32
+else
+  JNI_MD_SUBDIR := $(OPENJDK_TARGET_OS)
+endif
+
+# SetupCopyFiles is not used here since it's non-trivial to copy a single
+# file with a different target name.
+$(INCLUDE_DST_DIR)/$(JNI_MD_SUBDIR)/jni_md.h: $(JNI_MD_H_SRC)
+	$(call LogInfo, Copying hotspot/dist/include/$(JNI_MD_SUBDIR)/jni_md.h)
+	$(install-file)
+
+#TARGETS += $(INCLUDE_DST_DIR)/$(JNI_MD_SUBDIR)/jni_md.h
+
+################################################################################
--- a/hotspot/make/gensrc/GenerateSources.gmk	Fri Sep 30 02:52:38 2016 -0700
+++ b/hotspot/make/gensrc/GenerateSources.gmk	Wed Oct 05 06:28:22 2016 -0700
@@ -47,7 +47,7 @@
 # The Xusage.txt file needs to have platform specific path separator
 $(eval $(call SetupTextFileProcessing, CREATE_XUSAGE, \
     SOURCE_FILES := $(HOTSPOT_TOPDIR)/src/share/vm/Xusage.txt, \
-    OUTPUT_FILE := $(JVM_SUPPORT_DIR)/misc/Xusage.txt, \
+    OUTPUT_FILE := $(JVM_LIB_OUTPUTDIR)/Xusage.txt, \
     REPLACEMENTS := separated by ;> => separated by $(PATH_SEP)> ; , \
 ))
 
--- a/hotspot/make/gensrc/GensrcJvmti.gmk	Fri Sep 30 02:52:38 2016 -0700
+++ b/hotspot/make/gensrc/GensrcJvmti.gmk	Wed Oct 05 06:28:22 2016 -0700
@@ -130,6 +130,21 @@
 TARGETS += $(JVMTI_OUTPUTDIR)/jvmtiEnvRecommended.cpp
 
 ################################################################################
+# Disable copy of jvmti.h from hotspot until this has been cleared up. The file
+# is currently being copied from the jdk repository. See JDK-8167078.
+# Copy jvmti.h to include dir
+
+# The file is the same regardless of jvm variant. Only let one do the copy.
+#ifeq ($(JVM_VARIANT), $(firstword $(JVM_VARIANTS)))
+#  $(eval $(call SetupCopyFiles, COPY_JVMTI_H, \
+#      DEST := $(SUPPORT_OUTPUTDIR)/modules_include/java.base, \
+#      FILES := $(JVMTI_OUTPUTDIR)/jvmti.h, \
+#  ))
+
+#  TARGETS += $(COPY_JVMTI_H)
+#endif
+
+################################################################################
 # Create trace files in gensrc/tracefiles
 
 TRACE_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/gensrc/tracefiles
--- a/hotspot/make/lib/CompileDtracePostJvm.gmk	Fri Sep 30 02:52:38 2016 -0700
+++ b/hotspot/make/lib/CompileDtracePostJvm.gmk	Wed Oct 05 06:28:22 2016 -0700
@@ -180,7 +180,7 @@
 
     $(eval $(call SetupNativeCompilation, BUILD_LIBJVM_DTRACE, \
         LIBRARY := jvm_dtrace, \
-        OUTPUT_DIR := $(LIBJVM_DTRACE_OUTPUTDIR), \
+        OUTPUT_DIR := $(JVM_LIB_OUTPUTDIR), \
         SRC := $(HOTSPOT_TOPDIR)/src/os/solaris/dtrace, \
         INCLUDE_FILES := jvm_dtrace.c, \
         CFLAGS := -m64 -G -mt -KPIC, \
@@ -197,7 +197,7 @@
     # the old build.
     $(eval $(call SetupNativeCompilation, BUILD_LIBJVM_DB, \
         LIBRARY := jvm_db, \
-        OUTPUT_DIR := $(LIBJVM_DB_OUTPUTDIR), \
+        OUTPUT_DIR := $(JVM_LIB_OUTPUTDIR), \
         SRC := $(HOTSPOT_TOPDIR)/src/os/solaris/dtrace, \
         INCLUDE_FILES := libjvm_db.c, \
         CFLAGS := -I$(JVM_VARIANT_OUTPUTDIR)/gensrc -I$(DTRACE_SUPPORT_DIR) \
--- a/hotspot/make/lib/CompileGtest.gmk	Fri Sep 30 02:52:38 2016 -0700
+++ b/hotspot/make/lib/CompileGtest.gmk	Wed Oct 05 06:28:22 2016 -0700
@@ -55,7 +55,7 @@
 # Disabling switch warning for clang because of test source.
 
 $(eval $(call SetupNativeCompilation, BUILD_GTEST_LIBJVM, \
-    TOOLCHAIN := $(JVM_TOOLCHAIN), \
+    TOOLCHAIN := TOOLCHAIN_LINK_CXX, \
     LIBRARY := jvm, \
     OUTPUT_DIR := $(JVM_OUTPUTDIR)/gtest, \
     OBJECT_DIR := $(JVM_OUTPUTDIR)/gtest/objs, \
@@ -95,7 +95,7 @@
 ################################################################################
 
 $(eval $(call SetupNativeCompilation, BUILD_GTEST_LAUNCHER, \
-    TOOLCHAIN := $(JVM_TOOLCHAIN), \
+    TOOLCHAIN := TOOLCHAIN_LINK_CXX, \
     PROGRAM := gtestLauncher, \
     OUTPUT_DIR := $(JVM_OUTPUTDIR)/gtest, \
     EXTRA_FILES := $(GTEST_LAUNCHER_SRC), \
--- a/hotspot/make/lib/CompileJvm.gmk	Fri Sep 30 02:52:38 2016 -0700
+++ b/hotspot/make/lib/CompileJvm.gmk	Wed Oct 05 06:28:22 2016 -0700
@@ -143,13 +143,6 @@
   JVM_PRECOMPILED_HEADER := $(HOTSPOT_TOPDIR)/src/share/vm/precompiled/precompiled.hpp
 endif
 
-ifneq ($(filter $(OPENJDK_TARGET_OS), macosx aix solaris), )
-  # On macosx, aix and solaris we have to link with the C++ compiler
-  JVM_TOOLCHAIN := TOOLCHAIN_LINK_CXX
-else
-  JVM_TOOLCHAIN := TOOLCHAIN_DEFAULT
-endif
-
 ifeq ($(OPENJDK_TARGET_CPU), x86)
   JVM_EXCLUDE_PATTERNS += x86_64
 else ifeq ($(OPENJDK_TARGET_CPU), x86_64)
@@ -181,22 +174,15 @@
   JVM_RCFLAGS += -D"HS_FILEDESC=$(HOTSPOT_VM_DISTRO) $(RC_DESC)$(JVM_VARIANT) VM"
 endif
 
-ifeq ($(OPENJDK_TARGET_OS), macosx)
-  # NOTE: The old build did not strip binaries on macosx.
-  JVM_STRIP_SYMBOLS := false
-else
-  JVM_STRIP_SYMBOLS := true
-endif
-
 JVM_OPTIMIZATION ?= HIGHEST_JVM
 
 ################################################################################
 # Now set up the actual compilation of the main hotspot native library
 
 $(eval $(call SetupNativeCompilation, BUILD_LIBJVM, \
-    TOOLCHAIN := $(JVM_TOOLCHAIN), \
+    TOOLCHAIN := TOOLCHAIN_LINK_CXX, \
     LIBRARY := jvm, \
-    OUTPUT_DIR := $(JVM_OUTPUTDIR), \
+    OUTPUT_DIR := $(JVM_LIB_OUTPUTDIR), \
     SRC := $(JVM_SRC_DIRS), \
     EXCLUDES := $(JVM_EXCLUDES), \
     EXCLUDE_FILES := $(JVM_EXCLUDE_FILES), \
@@ -218,7 +204,6 @@
     OBJECT_DIR := $(JVM_OUTPUTDIR)/objs, \
     MAPFILE := $(JVM_MAPFILE), \
     USE_MAPFILE_FOR_SYMBOLS := true, \
-    STRIP_SYMBOLS := $(JVM_STRIP_SYMBOLS), \
     EMBED_MANIFEST := true, \
     RC_FLAGS := $(JVM_RCFLAGS), \
     VERSIONINFO_RESOURCE := $(HOTSPOT_TOPDIR)/src/os/windows/vm/version.rc, \
@@ -226,6 +211,18 @@
     PRECOMPILED_HEADER_EXCLUDE := $(JVM_PRECOMPILED_HEADER_EXCLUDE), \
 ))
 
+ifeq ($(OPENJDK_TARGET_OS), windows)
+  # It doesn't matter which jvm.lib file gets exported, but we need
+  # to pick just one.
+  ifeq ($(JVM_VARIANT), $(firstword $(JVM_VARIANTS)))
+    $(eval $(call SetupCopyFiles, COPY_JVM_LIB, \
+        DEST := $(LIB_OUTPUTDIR), \
+        FILES :=$(JVM_VARIANT_OUTPUTDIR)/libjvm/objs/jvm.lib, \
+    ))
+    TARGETS += $(COPY_JVM_LIB)
+  endif
+endif
+
 # AIX warning explanation:
 # 1500-010  : (W) WARNING in ...: Infinite loop.  Program may not stop.
 #             There are several infinite loops in the vm, so better suppress.
--- a/hotspot/make/lib/CompileLibjsig.gmk	Fri Sep 30 02:52:38 2016 -0700
+++ b/hotspot/make/lib/CompileLibjsig.gmk	Wed Oct 05 06:28:22 2016 -0700
@@ -34,7 +34,6 @@
 
 ifneq ($(OPENJDK_TARGET_OS), windows)
   ifeq ($(STATIC_BUILD), false)
-    LIBJSIG_STRIP_SYMBOLS := true
     ifeq ($(OPENJDK_TARGET_OS), linux)
       LIBJSIG_CFLAGS := -fPIC -D_GNU_SOURCE -D_REENTRANT $(EXTRA_CFLAGS)
       LIBJSIG_LDFLAGS := $(LDFLAGS_HASH_STYLE) $(EXTRA_CFLAGS)
@@ -72,8 +71,6 @@
     else ifeq ($(OPENJDK_TARGET_OS), macosx)
       LIBJSIG_CFLAGS := -m64 -D_GNU_SOURCE -pthread -mno-omit-leaf-frame-pointer -mstack-alignment=16 -fPIC
       LIBJSIG_LDFLAGS := $(LDFLAGS_HASH_STYLE)
-      # NOTE: This lib is not stripped on macosx in old build. Looks like a mistake.
-      LIBJSIG_STRIP_SYMBOLS := false
     else
       $(error Unknown target OS $(OPENJDK_TARGET_OS) in CompileLibjsig.gmk)
     endif
@@ -84,20 +81,71 @@
 
     LIBJSIG_LDFLAGS += $(SHARED_LIBRARY_FLAGS)
 
+    LIB_OUTPUTDIR := $(call FindLibDirForModule, java.base)
+
     $(eval $(call SetupNativeCompilation, BUILD_LIBJSIG, \
         LIBRARY := jsig, \
         EXTRA_FILES := $(LIBJSIG_SRC_FILE), \
-        OUTPUT_DIR := $(LIBJSIG_OUTPUTDIR), \
+        OUTPUT_DIR := $(LIB_OUTPUTDIR), \
         LANG := C, \
         CFLAGS := $(LIBJSIG_CFLAGS) $(LIBJSIG_CPU_FLAGS), \
         LDFLAGS := $(LIBJSIG_LDFLAGS) $(LIBJSIG_CPU_FLAGS), \
         LIBS := $(LIBJSIG_LIBS), \
         MAPFILE := $(LIBJSIG_MAPFILE), \
         OBJECT_DIR := $(LIBJSIG_OUTPUTDIR)/objs, \
-        STRIP_SYMBOLS := $(LIBJSIG_STRIP_SYMBOLS), \
     ))
 
     TARGETS += $(BUILD_LIBJSIG)
+
+    ############################################################################
+    # Create symlinks in each variant sub dir
+    ifeq ($(OPENJDK_TARGET_OS), macosx)
+      DEBUG_INFO_SUFFIX := $(SHARED_LIBRARY_SUFFIX).dSYM
+    else
+      DEBUG_INFO_SUFFIX := .debuginfo
+    endif
+
+    # $1 variant subdir
+    define CreateSymlinks
+      # Always symlink from libdir/variant/libjsig.so -> ../libjsig.so and
+      # the corresponding debuginfo.
+      $(LIB_OUTPUTDIR)/$1/$(call SHARED_LIBRARY,jsig): \
+          $(LIB_OUTPUTDIR)/$(call SHARED_LIBRARY,jsig)
+		$$(call MakeDir, $$(@D))
+		$(RM) $$@
+		$(LN) -s ../$$(@F) $$@
+
+      TARGETS += $(LIB_OUTPUTDIR)/$1/$(call SHARED_LIBRARY,jsig)
+
+      ifeq ($(COPY_DEBUG_SYMBOLS), true)
+        $(LIB_OUTPUTDIR)/$1/$(LIBRARY_PREFIX)jsig$(DEBUG_INFO_SUFFIX): \
+            $(LIB_OUTPUTDIR)/$(call SHARED_LIBRARY,jsig)
+		$$(call MakeDir, $$(@D))
+		$(RM) $$@
+		$(LN) -s ../$$(@F) $$@
+
+        TARGETS += $(LIB_OUTPUTDIR)/$1/$(LIBRARY_PREFIX)jsig$(DEBUG_INFO_SUFFIX)
+
+        ifeq ($(ZIP_EXTERNAL_DEBUG_SYMBOLS), true)
+          $(LIB_OUTPUTDIR)/$1/$(LIBRARY_PREFIX)jsig.diz: \
+              $(LIB_OUTPUTDIR)/$1/$(LIBRARY_PREFIX)jsig$(DEBUG_INFO_SUFFIX)
+			$(CD) $$(@D) && $(ZIP) -q -y $$@ $$(basename $$(@F))$(DEBUG_INFO_SUFFIX)
+
+          TARGETS += $(LIB_OUTPUTDIR)/$1/$(LIBRARY_PREFIX)jsig.diz
+        endif
+      endif
+    endef
+
+    # The subdir is the same as the variant for client and minimal, for all
+    # others it's server.
+    VARIANT_SUBDIRS := $(filter client minimal, $(JVM_VARIANTS)) \
+        $(if $(filter-out client minimal, $(JVM_VARIANTS)), server)
+    $(foreach v, $(VARIANT_SUBDIRS), $(eval $(call CreateSymlinks,$v)))
+
+    ############################################################################
+
+    include CopyToExplodedJdk.gmk
+
   endif
 endif
 
--- a/hotspot/make/lib/CompileLibraries.gmk	Fri Sep 30 02:52:38 2016 -0700
+++ b/hotspot/make/lib/CompileLibraries.gmk	Wed Oct 05 06:28:22 2016 -0700
@@ -41,6 +41,8 @@
   include lib/CompileGtest.gmk
 endif
 
+include CopyToExplodedJdk.gmk
+
 all: $(TARGETS)
 
 .PHONY: all
--- a/jaxp/.hgtags	Fri Sep 30 02:52:38 2016 -0700
+++ b/jaxp/.hgtags	Wed Oct 05 06:28:22 2016 -0700
@@ -380,3 +380,4 @@
 f695240370c77a25fed88225a392e7d530cb4d78 jdk-9+135
 f1eafcb0eb7182b937bc93f214d8cabd01ec4d59 jdk-9+136
 a8d5fe567ae72b4931040e59dd4478363f9004f5 jdk-9+137
+69c3b12ba75b2e321dee731ac545e7fbff608451 jdk-9+138
--- a/jaxws/.hgtags	Fri Sep 30 02:52:38 2016 -0700
+++ b/jaxws/.hgtags	Wed Oct 05 06:28:22 2016 -0700
@@ -383,3 +383,4 @@
 22631824f55128a7ab6605493b3001a37af6a168 jdk-9+135
 09ec13a99f50a4a346180d1e3b0fd8bc1ee399ce jdk-9+136
 297c16d401c534cb879809d2a746d21ca99d2954 jdk-9+137
+7d3a8f52b124db26ba8425c2931b748dd9d2791b jdk-9+138
--- a/jdk/.hgtags	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/.hgtags	Wed Oct 05 06:28:22 2016 -0700
@@ -380,3 +380,4 @@
 021369229cfd0b5feb76834b2ea498f47f43c0f3 jdk-9+135
 54c5931849a33a363e03fdffa141503f5cc4779d jdk-9+136
 e72df94364e3686e7d62059ce0d6b187b82da713 jdk-9+137
+665096863382bf23ce891307cf2a7511e77c1c88 jdk-9+138
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/CompileModuleTools.gmk	Wed Oct 05 06:28:22 2016 -0700
@@ -0,0 +1,42 @@
+#
+# Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  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 $(SPEC)
+include MakeBase.gmk
+include JavaCompilation.gmk
+include SetupJavaCompilers.gmk
+
+TOOLS_CLASSES_DIR := $(BUILDTOOLS_OUTPUTDIR)/tools_jigsaw_classes
+
+$(eval $(call SetupJavaCompilation,BUILD_JIGSAW_TOOLS, \
+    SETUP := GENERATE_USINGJDKBYTECODE, \
+    SRC := $(JDK_TOPDIR)/make/src/classes, \
+    INCLUDES := build/tools/deps \
+                build/tools/jigsaw, \
+    BIN := $(TOOLS_CLASSES_DIR), \
+    ADD_JAVAC_FLAGS := \
+        --add-exports jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED \
+        --add-exports java.base/jdk.internal.module=ALL-UNNAMED \
+))
--- a/jdk/make/ModuleTools.gmk	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/make/ModuleTools.gmk	Wed Oct 05 06:28:22 2016 -0700
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -26,18 +26,14 @@
 include $(SPEC)
 include MakeBase.gmk
 include JavaCompilation.gmk
-include SetupJavaCompilers.gmk
 
 TOOLS_CLASSES_DIR := $(BUILDTOOLS_OUTPUTDIR)/tools_jigsaw_classes
 
-$(eval $(call SetupJavaCompilation,BUILD_JIGSAW_TOOLS, \
-    SETUP := GENERATE_USINGJDKBYTECODE, \
-    SRC := $(JDK_TOPDIR)/make/src/classes, \
-    INCLUDES := build/tools/deps \
-                build/tools/jigsaw, \
-    BIN := $(TOOLS_CLASSES_DIR), \
-    ADD_JAVAC_FLAGS := --add-exports jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED ))
-
+# To avoid reevaluating the compilation setup for the tools each time this file
+# is included, the actual compilation is handled by CompileModuleTools.gmk. The
+# following trick is used to be able to declare a dependency on the built tools.
+BUILD_TOOLS_JDK := $(call SetupJavaCompilationCompileTarget, \
+    BUILD_JIGSAW_TOOLS, $(TOOLS_CLASSES_DIR))
 
 TOOL_GENGRAPHS := $(BUILD_JAVA) -esa -ea -cp $(TOOLS_CLASSES_DIR) \
     build.tools.jigsaw.GenGraphs
@@ -45,3 +41,8 @@
 TOOL_MODULESUMMARY := $(BUILD_JAVA) -esa -ea -cp $(TOOLS_CLASSES_DIR) \
     --add-exports jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED \
     build.tools.jigsaw.ModuleSummary
+
+TOOL_ADD_PACKAGES_ATTRIBUTE := $(BUILD_JAVA) $(JAVA_FLAGS_SMALL) \
+    -cp $(TOOLS_CLASSES_DIR) \
+    --add-exports java.base/jdk.internal.module=ALL-UNNAMED \
+    build.tools.jigsaw.AddPackagesAttribute
--- a/jdk/make/lib/CoreLibraries.gmk	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/make/lib/CoreLibraries.gmk	Wed Oct 05 06:28:22 2016 -0700
@@ -236,10 +236,6 @@
 
 ##########################################################################################
 
-ifeq ($(OPENJDK_TARGET_OS), aix)
-  LIBJIMAGE_TOOLCHAIN := TOOLCHAIN_LINK_CXX
-endif # OPENJDK_TARGET_OS aix
-
 JIMAGELIB_CPPFLAGS := \
     -I$(JDK_TOPDIR)/src/java.base/share/native/libjava \
     -I$(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libjava \
@@ -249,7 +245,7 @@
 
 $(eval $(call SetupNativeCompilation,BUILD_LIBJIMAGE, \
     LIBRARY := jimage, \
-    TOOLCHAIN := $(LIBJIMAGE_TOOLCHAIN), \
+    TOOLCHAIN := TOOLCHAIN_LINK_CXX, \
     OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
     OPTIMIZATION := LOW, \
     SRC := $(JDK_TOPDIR)/src/java.base/share/native/libjimage \
--- a/jdk/make/lib/NioLibraries.gmk	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/make/lib/NioLibraries.gmk	Wed Oct 05 06:28:22 2016 -0700
@@ -53,12 +53,7 @@
 endif
 
 ifeq ($(OPENJDK_TARGET_OS), aix)
-  BUILD_LIBNIO_MAPFILE:=$(JDK_TOPDIR)/make/mapfiles/libnio/mapfile-$(OPENJDK_TARGET_OS)
-  BUILD_LIBNIO_EXFILES += \
-      /NativeThread.c
-  # Notice: we really need the leading slash here because otherwise every
-  # FILE_NAME in EXCLUDE_FILES will actually match any file ending in FILE_NAME
-  # (e.g. 'NativeThread.c' will also exclude 'AixNativeThread.c').
+  BUILD_LIBNIO_MAPFILE := $(JDK_TOPDIR)/make/mapfiles/libnio/mapfile-$(OPENJDK_TARGET_OS)
 endif
 
 $(eval $(call SetupNativeCompilation,BUILD_LIBNIO, \
--- a/jdk/make/rmic/RmicCommon.gmk	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/make/rmic/RmicCommon.gmk	Wed Oct 05 06:28:22 2016 -0700
@@ -37,7 +37,7 @@
   RMIC_MAIN_CLASS := sun.rmi.rmic.Main
 endif
 
-RMIC := $(JAVA) $(INTERIM_OVERRIDE_MODULES_ARGS) $(RMIC_MAIN_CLASS)
+RMIC := $(JAVA_SMALL) $(INTERIM_OVERRIDE_MODULES_ARGS) $(RMIC_MAIN_CLASS)
 
 CLASSES_DIR := $(JDK_OUTPUTDIR)/modules
 # NOTE: If the smart javac dependency management is reintroduced, these classes risk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/src/classes/build/tools/jigsaw/AddPackagesAttribute.java	Wed Oct 05 06:28:22 2016 -0700
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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 build.tools.jigsaw;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReference;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Optional;
+import java.util.Set;
+
+import jdk.internal.module.ModuleInfoExtender;
+
+/**
+ * Adds the Packages class file attribute to each module-info.class in an
+ * exploded build.
+ */
+
+public class AddPackagesAttribute {
+
+    public static void main(String[] args) throws IOException {
+
+        if (args.length != 1) {
+            System.err.println("Usage AddPackagesAttribute exploded-java-home");
+            System.exit(-1);
+        }
+
+        String home = args[0];
+        Path dir = Paths.get(home, "modules");
+
+        ModuleFinder finder = ModuleFinder.of(dir);
+
+        try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
+            for (Path entry : stream) {
+                Path mi = entry.resolve("module-info.class");
+                if (Files.isRegularFile(mi)) {
+                    String mn = entry.getFileName().toString();
+                    Optional<ModuleReference> omref = finder.find(mn);
+                    if (omref.isPresent()) {
+                        Set<String> packages = omref.get().descriptor().conceals();
+                        addPackagesAttribute(mi, packages);
+                    }
+                }
+            }
+        }
+    }
+
+    static void addPackagesAttribute(Path mi, Set<String> packages) throws IOException {
+        byte[] bytes;
+        try (InputStream in = Files.newInputStream(mi)) {
+            ModuleInfoExtender extender = ModuleInfoExtender.newExtender(in);
+            extender.conceals(packages);
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            extender.write(baos);
+            bytes = baos.toByteArray();
+        }
+
+        Files.write(mi, bytes);
+    }
+
+}
--- a/jdk/src/java.base/aix/native/libnio/ch/AixNativeThread.c	Fri Sep 30 02:52:38 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2002, 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.
- */
-
-#include <sys/types.h>
-#include <string.h>
-#include "jni.h"
-#include "jni_util.h"
-#include "jvm.h"
-#include "jlong.h"
-#include "sun_nio_ch_NativeThread.h"
-
-#include <pthread.h>
-#include <sys/signal.h>
-
-/* Also defined in src/aix/native/java/net/aix_close.c */
-#define INTERRUPT_SIGNAL (SIGRTMAX - 1)
-
-static void
-nullHandler(int sig)
-{
-}
-
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_NativeThread_init(JNIEnv *env, jclass cl)
-{
-    /* Install the null handler for INTERRUPT_SIGNAL. This might overwrite the
-     * handler previously installed by java/net/aix_close.c, but that's okay
-     * since neither handler actually does anything.  We install our own
-     * handler here simply out of paranoia; ultimately the two mechanisms
-     * should somehow be unified, perhaps within the VM.
-     */
-
-    sigset_t ss;
-    struct sigaction sa, osa;
-    sa.sa_handler = nullHandler;
-    sa.sa_flags = 0;
-    sigemptyset(&sa.sa_mask);
-    if (sigaction(INTERRUPT_SIGNAL, &sa, &osa) < 0)
-        JNU_ThrowIOExceptionWithLastError(env, "sigaction");
-}
-
-JNIEXPORT jlong JNICALL
-Java_sun_nio_ch_NativeThread_current(JNIEnv *env, jclass cl)
-{
-    return (long)pthread_self();
-}
-
-JNIEXPORT void JNICALL
-Java_sun_nio_ch_NativeThread_signal(JNIEnv *env, jclass cl, jlong thread)
-{
-    if (pthread_kill((pthread_t)thread, INTERRUPT_SIGNAL))
-        JNU_ThrowIOExceptionWithLastError(env, "Thread signal failed");
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/java/io/ObjectInputFilter.java	Wed Oct 05 06:28:22 2016 -0700
@@ -0,0 +1,631 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.io;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.Security;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Function;
+
+
+/**
+ * Filter classes, array lengths, and graph metrics during deserialization.
+ * If set on an {@link ObjectInputStream}, the {@link #checkInput checkInput(FilterInfo)}
+ * method is called to validate classes, the length of each array,
+ * the number of objects being read from the stream, the depth of the graph,
+ * and the total number of bytes read from the stream.
+ * <p>
+ * A filter can be set via {@link ObjectInputStream#setObjectInputFilter setObjectInputFilter}
+ * for an individual ObjectInputStream.
+ * A filter can be set via {@link Config#setSerialFilter(ObjectInputFilter) Config.setSerialFilter}
+ * to affect every {@code ObjectInputStream} that does not otherwise set a filter.
+ * <p>
+ * A filter determines whether the arguments are {@link Status#ALLOWED ALLOWED}
+ * or {@link Status#REJECTED REJECTED} and should return the appropriate status.
+ * If the filter cannot determine the status it should return
+ * {@link Status#UNDECIDED UNDECIDED}.
+ * Filters should be designed for the specific use case and expected types.
+ * A filter designed for a particular use may be passed a class that is outside
+ * of the scope of the filter. If the purpose of the filter is to black-list classes
+ * then it can reject a candidate class that matches and report UNDECIDED for others.
+ * A filter may be called with class equals {@code null}, {@code arrayLength} equal -1,
+ * the depth, number of references, and stream size and return a status
+ * that reflects only one or only some of the values.
+ * This allows a filter to specific about the choice it is reporting and
+ * to use other filters without forcing either allowed or rejected status.
+ *
+ * <p>
+ * Typically, a custom filter should check if a process-wide filter
+ * is configured and defer to it if so. For example,
+ * <pre>{@code
+ * ObjectInputFilter.Status checkInput(FilterInfo info) {
+ *     ObjectInputFilter serialFilter = ObjectInputFilter.Config.getSerialFilter();
+ *     if (serialFilter != null) {
+ *         ObjectInputFilter.Status status = serialFilter.checkInput(info);
+ *         if (status != ObjectInputFilter.Status.UNDECIDED) {
+ *             // The process-wide filter overrides this filter
+ *             return status;
+ *         }
+ *     }
+ *     if (info.serialClass() != null &&
+ *         Remote.class.isAssignableFrom(info.serialClass())) {
+ *         return Status.REJECTED;      // Do not allow Remote objects
+ *     }
+ *     return Status.UNDECIDED;
+ * }
+ *}</pre>
+ * <p>
+ * Unless otherwise noted, passing a {@code null} argument to a
+ * method in this interface and its nested classes will cause a
+ * {@link NullPointerException} to be thrown.
+ *
+ * @see ObjectInputStream#setObjectInputFilter(ObjectInputFilter)
+ * @since 9
+ */
+@FunctionalInterface
+public interface ObjectInputFilter {
+
+    /**
+     * Check the class, array length, number of object references, depth,
+     * stream size, and other available filtering information.
+     * Implementations of this method check the contents of the object graph being created
+     * during deserialization. The filter returns {@link Status#ALLOWED Status.ALLOWED},
+     * {@link Status#REJECTED Status.REJECTED}, or {@link Status#UNDECIDED Status.UNDECIDED}.
+     *
+     * @param filterInfo provides information about the current object being deserialized,
+     *             if any, and the status of the {@link ObjectInputStream}
+     * @return  {@link Status#ALLOWED Status.ALLOWED} if accepted,
+     *          {@link Status#REJECTED Status.REJECTED} if rejected,
+     *          {@link Status#UNDECIDED Status.UNDECIDED} if undecided.
+     * @since 9
+     */
+    Status checkInput(FilterInfo filterInfo);
+
+    /**
+     * FilterInfo provides access to information about the current object
+     * being deserialized and the status of the {@link ObjectInputStream}.
+     * @since 9
+     */
+    interface FilterInfo {
+        /**
+         * The class of an object being deserialized.
+         * For arrays, it is the array type.
+         * For example, the array class name of a 2 dimensional array of strings is
+         * "{@code [[Ljava.lang.String;}".
+         * To check the array's element type, iteratively use
+         * {@link Class#getComponentType() Class.getComponentType} while the result
+         * is an array and then check the class.
+         * The {@code serialClass is null} in the case where a new object is not being
+         * created and to give the filter a chance to check the depth, number of
+         * references to existing objects, and the stream size.
+         *
+         * @return class of an object being deserialized; may be null
+         */
+        Class<?> serialClass();
+
+        /**
+         * The number of array elements when deserializing an array of the class.
+         *
+         * @return the non-negative number of array elements when deserializing
+         * an array of the class, otherwise -1
+         */
+        long arrayLength();
+
+        /**
+         * The current depth.
+         * The depth starts at {@code 1} and increases for each nested object and
+         * decrements when each nested object returns.
+         *
+         * @return the current depth
+         */
+        long depth();
+
+        /**
+         * The current number of object references.
+         *
+         * @return the non-negative current number of object references
+         */
+        long references();
+
+        /**
+         * The current number of bytes consumed.
+         * @implSpec  {@code streamBytes} is implementation specific
+         * and may not be directly related to the object in the stream
+         * that caused the callback.
+         *
+         * @return the non-negative current number of bytes consumed
+         */
+        long streamBytes();
+    }
+
+    /**
+     * The status of a check on the class, array length, number of references,
+     * depth, and stream size.
+     *
+     * @since 9
+     */
+    enum Status {
+        /**
+         * The status is undecided, not allowed and not rejected.
+         */
+        UNDECIDED,
+        /**
+         * The status is allowed.
+         */
+        ALLOWED,
+        /**
+         * The status is rejected.
+         */
+        REJECTED;
+    }
+
+    /**
+     * A utility class to set and get the process-wide filter or create a filter
+     * from a pattern string. If a process-wide filter is set, it will be
+     * used for each {@link ObjectInputStream} that does not set its own filter.
+     * <p>
+     * When setting the filter, it should be stateless and idempotent,
+     * reporting the same result when passed the same arguments.
+     * <p>
+     * The filter is configured using the {@link java.security.Security}
+     * property {@code jdk.serialFilter} and can be overridden by
+     * the System property {@code jdk.serialFilter}.
+     *
+     * The syntax is the same as for the {@link #createFilter(String) createFilter} method.
+     *
+     * @since 9
+     */
+    final class Config {
+        /* No instances. */
+        private Config() {}
+
+        /**
+         * Lock object for process-wide filter.
+         */
+        private final static Object serialFilterLock = new Object();
+
+        /**
+         * Debug: Logger
+         */
+        private final static System.Logger configLog;
+
+        /**
+         * Logger for debugging.
+         */
+        static void filterLog(System.Logger.Level level, String msg, Object... args) {
+            if (configLog != null) {
+                configLog.log(level, msg, args);
+            }
+        }
+
+        /**
+         * The name for the process-wide deserialization filter.
+         * Used as a system property and a java.security.Security property.
+         */
+        private final static String SERIAL_FILTER_PROPNAME = "jdk.serialFilter";
+
+        /**
+         * The process-wide filter; may be null.
+         * Lookup the filter in java.security.Security or
+         * the system property.
+         */
+        private final static ObjectInputFilter configuredFilter;
+
+        static {
+            configuredFilter = AccessController
+                    .doPrivileged((PrivilegedAction<ObjectInputFilter>) () -> {
+                        String props = System.getProperty(SERIAL_FILTER_PROPNAME);
+                        if (props == null) {
+                            props = Security.getProperty(SERIAL_FILTER_PROPNAME);
+                        }
+                        if (props != null) {
+                            System.Logger log =
+                                    System.getLogger("java.io.serialization");
+                            log.log(System.Logger.Level.INFO,
+                                    "Creating serialization filter from {0}", props);
+                            try {
+                                return createFilter(props);
+                            } catch (RuntimeException re) {
+                                log.log(System.Logger.Level.ERROR,
+                                        "Error configuring filter: {0}", re);
+                            }
+                        }
+                        return null;
+                    });
+            configLog = (configuredFilter != null) ? System.getLogger("java.io.serialization") : null;
+        }
+
+        /**
+         * Current configured filter.
+         */
+        private static ObjectInputFilter serialFilter = configuredFilter;
+
+        /**
+         * Returns the process-wide serialization filter or {@code null} if not configured.
+         *
+         * @return the process-wide serialization filter or {@code null} if not configured
+         */
+        public static ObjectInputFilter getSerialFilter() {
+            synchronized (serialFilterLock) {
+                return serialFilter;
+            }
+        }
+
+        /**
+         * Set the process-wide filter if it has not already been configured or set.
+         *
+         * @param filter the serialization filter to set as the process-wide filter; not null
+         * @throws SecurityException if there is security manager and the
+         *       {@code SerializablePermission("serialFilter")} is not granted
+         * @throws IllegalStateException if the filter has already been set {@code non-null}
+         */
+        public static void setSerialFilter(ObjectInputFilter filter) {
+            Objects.requireNonNull(filter, "filter");
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null) {
+                sm.checkPermission(ObjectStreamConstants.SERIAL_FILTER_PERMISSION);
+            }
+            synchronized (serialFilterLock) {
+                if (serialFilter != null) {
+                    throw new IllegalStateException("Serial filter can only be set once");
+                }
+                serialFilter = filter;
+            }
+        }
+
+        /**
+         * Returns an ObjectInputFilter from a string of patterns.
+         * <p>
+         * Patterns are separated by ";" (semicolon). Whitespace is significant and
+         * is considered part of the pattern.
+         * If a pattern includes an equals assignment, "{@code =}" it sets a limit.
+         * If a limit appears more than once the last value is used.
+         * <ul>
+         *     <li>maxdepth={@code value} - the maximum depth of a graph</li>
+         *     <li>maxrefs={@code value}  - the maximum number of internal references</li>
+         *     <li>maxbytes={@code value} - the maximum number of bytes in the input stream</li>
+         *     <li>maxarray={@code value} - the maximum array length allowed</li>
+         * </ul>
+         * <p>
+         * Other patterns match or reject class or package name
+         * as returned from {@link Class#getName() Class.getName()} and
+         * if an optional module name is present
+         * {@link java.lang.reflect.Module#getName() class.getModule().getName()}.
+         * Note that for arrays the element type is used in the pattern,
+         * not the array type.
+         * <ul>
+         * <li>If the pattern starts with "!", the class is rejected if the remaining pattern is matched;
+         *     otherwise the class is allowed if the pattern matches.
+         * <li>If the pattern contains "/", the non-empty prefix up to the "/" is the module name;
+         *     if the module name matches the module name of the class then
+         *     the remaining pattern is matched with the class name.
+         *     If there is no "/", the module name is not compared.
+         * <li>If the pattern ends with ".**" it matches any class in the package and all subpackages.
+         * <li>If the pattern ends with ".*" it matches any class in the package.
+         * <li>If the pattern ends with "*", it matches any class with the pattern as a prefix.
+         * <li>If the pattern is equal to the class name, it matches.
+         * <li>Otherwise, the pattern is not matched.
+         * </ul>
+         * <p>
+         * The resulting filter performs the limit checks and then
+         * tries to match the class, if any. If any of the limits are exceeded,
+         * the filter returns {@link Status#REJECTED Status.REJECTED}.
+         * If the class is an array type, the class to be matched is the element type.
+         * Arrays of any number of dimensions are treated the same as the element type.
+         * For example, a pattern of "{@code !example.Foo}",
+         * rejects creation of any instance or array of {@code example.Foo}.
+         * The first pattern that matches, working from left to right, determines
+         * the {@link Status#ALLOWED Status.ALLOWED}
+         * or {@link Status#REJECTED Status.REJECTED} result.
+         * If nothing matches, the result is {@link Status#UNDECIDED Status.UNDECIDED}.
+         *
+         * @param pattern the pattern string to parse; not null
+         * @return a filter to check a class being deserialized; may be null;
+         *          {@code null} if no patterns
+         * @throws IllegalArgumentException
+         *                if a limit is missing the name, or the long value
+         *                is not a number or is negative,
+         *                or the module name is missing if the pattern contains "/"
+         *                or if the package is missing for ".*" and ".**"
+         */
+        public static ObjectInputFilter createFilter(String pattern) {
+            Objects.requireNonNull(pattern, "pattern");
+            return Global.createFilter(pattern);
+        }
+
+        /**
+         * Implementation of ObjectInputFilter that performs the checks of
+         * the process-wide serialization filter. If configured, it will be
+         * used for all ObjectInputStreams that do not set their own filters.
+         *
+         */
+        final static class Global implements ObjectInputFilter {
+            /**
+             * The pattern used to create the filter.
+             */
+            private final String pattern;
+            /**
+             * The list of class filters.
+             */
+            private final List<Function<Class<?>, Status>> filters;
+            /**
+             * Maximum allowed bytes in the stream.
+             */
+            private long maxStreamBytes;
+            /**
+             * Maximum depth of the graph allowed.
+             */
+            private long maxDepth;
+            /**
+             * Maximum number of references in a graph.
+             */
+            private long maxReferences;
+            /**
+             * Maximum length of any array.
+             */
+            private long maxArrayLength;
+
+            /**
+             * Returns an ObjectInputFilter from a string of patterns.
+             *
+             * @param pattern the pattern string to parse
+             * @return a filter to check a class being deserialized; not null
+             * @throws IllegalArgumentException if the parameter is malformed
+             *                if the pattern is missing the name, the long value
+             *                is not a number or is negative.
+             */
+            static ObjectInputFilter createFilter(String pattern) {
+                Global filter = new Global(pattern);
+                return filter.isEmpty() ? null : filter;
+            }
+
+            /**
+             * Construct a new filter from the pattern String.
+             *
+             * @param pattern a pattern string of filters
+             * @throws IllegalArgumentException if the pattern is malformed
+             */
+            private Global(String pattern) {
+                this.pattern = pattern;
+
+                maxArrayLength = Long.MAX_VALUE; // Default values are unlimited
+                maxDepth = Long.MAX_VALUE;
+                maxReferences = Long.MAX_VALUE;
+                maxStreamBytes = Long.MAX_VALUE;
+
+                String[] patterns = pattern.split(";");
+                filters = new ArrayList<>(patterns.length);
+                for (int i = 0; i < patterns.length; i++) {
+                    String p = patterns[i];
+                    int nameLen = p.length();
+                    if (nameLen == 0) {
+                        continue;
+                    }
+                    if (parseLimit(p)) {
+                        // If the pattern contained a limit setting, i.e. type=value
+                        continue;
+                    }
+                    boolean negate = p.charAt(0) == '!';
+                    int poffset = negate ? 1 : 0;
+
+                    // isolate module name, if any
+                    int slash = p.indexOf('/', poffset);
+                    if (slash == poffset) {
+                        throw new IllegalArgumentException("module name is missing in: \"" + pattern + "\"");
+                    }
+                    final String moduleName = (slash >= 0) ? p.substring(poffset, slash) : null;
+                    poffset = (slash >= 0) ? slash + 1 : poffset;
+
+                    final Function<Class<?>, Status> patternFilter;
+                    if (p.endsWith("*")) {
+                        // Wildcard cases
+                        if (p.endsWith(".*")) {
+                            // Pattern is a package name with a wildcard
+                            final String pkg = p.substring(poffset, nameLen - 1);
+                            if (pkg.length() < 2) {
+                                throw new IllegalArgumentException("package missing in: \"" + pattern + "\"");
+                            }
+                            if (negate) {
+                                // A Function that fails if the class starts with the pattern, otherwise don't care
+                                patternFilter = c -> matchesPackage(c, pkg) ? Status.REJECTED : Status.UNDECIDED;
+                            } else {
+                                // A Function that succeeds if the class starts with the pattern, otherwise don't care
+                                patternFilter = c -> matchesPackage(c, pkg) ? Status.ALLOWED : Status.UNDECIDED;
+                            }
+                        } else if (p.endsWith(".**")) {
+                            // Pattern is a package prefix with a double wildcard
+                            final String pkgs = p.substring(poffset, nameLen - 2);
+                            if (pkgs.length() < 2) {
+                                throw new IllegalArgumentException("package missing in: \"" + pattern + "\"");
+                            }
+                            if (negate) {
+                                // A Function that fails if the class starts with the pattern, otherwise don't care
+                                patternFilter = c -> c.getName().startsWith(pkgs) ? Status.REJECTED : Status.UNDECIDED;
+                            } else {
+                                // A Function that succeeds if the class starts with the pattern, otherwise don't care
+                                patternFilter = c -> c.getName().startsWith(pkgs) ? Status.ALLOWED : Status.UNDECIDED;
+                            }
+                        } else {
+                            // Pattern is a classname (possibly empty) with a trailing wildcard
+                            final String className = p.substring(poffset, nameLen - 1);
+                            if (negate) {
+                                // A Function that fails if the class starts with the pattern, otherwise don't care
+                                patternFilter = c -> c.getName().startsWith(className) ? Status.REJECTED : Status.UNDECIDED;
+                            } else {
+                                // A Function that succeeds if the class starts with the pattern, otherwise don't care
+                                patternFilter = c -> c.getName().startsWith(className) ? Status.ALLOWED : Status.UNDECIDED;
+                            }
+                        }
+                    } else {
+                        final String name = p.substring(poffset);
+                        if (name.isEmpty()) {
+                            throw new IllegalArgumentException("class or package missing in: \"" + pattern + "\"");
+                        }
+                        // Pattern is a class name
+                        if (negate) {
+                            // A Function that fails if the class equals the pattern, otherwise don't care
+                            patternFilter = c -> c.getName().equals(name) ? Status.REJECTED : Status.UNDECIDED;
+                        } else {
+                            // A Function that succeeds if the class equals the pattern, otherwise don't care
+                            patternFilter = c -> c.getName().equals(name) ? Status.ALLOWED : Status.UNDECIDED;
+                        }
+                    }
+                    // If there is a moduleName, combine the module name check with the package/class check
+                    if (moduleName == null) {
+                        filters.add(patternFilter);
+                    } else {
+                        filters.add(c -> moduleName.equals(c.getModule().getName()) ? patternFilter.apply(c) : Status.UNDECIDED);
+                    }
+                }
+            }
+
+            /**
+             * Returns if this filter has any checks.
+             * @return {@code true} if the filter has any checks, {@code false} otherwise
+             */
+            private boolean isEmpty() {
+                return filters.isEmpty() &&
+                        maxArrayLength == Long.MAX_VALUE &&
+                        maxDepth == Long.MAX_VALUE &&
+                        maxReferences == Long.MAX_VALUE &&
+                        maxStreamBytes == Long.MAX_VALUE;
+            }
+
+            /**
+             * Parse out a limit for one of maxarray, maxdepth, maxbytes, maxreferences.
+             *
+             * @param pattern a string with a type name, '=' and a value
+             * @return {@code true} if a limit was parsed, else {@code false}
+             * @throws IllegalArgumentException if the pattern is missing
+             *                the name, the Long value is not a number or is negative.
+             */
+            private boolean parseLimit(String pattern) {
+                int eqNdx = pattern.indexOf('=');
+                if (eqNdx < 0) {
+                    // not a limit pattern
+                    return false;
+                }
+                String valueString = pattern.substring(eqNdx + 1);
+                if (pattern.startsWith("maxdepth=")) {
+                    maxDepth = parseValue(valueString);
+                } else if (pattern.startsWith("maxarray=")) {
+                    maxArrayLength = parseValue(valueString);
+                } else if (pattern.startsWith("maxrefs=")) {
+                    maxReferences = parseValue(valueString);
+                } else if (pattern.startsWith("maxbytes=")) {
+                    maxStreamBytes = parseValue(valueString);
+                } else {
+                    throw new IllegalArgumentException("unknown limit: " + pattern.substring(0, eqNdx));
+                }
+                return true;
+            }
+
+            /**
+             * Parse the value of a limit and check that it is non-negative.
+             * @param string inputstring
+             * @return the parsed value
+             * @throws IllegalArgumentException if parsing the value fails or the value is negative
+             */
+            private static long parseValue(String string) throws IllegalArgumentException {
+                // Parse a Long from after the '=' to the end
+                long value = Long.parseLong(string);
+                if (value < 0) {
+                    throw new IllegalArgumentException("negative limit: " + string);
+                }
+                return value;
+            }
+
+            /**
+             * {@inheritDoc}
+             */
+            @Override
+            public Status checkInput(FilterInfo filterInfo) {
+                if (filterInfo.references() < 0
+                        || filterInfo.depth() < 0
+                        || filterInfo.streamBytes() < 0
+                        || filterInfo.references() > maxReferences
+                        || filterInfo.depth() > maxDepth
+                        || filterInfo.streamBytes() > maxStreamBytes) {
+                    return Status.REJECTED;
+                }
+
+                Class<?> clazz = filterInfo.serialClass();
+                if (clazz != null) {
+                    if (clazz.isArray()) {
+                        if (filterInfo.arrayLength() >= 0 && filterInfo.arrayLength() > maxArrayLength) {
+                            // array length is too big
+                            return Status.REJECTED;
+                        }
+                        do {
+                            // Arrays are decided based on the component type
+                            clazz = clazz.getComponentType();
+                        } while (clazz.isArray());
+                    }
+
+                    if (clazz.isPrimitive())  {
+                        // Primitive types are undecided; let someone else decide
+                        return Status.UNDECIDED;
+                    } else {
+                        // Find any filter that allowed or rejected the class
+                        final Class<?> cl = clazz;
+                        Optional<Status> status = filters.stream()
+                                .map(f -> f.apply(cl))
+                                .filter(p -> p != Status.UNDECIDED)
+                                .findFirst();
+                        return status.orElse(Status.UNDECIDED);
+                    }
+                }
+                return Status.UNDECIDED;
+            }
+
+            /**
+             * Returns {@code true} if the class is in the package.
+             *
+             * @param c   a class
+             * @param pkg a package name (including the trailing ".")
+             * @return {@code true} if the class is in the package,
+             * otherwise {@code false}
+             */
+            private static boolean matchesPackage(Class<?> c, String pkg) {
+                String n = c.getName();
+                return n.startsWith(pkg) && n.lastIndexOf('.') == pkg.length() - 1;
+            }
+
+            /**
+             * Returns the pattern used to create this filter.
+             * @return the pattern used to create this filter
+             */
+            @Override
+            public String toString() {
+                return pattern;
+            }
+        }
+    }
+}
--- a/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java	Wed Oct 05 06:28:22 2016 -0700
@@ -26,6 +26,7 @@
 package java.io;
 
 import java.io.ObjectStreamClass.WeakClassKey;
+import java.lang.System.Logger;
 import java.lang.ref.ReferenceQueue;
 import java.lang.reflect.Array;
 import java.lang.reflect.Modifier;
@@ -37,10 +38,12 @@
 import java.security.PrivilegedExceptionAction;
 import java.util.Arrays;
 import java.util.Map;
+import java.util.Objects;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+
 import static java.io.ObjectStreamClass.processQueue;
-import jdk.internal.misc.JavaObjectInputStreamAccess;
+
 import jdk.internal.misc.ObjectStreamClassValidator;
 import jdk.internal.misc.SharedSecrets;
 import jdk.internal.misc.Unsafe;
@@ -172,6 +175,16 @@
  * protected) or that there are get and set methods that can be used to restore
  * the state.
  *
+ * <p>The contents of the stream can be filtered during deserialization.
+ * If a {@linkplain #setObjectInputFilter(ObjectInputFilter) filter is set}
+ * on an ObjectInputStream, the {@link ObjectInputFilter} can check that
+ * the classes, array lengths, number of references in the stream, depth, and
+ * number of bytes consumed from the input stream are allowed and
+ * if not, can terminate deserialization.
+ * A {@linkplain ObjectInputFilter.Config#setSerialFilter(ObjectInputFilter) process-wide filter}
+ * can be configured that is applied to each {@code ObjectInputStream} unless replaced
+ * using {@link #setObjectInputFilter(ObjectInputFilter) setObjectInputFilter}.
+ *
  * <p>Any exception that occurs while deserializing an object will be caught by
  * the ObjectInputStream and abort the reading process.
  *
@@ -240,12 +253,32 @@
             new ReferenceQueue<>();
     }
 
+    /*
+     * Separate class to defer initialization of logging until needed.
+     */
+    private static class Logging {
+        /*
+         * Logger for ObjectInputFilter results.
+         * Setup the filter logger if it is set to DEBUG or TRACE.
+         * (Assuming it will not change).
+         */
+        static final System.Logger filterLogger;
+
+        static {
+            Logger filterLog = System.getLogger("java.io.serialization");
+            filterLogger = (filterLog.isLoggable(Logger.Level.DEBUG)
+                    || filterLog.isLoggable(Logger.Level.TRACE)) ? filterLog : null;
+        }
+    }
+
     /** filter stream for handling block data conversion */
     private final BlockDataInputStream bin;
     /** validation callback list */
     private final ValidationList vlist;
     /** recursion depth */
-    private int depth;
+    private long depth;
+    /** Total number of references to any type of object, class, enum, proxy, etc. */
+    private long totalObjectRefs;
     /** whether stream is closed */
     private boolean closed;
 
@@ -269,11 +302,20 @@
     private SerialCallbackContext curContext;
 
     /**
+     * Filter of class descriptors and classes read from the stream;
+     * may be null.
+     */
+    private ObjectInputFilter serialFilter;
+
+    /**
      * Creates an ObjectInputStream that reads from the specified InputStream.
      * A serialization stream header is read from the stream and verified.
      * This constructor will block until the corresponding ObjectOutputStream
      * has written and flushed the header.
      *
+     * <p>The serialization filter is initialized to the value of
+     * {@linkplain ObjectInputFilter.Config#getSerialFilter() the process-wide filter}.
+     *
      * <p>If a security manager is installed, this constructor will check for
      * the "enableSubclassImplementation" SerializablePermission when invoked
      * directly or indirectly by the constructor of a subclass which overrides
@@ -295,6 +337,7 @@
         bin = new BlockDataInputStream(in);
         handles = new HandleTable(10);
         vlist = new ValidationList();
+        serialFilter = ObjectInputFilter.Config.getSerialFilter();
         enableOverride = false;
         readStreamHeader();
         bin.setBlockDataMode(true);
@@ -305,6 +348,9 @@
      * ObjectInputStream to not have to allocate private data just used by this
      * implementation of ObjectInputStream.
      *
+     * <p>The serialization filter is initialized to the value of
+     * {@linkplain ObjectInputFilter.Config#getSerialFilter() the process-wide filter}.
+     *
      * <p>If there is a security manager installed, this method first calls the
      * security manager's <code>checkPermission</code> method with the
      * <code>SerializablePermission("enableSubclassImplementation")</code>
@@ -325,6 +371,7 @@
         bin = null;
         handles = null;
         vlist = null;
+        serialFilter = ObjectInputFilter.Config.getSerialFilter();
         enableOverride = true;
     }
 
@@ -332,7 +379,7 @@
      * Read an object from the ObjectInputStream.  The class of the object, the
      * signature of the class, and the values of the non-transient and
      * non-static fields of the class and all of its supertypes are read.
-     * Default deserializing for a class can be overriden using the writeObject
+     * Default deserializing for a class can be overridden using the writeObject
      * and readObject methods.  Objects referenced by this object are read
      * transitively so that a complete equivalent graph of objects is
      * reconstructed by readObject.
@@ -343,6 +390,10 @@
      * priorities. The callbacks are registered by objects (in the readObject
      * special methods) as they are individually restored.
      *
+     * <p>The serialization filter, when not {@code null}, is invoked for
+     * each object (regular or class) read to reconstruct the root object.
+     * See {@link #setObjectInputFilter(ObjectInputFilter) setObjectInputFilter} for details.
+     *
      * <p>Exceptions are thrown for problems with the InputStream and for
      * classes that should not be deserialized.  All exceptions are fatal to
      * the InputStream and leave it in an indeterminate state; it is up to the
@@ -438,6 +489,10 @@
      * invocation of readObject or readUnshared on the ObjectInputStream,
      * even if the underlying data stream has been manipulated.
      *
+     * <p>The serialization filter, when not {@code null}, is invoked for
+     * each object (regular or class) read to reconstruct the root object.
+     * See {@link #setObjectInputFilter(ObjectInputFilter) setObjectInputFilter} for details.
+     *
      * <p>ObjectInputStream subclasses which override this method can only be
      * constructed in security contexts possessing the
      * "enableSubclassImplementation" SerializablePermission; any attempt to
@@ -1094,6 +1149,134 @@
     }
 
     /**
+     * Returns the serialization filter for this stream.
+     * The serialization filter is the most recent filter set in
+     * {@link #setObjectInputFilter setObjectInputFilter} or
+     * the initial process-wide filter from
+     * {@link ObjectInputFilter.Config#getSerialFilter() ObjectInputFilter.Config.getSerialFilter}.
+     *
+     * @return the serialization filter for the stream; may be null
+     * @since 9
+     */
+    public final ObjectInputFilter getObjectInputFilter() {
+        return serialFilter;
+    }
+
+    /**
+     * Set the serialization filter for the stream.
+     * The filter's {@link ObjectInputFilter#checkInput checkInput} method is called
+     * for each class and reference in the stream.
+     * The filter can check any or all of the class, the array length, the number
+     * of references, the depth of the graph, and the size of the input stream.
+     * <p>
+     * If the filter returns {@link ObjectInputFilter.Status#REJECTED Status.REJECTED},
+     * {@code null} or throws a {@link RuntimeException},
+     * the active {@code readObject} or {@code readUnshared}
+     * throws {@link InvalidClassException}, otherwise deserialization
+     * continues uninterrupted.
+     * <p>
+     * The serialization filter is initialized to the value of
+     * {@link ObjectInputFilter.Config#getSerialFilter() ObjectInputFilter.Config.getSerialFilter}
+     * when the {@code  ObjectInputStream} is constructed and can be set
+     * to a custom filter only once.
+     *
+     * @implSpec
+     * The filter, when not {@code null}, is invoked during {@link #readObject readObject}
+     * and {@link #readUnshared readUnshared} for each object
+     * (regular or class) in the stream including the following:
+     * <ul>
+     *     <li>each object reference previously deserialized from the stream
+     *     (class is {@code null}, arrayLength is -1),
+     *     <li>each regular class (class is not {@code null}, arrayLength is -1),
+     *     <li>each interface of a dynamic proxy and the dynamic proxy class itself
+     *     (class is not {@code null}, arrayLength is -1),
+     *     <li>each array is filtered using the array type and length of the array
+     *     (class is the array type, arrayLength is the requested length),
+     *     <li>each object replaced by its class' {@code readResolve} method
+     *         is filtered using the replacement object's class, if not {@code null},
+     *         and if it is an array, the arrayLength, otherwise -1,
+     *     <li>and each object replaced by {@link #resolveObject resolveObject}
+     *         is filtered using the replacement object's class, if not {@code null},
+     *         and if it is an array, the arrayLength, otherwise -1.
+     * </ul>
+     *
+     * When the {@link ObjectInputFilter#checkInput checkInput} method is invoked
+     * it is given access to the current class, the array length,
+     * the current number of references already read from the stream,
+     * the depth of nested calls to {@link #readObject readObject} or
+     * {@link #readUnshared readUnshared},
+     * and the implementation dependent number of bytes consumed from the input stream.
+     * <p>
+     * Each call to {@link #readObject readObject} or
+     * {@link #readUnshared readUnshared} increases the depth by 1
+     * before reading an object and decreases by 1 before returning
+     * normally or exceptionally.
+     * The depth starts at {@code 1} and increases for each nested object and
+     * decrements when each nested call returns.
+     * The count of references in the stream starts at {@code 1} and
+     * is increased before reading an object.
+     *
+     * @param filter the filter, may be null
+     * @throws SecurityException if there is security manager and the
+     *       {@code SerializablePermission("serialFilter")} is not granted
+     * @throws IllegalStateException if the {@linkplain #getObjectInputFilter() current filter}
+     *       is not {@code null} and is not the process-wide filter
+     * @since 9
+     */
+    public final void setObjectInputFilter(ObjectInputFilter filter) {
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(ObjectStreamConstants.SERIAL_FILTER_PERMISSION);
+        }
+        // Allow replacement of the process-wide filter if not already set
+        if (serialFilter != null &&
+                serialFilter != ObjectInputFilter.Config.getSerialFilter()) {
+            throw new IllegalStateException("filter can not be set more than once");
+        }
+        this.serialFilter = filter;
+    }
+
+    /**
+     * Invoke the serialization filter if non-null.
+     * If the filter rejects or an exception is thrown, throws InvalidClassException.
+     *
+     * @param clazz the class; may be null
+     * @param arrayLength the array length requested; use {@code -1} if not creating an array
+     * @throws InvalidClassException if it rejected by the filter or
+     *        a {@link RuntimeException} is thrown
+     */
+    private void filterCheck(Class<?> clazz, int arrayLength)
+            throws InvalidClassException {
+        if (serialFilter != null) {
+            RuntimeException ex = null;
+            ObjectInputFilter.Status status;
+            try {
+                status = serialFilter.checkInput(new FilterValues(clazz, arrayLength,
+                        totalObjectRefs, depth, bin.getBytesRead()));
+            } catch (RuntimeException e) {
+                // Preventive interception of an exception to log
+                status = ObjectInputFilter.Status.REJECTED;
+                ex = e;
+            }
+            if (Logging.filterLogger != null) {
+                // Debug logging of filter checks that fail; Tracing for those that succeed
+                Logging.filterLogger.log(status == null || status == ObjectInputFilter.Status.REJECTED
+                                ? Logger.Level.DEBUG
+                                : Logger.Level.TRACE,
+                        "ObjectInputFilter {0}: {1}, array length: {2}, nRefs: {3}, depth: {4}, bytes: {5}, ex: {6}",
+                        status, clazz, arrayLength, totalObjectRefs, depth, bin.getBytesRead(),
+                        Objects.toString(ex, "n/a"));
+            }
+            if (status == null ||
+                    status == ObjectInputFilter.Status.REJECTED) {
+                InvalidClassException ice = new InvalidClassException("filter status: " + status);
+                ice.initCause(ex);
+                throw ice;
+            }
+        }
+    }
+
+    /**
      * Provide access to the persistent fields read from the input stream.
      */
     public abstract static class GetField {
@@ -1280,7 +1463,7 @@
      */
     private static Boolean auditSubclass(Class<?> subcl) {
         return AccessController.doPrivileged(
-            new PrivilegedAction<>() {
+            new PrivilegedAction<Boolean>() {
                 public Boolean run() {
                     for (Class<?> cl = subcl;
                          cl != ObjectInputStream.class;
@@ -1340,6 +1523,7 @@
         }
 
         depth++;
+        totalObjectRefs++;
         try {
             switch (tc) {
                 case TC_NULL:
@@ -1416,6 +1600,15 @@
         }
         Object rep = resolveObject(obj);
         if (rep != obj) {
+            // The type of the original object has been filtered but resolveObject
+            // may have replaced it;  filter the replacement's type
+            if (rep != null) {
+                if (rep.getClass().isArray()) {
+                    filterCheck(rep.getClass(), Array.getLength(rep));
+                } else {
+                    filterCheck(rep.getClass(), -1);
+                }
+            }
             handles.setObject(passHandle, rep);
         }
         return rep;
@@ -1486,6 +1679,7 @@
             throw new InvalidObjectException(
                 "cannot read back reference to unshared object");
         }
+        filterCheck(null, -1);       // just a check for number of references, depth, no class
         return obj;
     }
 
@@ -1590,6 +1784,10 @@
                 ReflectUtil.checkProxyPackageAccess(
                         getClass().getClassLoader(),
                         cl.getInterfaces());
+                // Filter the interfaces
+                for (Class<?> clazz : cl.getInterfaces()) {
+                    filterCheck(clazz, -1);
+                }
             }
         } catch (ClassNotFoundException ex) {
             resolveEx = ex;
@@ -1598,6 +1796,9 @@
 
         desc.initProxy(cl, resolveEx, readClassDesc(false));
 
+        // Call filterCheck on the definition
+        filterCheck(desc.forClass(), -1);
+
         handles.finish(descHandle);
         passHandle = descHandle;
         return desc;
@@ -1645,8 +1846,12 @@
 
         desc.initNonProxy(readDesc, cl, resolveEx, readClassDesc(false));
 
+        // Call filterCheck on the definition
+        filterCheck(desc.forClass(), -1);
+
         handles.finish(descHandle);
         passHandle = descHandle;
+
         return desc;
     }
 
@@ -1687,6 +1892,8 @@
         ObjectStreamClass desc = readClassDesc(false);
         int len = bin.readInt();
 
+        filterCheck(desc.forClass(), len);
+
         Object array = null;
         Class<?> cl, ccl = null;
         if ((cl = desc.forClass()) != null) {
@@ -1835,6 +2042,14 @@
                 rep = cloneArray(rep);
             }
             if (rep != obj) {
+                // Filter the replacement object
+                if (rep != null) {
+                    if (rep.getClass().isArray()) {
+                        filterCheck(rep.getClass(), Array.getLength(rep));
+                    } else {
+                        filterCheck(rep.getClass(), -1);
+                    }
+                }
                 handles.setObject(passHandle, obj = rep);
             }
         }
@@ -2360,7 +2575,7 @@
             try {
                 while (list != null) {
                     AccessController.doPrivileged(
-                        new PrivilegedExceptionAction<>()
+                        new PrivilegedExceptionAction<Void>()
                     {
                         public Void run() throws InvalidObjectException {
                             list.obj.validateObject();
@@ -2384,6 +2599,51 @@
     }
 
     /**
+     * Hold a snapshot of values to be passed to an ObjectInputFilter.
+     */
+    static class FilterValues implements ObjectInputFilter.FilterInfo {
+        final Class<?> clazz;
+        final long arrayLength;
+        final long totalObjectRefs;
+        final long depth;
+        final long streamBytes;
+
+        public FilterValues(Class<?> clazz, long arrayLength, long totalObjectRefs,
+                            long depth, long streamBytes) {
+            this.clazz = clazz;
+            this.arrayLength = arrayLength;
+            this.totalObjectRefs = totalObjectRefs;
+            this.depth = depth;
+            this.streamBytes = streamBytes;
+        }
+
+        @Override
+        public Class<?> serialClass() {
+            return clazz;
+        }
+
+        @Override
+        public long arrayLength() {
+            return arrayLength;
+        }
+
+        @Override
+        public long references() {
+            return totalObjectRefs;
+        }
+
+        @Override
+        public long depth() {
+            return depth;
+        }
+
+        @Override
+        public long streamBytes() {
+            return streamBytes;
+        }
+    }
+
+    /**
      * Input stream supporting single-byte peek operations.
      */
     private static class PeekInputStream extends InputStream {
@@ -2392,6 +2652,8 @@
         private final InputStream in;
         /** peeked byte */
         private int peekb = -1;
+        /** total bytes read from the stream */
+        private long totalBytesRead = 0;
 
         /**
          * Creates new PeekInputStream on top of given underlying stream.
@@ -2405,7 +2667,12 @@
          * that it does not consume the read value.
          */
         int peek() throws IOException {
-            return (peekb >= 0) ? peekb : (peekb = in.read());
+            if (peekb >= 0) {
+                return peekb;
+            }
+            peekb = in.read();
+            totalBytesRead += peekb >= 0 ? 1 : 0;
+            return peekb;
         }
 
         public int read() throws IOException {
@@ -2414,21 +2681,27 @@
                 peekb = -1;
                 return v;
             } else {
-                return in.read();
+                int nbytes = in.read();
+                totalBytesRead += nbytes >= 0 ? 1 : 0;
+                return nbytes;
             }
         }
 
         public int read(byte[] b, int off, int len) throws IOException {
+            int nbytes;
             if (len == 0) {
                 return 0;
             } else if (peekb < 0) {
-                return in.read(b, off, len);
+                nbytes = in.read(b, off, len);
+                totalBytesRead += nbytes >= 0 ? nbytes : 0;
+                return nbytes;
             } else {
                 b[off++] = (byte) peekb;
                 len--;
                 peekb = -1;
-                int n = in.read(b, off, len);
-                return (n >= 0) ? (n + 1) : 1;
+                nbytes = in.read(b, off, len);
+                totalBytesRead += nbytes >= 0 ? nbytes : 0;
+                return (nbytes >= 0) ? (nbytes + 1) : 1;
             }
         }
 
@@ -2453,7 +2726,9 @@
                 skipped++;
                 n--;
             }
-            return skipped + in.skip(n);
+            n = skipped + in.skip(n);
+            totalBytesRead += n;
+            return n;
         }
 
         public int available() throws IOException {
@@ -2463,6 +2738,10 @@
         public void close() throws IOException {
             in.close();
         }
+
+        public long getBytesRead() {
+            return totalBytesRead;
+        }
     }
 
     private static final Unsafe UNSAFE = Unsafe.getUnsafe();
@@ -3346,6 +3625,14 @@
                     throw new UTFDataFormatException();
             }
         }
+
+        /**
+         * Returns the number of bytes read from the input stream.
+         * @return the number of bytes read from the input stream
+         */
+        long getBytesRead() {
+            return in.getBytesRead();
+        }
     }
 
     /**
--- a/jdk/src/java.base/share/classes/java/io/ObjectStreamConstants.java	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/io/ObjectStreamConstants.java	Wed Oct 05 06:28:22 2016 -0700
@@ -199,6 +199,16 @@
      */
     static final SerializablePermission SUBCLASS_IMPLEMENTATION_PERMISSION =
                     new SerializablePermission("enableSubclassImplementation");
+
+    /**
+     * Enable setting the process-wide serial filter.
+     *
+     * @see java.io.ObjectInputFilter.Config#setSerialFilter(ObjectInputFilter)
+     * @since 9
+     */
+    static final SerializablePermission SERIAL_FILTER_PERMISSION =
+            new SerializablePermission("serialFilter");
+
    /**
     * A Stream Protocol Version. <p>
     *
--- a/jdk/src/java.base/share/classes/java/io/SerializablePermission.java	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/io/SerializablePermission.java	Wed Oct 05 06:28:22 2016 -0700
@@ -40,7 +40,7 @@
  * The target name is the name of the Serializable permission (see below).
  *
  * <P>
- * The following table lists all the possible SerializablePermission target names,
+ * The following table lists the standard {@code SerializablePermission} target names,
  * and for each provides a description of what the permission allows
  * and a discussion of the risks of granting code the permission.
  *
@@ -73,6 +73,13 @@
  * malignant data.</td>
  * </tr>
  *
+ * <tr>
+ *   <td>serialFilter</td>
+ *   <td>Setting a filter for ObjectInputStreams.</td>
+ *   <td>Code could remove a configured filter and remove protections
+ *       already established.</td>
+ * </tr>
+ *
  * </table>
  *
  * @see java.security.BasicPermission
--- a/jdk/src/java.base/share/classes/java/lang/String.java	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/String.java	Wed Oct 05 06:28:22 2016 -0700
@@ -1516,11 +1516,12 @@
      * @return  a hash code value for this object.
      */
     public int hashCode() {
-        if (hash == 0 && value.length > 0) {
-            hash = isLatin1() ? StringLatin1.hashCode(value)
-                              : StringUTF16.hashCode(value);
+        int h = hash;
+        if (h == 0 && value.length > 0) {
+            hash = h = isLatin1() ? StringLatin1.hashCode(value)
+                                  : StringUTF16.hashCode(value);
         }
-        return hash;
+        return h;
     }
 
     /**
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Wed Oct 05 06:28:22 2016 -0700
@@ -1962,12 +1962,12 @@
      * This method is bound as the predicate in {@linkplain MethodHandles#countedLoop(MethodHandle, MethodHandle,
      * MethodHandle) counting loops}.
      *
+     * @param limit the upper bound of the parameter, statically bound at loop creation time.
      * @param counter the counter parameter, passed in during loop execution.
-     * @param limit the upper bound of the parameter, statically bound at loop creation time.
      *
      * @return whether the counter has reached the limit.
      */
-    static boolean countedLoopPredicate(int counter, int limit) {
+    static boolean countedLoopPredicate(int limit, int counter) {
         return counter < limit;
     }
 
@@ -1975,27 +1975,16 @@
      * This method is bound as the step function in {@linkplain MethodHandles#countedLoop(MethodHandle, MethodHandle,
      * MethodHandle) counting loops} to increment the counter.
      *
+     * @param limit the upper bound of the loop counter (ignored).
      * @param counter the loop counter.
      *
      * @return the loop counter incremented by 1.
      */
-    static int countedLoopStep(int counter, int limit) {
+    static int countedLoopStep(int limit, int counter) {
         return counter + 1;
     }
 
     /**
-     * This method is bound as a filter in {@linkplain MethodHandles#countedLoop(MethodHandle, MethodHandle, MethodHandle,
-     * MethodHandle) counting loops} to pass the correct counter value to the body.
-     *
-     * @param counter the loop counter.
-     *
-     * @return the loop counter decremented by 1.
-     */
-    static int decrementCounter(int counter) {
-        return counter - 1;
-    }
-
-    /**
      * This is bound to initialize the loop-local iterator in {@linkplain MethodHandles#iteratedLoop iterating loops}.
      *
      * @param it the {@link Iterable} over which the loop iterates.
@@ -2164,12 +2153,11 @@
             MH_arrayIdentity         =  5,
             MH_countedLoopPred       =  6,
             MH_countedLoopStep       =  7,
-            MH_iteratePred           =  8,
-            MH_initIterator          =  9,
+            MH_initIterator          =  8,
+            MH_iteratePred           =  9,
             MH_iterateNext           = 10,
-            MH_decrementCounter      = 11,
-            MH_Array_newInstance     = 12,
-            MH_LIMIT                 = 13;
+            MH_Array_newInstance     = 11,
+            MH_LIMIT                 = 12;
 
     static MethodHandle getConstantHandle(int idx) {
         MethodHandle handle = HANDLES[idx];
@@ -2220,18 +2208,15 @@
                 case MH_countedLoopStep:
                     return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "countedLoopStep",
                             MethodType.methodType(int.class, int.class, int.class));
-                case MH_iteratePred:
-                    return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "iteratePredicate",
-                            MethodType.methodType(boolean.class, Iterator.class));
                 case MH_initIterator:
                     return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "initIterator",
                             MethodType.methodType(Iterator.class, Iterable.class));
+                case MH_iteratePred:
+                    return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "iteratePredicate",
+                            MethodType.methodType(boolean.class, Iterator.class));
                 case MH_iterateNext:
                     return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "iterateNext",
                             MethodType.methodType(Object.class, Iterator.class));
-                case MH_decrementCounter:
-                    return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "decrementCounter",
-                            MethodType.methodType(int.class, int.class));
                 case MH_Array_newInstance:
                     return IMPL_LOOKUP.findStatic(Array.class, "newInstance",
                             MethodType.methodType(Object.class, Class.class, int.class));
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandles.java	Wed Oct 05 06:28:22 2016 -0700
@@ -44,8 +44,6 @@
 import java.lang.reflect.Modifier;
 import java.lang.reflect.ReflectPermission;
 import java.nio.ByteOrder;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.BitSet;
@@ -3114,7 +3112,7 @@
      * @see MethodHandles#explicitCastArguments
      * @since 9
      */
-    public static  MethodHandle zero(Class<?> type) {
+    public static MethodHandle zero(Class<?> type) {
         Objects.requireNonNull(type);
         return type.isPrimitive() ?  zero(Wrapper.forPrimitiveType(type), type) : zero(Wrapper.OBJECT, type);
     }
@@ -3403,7 +3401,8 @@
                 throw newIllegalArgumentException("illegal pos", pos, newTypes);
             }
             addTypes = addTypes.subList(pos, add);
-            add -= pos; assert(addTypes.size() == add);
+            add -= pos;
+            assert(addTypes.size() == add);
         }
         // Do not add types which already match the existing arguments.
         if (match > add || !oldTypes.equals(addTypes.subList(0, match))) {
@@ -3413,7 +3412,8 @@
             throw newIllegalArgumentException("argument lists do not match", oldTypes, newTypes);
         }
         addTypes = addTypes.subList(match, add);
-        add -= match; assert(addTypes.size() == add);
+        add -= match;
+        assert(addTypes.size() == add);
         // newTypes:     (   P*[pos], M*[match], A*[add] )
         // target: ( S*[skip],        M*[match]  )
         MethodHandle adapter = target;
@@ -3423,26 +3423,37 @@
         // adapter: (S*[skip],        M*[match], A*[add] )
         if (pos > 0) {
             adapter = dropArguments0(adapter, skip, newTypes.subList(0, pos));
-       }
+        }
         // adapter: (S*[skip], P*[pos], M*[match], A*[add] )
         return adapter;
     }
 
     /**
-     * Adapts a target method handle to match the given parameter type list, if necessary, by adding dummy arguments.
-     * Some leading parameters are first skipped; they will be left unchanged and are otherwise ignored.
-     * The remaining types in the target's parameter type list must be contained as a sub-list of the given type list,
-     * at the given position.
-     * Any non-matching parameter types (before or after the matching sub-list) are inserted in corresponding
-     * positions of the target method handle's parameters, as if by {@link #dropArguments}.
-     * (More precisely, elements in the new list before {@code pos} are inserted into the target list at {@code skip},
-     * while elements in the new list after the match beginning at {@code pos} are inserted at the end of the
-     * target list.)
-     * The target's return type will be unchanged.
+     * Adapts a target method handle to match the given parameter type list. If necessary, adds dummy arguments. Some
+     * leading parameters can be skipped before matching begins. The remaining types in the {@code target}'s parameter
+     * type list must be a sub-list of the {@code newTypes} type list at the starting position {@code pos}. The
+     * resulting handle will have the target handle's parameter type list, with any non-matching parameter types (before
+     * or after the matching sub-list) inserted in corresponding positions of the target's original parameters, as if by
+     * {@link #dropArguments(MethodHandle, int, Class[])}.
+     * <p>
+     * The resulting handle will have the same return type as the target handle.
+     * <p>
+     * In more formal terms, assume these two type lists:<ul>
+     * <li>The target handle has the parameter type list {@code S..., M...}, with as many types in {@code S} as
+     * indicated by {@code skip}. The {@code M} types are those that are supposed to match part of the given type list,
+     * {@code newTypes}.
+     * <li>The {@code newTypes} list contains types {@code P..., M..., A...}, with as many types in {@code P} as
+     * indicated by {@code pos}. The {@code M} types are precisely those that the {@code M} types in the target handle's
+     * parameter type list are supposed to match. The types in {@code A} are additional types found after the matching
+     * sub-list.
+     * </ul>
+     * Given these assumptions, the result of an invocation of {@code dropArgumentsToMatch} will have the parameter type
+     * list {@code S..., P..., M..., A...}, with the {@code P} and {@code A} types inserted as if by
+     * {@link #dropArguments(MethodHandle, int, Class[])}.
+     * <p>
      * @apiNote
-     * Two method handles whose argument lists are "effectively identical" (i.e., identical
-     * in a common prefix) may be mutually converted to a common type
-     * by two calls to {@code dropArgumentsToMatch}, as follows:
+     * Two method handles whose argument lists are "effectively identical" (i.e., identical in a common prefix) may be
+     * mutually converted to a common type by two calls to {@code dropArgumentsToMatch}, as follows:
      * <blockquote><pre>{@code
 import static java.lang.invoke.MethodHandles.*;
 import static java.lang.invoke.MethodType.*;
@@ -3461,14 +3472,15 @@
      * }</pre></blockquote>
      * @param target the method handle to adapt
      * @param skip number of targets parameters to disregard (they will be unchanged)
-     * @param newTypes the desired argument list of the method handle
+     * @param newTypes the list of types to match {@code target}'s parameter type list to
      * @param pos place in {@code newTypes} where the non-skipped target parameters must occur
      * @return a possibly adapted method handle
      * @throws NullPointerException if either argument is null
      * @throws IllegalArgumentException if any element of {@code newTypes} is {@code void.class},
      *         or if {@code skip} is negative or greater than the arity of the target,
      *         or if {@code pos} is negative or greater than the newTypes list size,
-     *         or if the non-skipped target parameter types match the new types at {@code pos}
+     *         or if {@code newTypes} does not contain the {@code target}'s non-skipped parameter types at position
+     *         {@code pos}.
      * @since 9
      */
     public static
@@ -3922,6 +3934,113 @@
         return foldArguments(target, 0, combiner);
     }
 
+    /**
+     * Adapts a target method handle by pre-processing some of its arguments, starting at a given position, and then
+     * calling the target with the result of the pre-processing, inserted into the original sequence of arguments just
+     * before the folded arguments.
+     * <p>
+     * This method is closely related to {@link #foldArguments(MethodHandle, MethodHandle)}, but allows to control the
+     * position in the parameter list at which folding takes place. The argument controlling this, {@code pos}, is a
+     * zero-based index. The aforementioned method {@link #foldArguments(MethodHandle, MethodHandle)} assumes position
+     * 0.
+     * <p>
+     * @apiNote Example:
+     * <blockquote><pre>{@code
+    import static java.lang.invoke.MethodHandles.*;
+    import static java.lang.invoke.MethodType.*;
+    ...
+    MethodHandle trace = publicLookup().findVirtual(java.io.PrintStream.class,
+    "println", methodType(void.class, String.class))
+    .bindTo(System.out);
+    MethodHandle cat = lookup().findVirtual(String.class,
+    "concat", methodType(String.class, String.class));
+    assertEquals("boojum", (String) cat.invokeExact("boo", "jum"));
+    MethodHandle catTrace = foldArguments(cat, 1, trace);
+    // also prints "jum":
+    assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
+     * }</pre></blockquote>
+     * <p>Here is pseudocode for the resulting adapter. In the code, {@code T}
+     * represents the result type of the {@code target} and resulting adapter.
+     * {@code V}/{@code v} represent the type and value of the parameter and argument
+     * of {@code target} that precedes the folding position; {@code V} also is
+     * the result type of the {@code combiner}. {@code A}/{@code a} denote the
+     * types and values of the {@code N} parameters and arguments at the folding
+     * position. {@code Z}/{@code z} and {@code B}/{@code b} represent the types
+     * and values of the {@code target} parameters and arguments that precede and
+     * follow the folded parameters and arguments starting at {@code pos},
+     * respectively.
+     * <blockquote><pre>{@code
+     * // there are N arguments in A...
+     * T target(Z..., V, A[N]..., B...);
+     * V combiner(A...);
+     * T adapter(Z... z, A... a, B... b) {
+     *   V v = combiner(a...);
+     *   return target(z..., v, a..., b...);
+     * }
+     * // and if the combiner has a void return:
+     * T target2(Z..., A[N]..., B...);
+     * void combiner2(A...);
+     * T adapter2(Z... z, A... a, B... b) {
+     *   combiner2(a...);
+     *   return target2(z..., a..., b...);
+     * }
+     * }</pre></blockquote>
+     * <p>
+     * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector
+     * variable-arity method handle}, even if the original target method handle was.
+     *
+     * @param target the method handle to invoke after arguments are combined
+     * @param pos the position at which to start folding and at which to insert the folding result; if this is {@code
+     *            0}, the effect is the same as for {@link #foldArguments(MethodHandle, MethodHandle)}.
+     * @param combiner method handle to call initially on the incoming arguments
+     * @return method handle which incorporates the specified argument folding logic
+     * @throws NullPointerException if either argument is null
+     * @throws IllegalArgumentException if either of the following two conditions holds:
+     *          (1) {@code combiner}'s return type is non-{@code void} and not the same as the argument type at position
+     *              {@code pos} of the target signature;
+     *          (2) the {@code N} argument types at position {@code pos} of the target signature (skipping one matching
+     *              the {@code combiner}'s return type) are not identical with the argument types of {@code combiner}.
+     *
+     * @see #foldArguments(MethodHandle, MethodHandle)
+     * @since 9
+     */
+    public static MethodHandle foldArguments(MethodHandle target, int pos, MethodHandle combiner) {
+        MethodType targetType = target.type();
+        MethodType combinerType = combiner.type();
+        Class<?> rtype = foldArgumentChecks(pos, targetType, combinerType);
+        BoundMethodHandle result = target.rebind();
+        boolean dropResult = rtype == void.class;
+        LambdaForm lform = result.editor().foldArgumentsForm(1 + pos, dropResult, combinerType.basicType());
+        MethodType newType = targetType;
+        if (!dropResult) {
+            newType = newType.dropParameterTypes(pos, pos + 1);
+        }
+        result = result.copyWithExtendL(newType, lform, combiner);
+        return result;
+    }
+
+    /**
+     * As {@see foldArguments(MethodHandle, int, MethodHandle)}, but with the
+     * added capability of selecting the arguments from the targets parameters
+     * to call the combiner with. This allows us to avoid some simple cases of
+     * permutations and padding the combiner with dropArguments to select the
+     * right argument, which may ultimately produce fewer intermediaries.
+     */
+    static MethodHandle foldArguments(MethodHandle target, int pos, MethodHandle combiner, int ... argPositions) {
+        MethodType targetType = target.type();
+        MethodType combinerType = combiner.type();
+        Class<?> rtype = foldArgumentChecks(pos, targetType, combinerType, argPositions);
+        BoundMethodHandle result = target.rebind();
+        boolean dropResult = rtype == void.class;
+        LambdaForm lform = result.editor().foldArgumentsForm(1 + pos, dropResult, combinerType.basicType(), argPositions);
+        MethodType newType = targetType;
+        if (!dropResult) {
+            newType = newType.dropParameterTypes(pos, pos + 1);
+        }
+        result = result.copyWithExtendL(newType, lform, combiner);
+        return result;
+    }
+
     private static Class<?> foldArgumentChecks(int foldPos, MethodType targetType, MethodType combinerType) {
         int foldArgs   = combinerType.parameterCount();
         Class<?> rtype = combinerType.returnType();
@@ -4125,32 +4244,69 @@
      * iteration. Upon termination of the loop due to one of the predicates, a corresponding finalizer is run and
      * delivers the loop's result, which is the return value of the resulting handle.
      * <p>
-     * Intuitively, every loop is formed by one or more "clauses", each specifying a local iteration value and/or a loop
+     * Intuitively, every loop is formed by one or more "clauses", each specifying a local <em>iteration variable</em> and/or a loop
      * exit. Each iteration of the loop executes each clause in order. A clause can optionally update its iteration
      * variable; it can also optionally perform a test and conditional loop exit. In order to express this logic in
-     * terms of method handles, each clause will determine four actions:<ul>
-     * <li>Before the loop executes, the initialization of an iteration variable or loop invariant local.
-     * <li>When a clause executes, an update step for the iteration variable.
-     * <li>When a clause executes, a predicate execution to test for loop exit.
-     * <li>If a clause causes a loop exit, a finalizer execution to compute the loop's return value.
+     * terms of method handles, each clause will specify up to four independent actions:<ul>
+     * <li><em>init:</em> Before the loop executes, the initialization of an iteration variable {@code v} of type {@code V}.
+     * <li><em>step:</em> When a clause executes, an update step for the iteration variable {@code v}.
+     * <li><em>pred:</em> When a clause executes, a predicate execution to test for loop exit.
+     * <li><em>fini:</em> If a clause causes a loop exit, a finalizer execution to compute the loop's return value.
      * </ul>
+     * The full sequence of all iteration variable types, in clause order, will be notated as {@code (V...)}.
+     * The values themselves will be {@code (v...)}.  When we speak of "parameter lists", we will usually
+     * be referring to types, but in some contexts (describing execution) the lists will be of actual values.
      * <p>
      * Some of these clause parts may be omitted according to certain rules, and useful default behavior is provided in
      * this case. See below for a detailed description.
      * <p>
-     * Each clause function, with the exception of clause initializers, is able to observe the entire loop state,
-     * because it will be passed <em>all</em> current iteration variable values, as well as all incoming loop
-     * parameters. Most clause functions will not need all of this information, but they will be formally connected as
-     * if by {@link #dropArguments}.
+     * <em>Parameters optional everywhere:</em>
+     * Each clause function is allowed but not required to accept a parameter for each iteration variable {@code v}.
+     * As an exception, the init functions cannot take any {@code v} parameters,
+     * because those values are not yet computed when the init functions are executed.
+     * Any clause function may neglect to take any trailing subsequence of parameters it is entitled to take.
+     * In fact, any clause function may take no arguments at all.
      * <p>
+     * <em>Loop parameters:</em>
+     * A clause function may take all the iteration variable values it is entitled to, in which case
+     * it may also take more trailing parameters. Such extra values are called <em>loop parameters</em>,
+     * with their types and values notated as {@code (A...)} and {@code (a...)}.
+     * These become the parameters of the resulting loop handle, to be supplied whenever the loop is executed.
+     * (Since init functions do not accept iteration variables {@code v}, any parameter to an
+     * init function is automatically a loop parameter {@code a}.)
+     * As with iteration variables, clause functions are allowed but not required to accept loop parameters.
+     * These loop parameters act as loop-invariant values visible across the whole loop.
+     * <p>
+     * <em>Parameters visible everywhere:</em>
+     * Each non-init clause function is permitted to observe the entire loop state, because it can be passed the full
+     * list {@code (v... a...)} of current iteration variable values and incoming loop parameters.
+     * The init functions can observe initial pre-loop state, in the form {@code (a...)}.
+     * Most clause functions will not need all of this information, but they will be formally connected to it
+     * as if by {@link #dropArguments}.
+     * <a name="astar"></a>
+     * More specifically, we shall use the notation {@code (V*)} to express an arbitrary prefix of a full
+     * sequence {@code (V...)} (and likewise for {@code (v*)}, {@code (A*)}, {@code (a*)}).
+     * In that notation, the general form of an init function parameter list
+     * is {@code (A*)}, and the general form of a non-init function parameter list is {@code (V*)} or {@code (V... A*)}.
+     * <p>
+     * <em>Checking clause structure:</em>
      * Given a set of clauses, there is a number of checks and adjustments performed to connect all the parts of the
      * loop. They are spelled out in detail in the steps below. In these steps, every occurrence of the word "must"
-     * corresponds to a place where {@link IllegalArgumentException} may be thrown if the required constraint is not met
-     * by the inputs to the loop combinator. The term "effectively identical", applied to parameter type lists, means
-     * that they must be identical, or else one list must be a proper prefix of the other.
+     * corresponds to a place where {@link IllegalArgumentException} will be thrown if the required constraint is not
+     * met by the inputs to the loop combinator.
+     * <p>
+     * <em>Effectively identical sequences:</em>
+     * <a name="effid"></a>
+     * A parameter list {@code A} is defined to be <em>effectively identical</em> to another parameter list {@code B}
+     * if {@code A} and {@code B} are identical, or if {@code A} is shorter and is identical with a proper prefix of {@code B}.
+     * When speaking of an unordered set of parameter lists, we say they the set is "effectively identical"
+     * as a whole if the set contains a longest list, and all members of the set are effectively identical to
+     * that longest list.
+     * For example, any set of type sequences of the form {@code (V*)} is effectively identical,
+     * and the same is true if more sequences of the form {@code (V... A*)} are added.
      * <p>
      * <em>Step 0: Determine clause structure.</em><ol type="a">
-     * <li>The clause array (of type {@code MethodHandle[][]} must be non-{@code null} and contain at least one element.
+     * <li>The clause array (of type {@code MethodHandle[][]}) must be non-{@code null} and contain at least one element.
      * <li>The clause array may not contain {@code null}s or sub-arrays longer than four elements.
      * <li>Clauses shorter than four elements are treated as if they were padded by {@code null} elements to length
      * four. Padding takes place by appending elements to the array.
@@ -4158,30 +4314,35 @@
      * <li>Each clause is treated as a four-tuple of functions, called "init", "step", "pred", and "fini".
      * </ol>
      * <p>
-     * <em>Step 1A: Determine iteration variables.</em><ol type="a">
-     * <li>Examine init and step function return types, pairwise, to determine each clause's iteration variable type.
-     * <li>If both functions are omitted, use {@code void}; else if one is omitted, use the other's return type; else
-     * use the common return type (they must be identical).
+     * <em>Step 1A: Determine iteration variable types {@code (V...)}.</em><ol type="a">
+     * <li>The iteration variable type for each clause is determined using the clause's init and step return types.
+     * <li>If both functions are omitted, there is no iteration variable for the corresponding clause ({@code void} is
+     * used as the type to indicate that). If one of them is omitted, the other's return type defines the clause's
+     * iteration variable type. If both are given, the common return type (they must be identical) defines the clause's
+     * iteration variable type.
      * <li>Form the list of return types (in clause order), omitting all occurrences of {@code void}.
-     * <li>This list of types is called the "common prefix".
+     * <li>This list of types is called the "iteration variable types" ({@code (V...)}).
      * </ol>
      * <p>
-     * <em>Step 1B: Determine loop parameters.</em><ul>
-     * <li><b>If at least one init function is given,</b><ol type="a">
-     *   <li>Examine init function parameter lists.
-     *   <li>Omitted init functions are deemed to have {@code null} parameter lists.
-     *   <li>All init function parameter lists must be effectively identical.
-     *   <li>The longest parameter list (which is necessarily unique) is called the "common suffix".
-     * </ol>
-     * <li><b>If no init function is given,</b><ol type="a">
-     *   <li>Examine the suffixes of the step, pred, and fini parameter lists, after removing the "common prefix".
-     *   <li>The longest of these suffixes is taken as the "common suffix".
-     * </ol></ul>
+     * <em>Step 1B: Determine loop parameters {@code (A...)}.</em><ul>
+     * <li>Examine and collect init function parameter lists (which are of the form {@code (A*)}).
+     * <li>Examine and collect the suffixes of the step, pred, and fini parameter lists, after removing the iteration variable types.
+     * (They must have the form {@code (V... A*)}; collect the {@code (A*)} parts only.)
+     * <li>Do not collect suffixes from step, pred, and fini parameter lists that do not begin with all the iteration variable types.
+     * (These types will checked in step 2, along with all the clause function types.)
+     * <li>Omitted clause functions are ignored.  (Equivalently, they are deemed to have empty parameter lists.)
+     * <li>All of the collected parameter lists must be effectively identical.
+     * <li>The longest parameter list (which is necessarily unique) is called the "external parameter list" ({@code (A...)}).
+     * <li>If there is no such parameter list, the external parameter list is taken to be the empty sequence.
+     * <li>The combined list consisting of iteration variable types followed by the external parameter types is called
+     * the "internal parameter list".
+     * </ul>
      * <p>
      * <em>Step 1C: Determine loop return type.</em><ol type="a">
      * <li>Examine fini function return types, disregarding omitted fini functions.
-     * <li>If there are no fini functions, use {@code void} as the loop return type.
-     * <li>Otherwise, use the common return type of the fini functions; they must all be identical.
+     * <li>If there are no fini functions, the loop return type is {@code void}.
+     * <li>Otherwise, the common return type {@code R} of the fini functions (their return types must be identical) defines the loop return
+     * type.
      * </ol>
      * <p>
      * <em>Step 1D: Check other types.</em><ol type="a">
@@ -4190,69 +4351,107 @@
      * </ol>
      * <p>
      * <em>Step 2: Determine parameter lists.</em><ol type="a">
-     * <li>The parameter list for the resulting loop handle will be the "common suffix".
-     * <li>The parameter list for init functions will be adjusted to the "common suffix". (Note that their parameter
-     * lists are already effectively identical to the common suffix.)
-     * <li>The parameter list for non-init (step, pred, and fini) functions will be adjusted to the common prefix
-     * followed by the common suffix, called the "common parameter sequence".
-     * <li>Every non-init, non-omitted function parameter list must be effectively identical to the common parameter
-     * sequence.
+     * <li>The parameter list for the resulting loop handle will be the external parameter list {@code (A...)}.
+     * <li>The parameter list for init functions will be adjusted to the external parameter list.
+     * (Note that their parameter lists are already effectively identical to this list.)
+     * <li>The parameter list for every non-omitted, non-init (step, pred, and fini) function must be
+     * effectively identical to the internal parameter list {@code (V... A...)}.
      * </ol>
      * <p>
      * <em>Step 3: Fill in omitted functions.</em><ol type="a">
-     * <li>If an init function is omitted, use a {@linkplain #constant constant function} of the appropriate
-     * {@code null}/zero/{@code false}/{@code void} type. (For this purpose, a constant {@code void} is simply a
-     * function which does nothing and returns {@code void}; it can be obtained from another constant function by
-     * {@linkplain MethodHandle#asType type conversion}.)
+     * <li>If an init function is omitted, use a {@linkplain #empty default value} for the clause's iteration variable
+     * type.
      * <li>If a step function is omitted, use an {@linkplain #identity identity function} of the clause's iteration
      * variable type; insert dropped argument parameters before the identity function parameter for the non-{@code void}
      * iteration variables of preceding clauses. (This will turn the loop variable into a local loop invariant.)
-     * <li>If a pred function is omitted, the corresponding fini function must also be omitted.
      * <li>If a pred function is omitted, use a constant {@code true} function. (This will keep the loop going, as far
-     * as this clause is concerned.)
-     * <li>If a fini function is omitted, use a constant {@code null}/zero/{@code false}/{@code void} function of the
+     * as this clause is concerned.  Note that in such cases the corresponding fini function is unreachable.)
+     * <li>If a fini function is omitted, use a {@linkplain #empty default value} for the
      * loop return type.
      * </ol>
      * <p>
      * <em>Step 4: Fill in missing parameter types.</em><ol type="a">
-     * <li>At this point, every init function parameter list is effectively identical to the common suffix, but some
-     * lists may be shorter. For every init function with a short parameter list, pad out the end of the list by
-     * {@linkplain #dropArguments dropping arguments}.
-     * <li>At this point, every non-init function parameter list is effectively identical to the common parameter
-     * sequence, but some lists may be shorter. For every non-init function with a short parameter list, pad out the end
-     * of the list by {@linkplain #dropArguments dropping arguments}.
+     * <li>At this point, every init function parameter list is effectively identical to the external parameter list {@code (A...)},
+     * but some lists may be shorter. For every init function with a short parameter list, pad out the end of the list.
+     * <li>At this point, every non-init function parameter list is effectively identical to the internal parameter
+     * list {@code (V... A...)}, but some lists may be shorter. For every non-init function with a short parameter list,
+     * pad out the end of the list.
+     * <li>Argument lists are padded out by {@linkplain #dropArgumentsToMatch dropping unused trailing arguments}.
      * </ol>
      * <p>
      * <em>Final observations.</em><ol type="a">
      * <li>After these steps, all clauses have been adjusted by supplying omitted functions and arguments.
-     * <li>All init functions have a common parameter type list, which the final loop handle will also have.
-     * <li>All fini functions have a common return type, which the final loop handle will also have.
-     * <li>All non-init functions have a common parameter type list, which is the common parameter sequence, of
-     * (non-{@code void}) iteration variables followed by loop parameters.
-     * <li>Each pair of init and step functions agrees in their return types.
-     * <li>Each non-init function will be able to observe the current values of all iteration variables, by means of the
-     * common prefix.
+     * <li>All init functions have a common parameter type list {@code (A...)}, which the final loop handle will also have.
+     * <li>All fini functions have a common return type {@code R}, which the final loop handle will also have.
+     * <li>All non-init functions have a common parameter type list {@code (V... A...)}, of
+     * (non-{@code void}) iteration variables {@code V} followed by loop parameters.
+     * <li>Each pair of init and step functions agrees in their return type {@code V}.
+     * <li>Each non-init function will be able to observe the current values {@code (v...)} of all iteration variables.
+     * <li>Every function will be able to observe the incoming values {@code (a...)} of all loop parameters.
      * </ol>
      * <p>
+     * <em>Example.</em> As a consequence of step 1A above, the {@code loop} combinator has the following property:
+     * <ul>
+     * <li>Given {@code N} clauses {@code Cn = {null, Sn, Pn}} with {@code n = 1..N}.
+     * <li>Suppose predicate handles {@code Pn} are either {@code null} or have no parameters.
+     * (Only one {@code Pn} has to be non-{@code null}.)
+     * <li>Suppose step handles {@code Sn} have signatures {@code (B1..BX)Rn}, for some constant {@code X>=N}.
+     * <li>Suppose {@code Q} is the count of non-void types {@code Rn}, and {@code (V1...VQ)} is the sequence of those types.
+     * <li>It must be that {@code Vn == Bn} for {@code n = 1..min(X,Q)}.
+     * <li>The parameter types {@code Vn} will be interpreted as loop-local state elements {@code (V...)}.
+     * <li>Any remaining types {@code BQ+1..BX} (if {@code Q<X}) will determine
+     * the resulting loop handle's parameter types {@code (A...)}.
+     * </ul>
+     * In this example, the loop handle parameters {@code (A...)} were derived from the step functions,
+     * which is natural if most of the loop computation happens in the steps.  For some loops,
+     * the burden of computation might be heaviest in the pred functions, and so the pred functions
+     * might need to accept the loop parameter values.  For loops with complex exit logic, the fini
+     * functions might need to accept loop parameters, and likewise for loops with complex entry logic,
+     * where the init functions will need the extra parameters.  For such reasons, the rules for
+     * determining these parameters are as symmetric as possible, across all clause parts.
+     * In general, the loop parameters function as common invariant values across the whole
+     * loop, while the iteration variables function as common variant values, or (if there is
+     * no step function) as internal loop invariant temporaries.
+     * <p>
      * <em>Loop execution.</em><ol type="a">
-     * <li>When the loop is called, the loop input values are saved in locals, to be passed (as the common suffix) to
+     * <li>When the loop is called, the loop input values are saved in locals, to be passed to
      * every clause function. These locals are loop invariant.
-     * <li>Each init function is executed in clause order (passing the common suffix) and the non-{@code void} values
-     * are saved (as the common prefix) into locals. These locals are loop varying (unless their steps are identity
-     * functions, as noted above).
-     * <li>All function executions (except init functions) will be passed the common parameter sequence, consisting of
-     * the non-{@code void} iteration values (in clause order) and then the loop inputs (in argument order).
+     * <li>Each init function is executed in clause order (passing the external arguments {@code (a...)})
+     * and the non-{@code void} values are saved (as the iteration variables {@code (v...)}) into locals.
+     * These locals will be loop varying (unless their steps behave as identity functions, as noted above).
+     * <li>All function executions (except init functions) will be passed the internal parameter list, consisting of
+     * the non-{@code void} iteration values {@code (v...)} (in clause order) and then the loop inputs {@code (a...)}
+     * (in argument order).
      * <li>The step and pred functions are then executed, in clause order (step before pred), until a pred function
      * returns {@code false}.
-     * <li>The non-{@code void} result from a step function call is used to update the corresponding loop variable. The
-     * updated value is immediately visible to all subsequent function calls.
+     * <li>The non-{@code void} result from a step function call is used to update the corresponding value in the
+     * sequence {@code (v...)} of loop variables.
+     * The updated value is immediately visible to all subsequent function calls.
      * <li>If a pred function returns {@code false}, the corresponding fini function is called, and the resulting value
-     * is returned from the loop as a whole.
+     * (of type {@code R}) is returned from the loop as a whole.
+     * <li>If all the pred functions always return true, no fini function is ever invoked, and the loop cannot exit
+     * except by throwing an exception.
      * </ol>
      * <p>
-     * Here is pseudocode for the resulting loop handle. In the code, {@code V}/{@code v} represent the types / values
-     * of loop variables; {@code A}/{@code a}, those of arguments passed to the resulting loop; and {@code R}, the
-     * result types of finalizers as well as of the resulting loop.
+     * <em>Usage tips.</em>
+     * <ul>
+     * <li>Although each step function will receive the current values of <em>all</em> the loop variables,
+     * sometimes a step function only needs to observe the current value of its own variable.
+     * In that case, the step function may need to explicitly {@linkplain #dropArguments drop all preceding loop variables}.
+     * This will require mentioning their types, in an expression like {@code dropArguments(step, 0, V0.class, ...)}.
+     * <li>Loop variables are not required to vary; they can be loop invariant.  A clause can create
+     * a loop invariant by a suitable init function with no step, pred, or fini function.  This may be
+     * useful to "wire" an incoming loop argument into the step or pred function of an adjacent loop variable.
+     * <li>If some of the clause functions are virtual methods on an instance, the instance
+     * itself can be conveniently placed in an initial invariant loop "variable", using an initial clause
+     * like {@code new MethodHandle[]{identity(ObjType.class)}}.  In that case, the instance reference
+     * will be the first iteration variable value, and it will be easy to use virtual
+     * methods as clause parts, since all of them will take a leading instance reference matching that value.
+     * </ul>
+     * <p>
+     * Here is pseudocode for the resulting loop handle. As above, {@code V} and {@code v} represent the types
+     * and values of loop variables; {@code A} and {@code a} represent arguments passed to the whole loop;
+     * and {@code R} is the common result type of all finalizers as well as of the resulting loop.
      * <blockquote><pre>{@code
      * V... init...(A...);
      * boolean pred...(V..., A...);
@@ -4270,6 +4469,9 @@
      *   }
      * }
      * }</pre></blockquote>
+     * Note that the parameter type lists {@code (V...)} and {@code (A...)} have been expanded
+     * to their full length, even though individual clause functions may neglect to take them all.
+     * As noted above, missing parameters are filled in as if by {@link #dropArgumentsToMatch}.
      * <p>
      * @apiNote Example:
      * <blockquote><pre>{@code
@@ -4286,6 +4488,43 @@
      * MethodHandle loop = MethodHandles.loop(counterClause, accumulatorClause);
      * assertEquals(120, loop.invoke(5));
      * }</pre></blockquote>
+     * The same example, dropping arguments and using combinators:
+     * <blockquote><pre>{@code
+     * // simplified implementation of the factorial function as a loop handle
+     * static int inc(int i) { return i + 1; } // drop acc, k
+     * static int mult(int i, int acc) { return i * acc; } //drop k
+     * static boolean cmp(int i, int k) { return i < k; }
+     * // assume MH_inc, MH_mult, and MH_cmp are handles to the above methods
+     * // null initializer for counter, should initialize to 0
+     * MethodHandle MH_one = MethodHandles.constant(int.class, 1);
+     * MethodHandle MH_pred = MethodHandles.dropArguments(MH_cmp, 1, int.class); // drop acc
+     * MethodHandle MH_fin = MethodHandles.dropArguments(MethodHandles.identity(int.class), 0, int.class); // drop i
+     * MethodHandle[] counterClause = new MethodHandle[]{null, MH_inc};
+     * MethodHandle[] accumulatorClause = new MethodHandle[]{MH_one, MH_mult, MH_pred, MH_fin};
+     * MethodHandle loop = MethodHandles.loop(counterClause, accumulatorClause);
+     * assertEquals(720, loop.invoke(6));
+     * }</pre></blockquote>
+     * A similar example, using a helper object to hold a loop parameter:
+     * <blockquote><pre>{@code
+     * // instance-based implementation of the factorial function as a loop handle
+     * static class FacLoop {
+     *   final int k;
+     *   FacLoop(int k) { this.k = k; }
+     *   int inc(int i) { return i + 1; }
+     *   int mult(int i, int acc) { return i * acc; }
+     *   boolean pred(int i) { return i < k; }
+     *   int fin(int i, int acc) { return acc; }
+     * }
+     * // assume MH_FacLoop is a handle to the constructor
+     * // assume MH_inc, MH_mult, MH_pred, and MH_fin are handles to the above methods
+     * // null initializer for counter, should initialize to 0
+     * MethodHandle MH_one = MethodHandles.constant(int.class, 1);
+     * MethodHandle[] instanceClause = new MethodHandle[]{MH_FacLoop};
+     * MethodHandle[] counterClause = new MethodHandle[]{null, MH_inc};
+     * MethodHandle[] accumulatorClause = new MethodHandle[]{MH_one, MH_mult, MH_pred, MH_fin};
+     * MethodHandle loop = MethodHandles.loop(instanceClause, counterClause, accumulatorClause);
+     * assertEquals(5040, loop.invoke(7));
+     * }</pre></blockquote>
      *
      * @param clauses an array of arrays (4-tuples) of {@link MethodHandle}s adhering to the rules described above.
      *
@@ -4301,7 +4540,7 @@
      */
     public static MethodHandle loop(MethodHandle[]... clauses) {
         // Step 0: determine clause structure.
-        checkLoop0(clauses);
+        loopChecks0(clauses);
 
         List<MethodHandle> init = new ArrayList<>();
         List<MethodHandle> step = new ArrayList<>();
@@ -4318,7 +4557,7 @@
         assert Stream.of(init, step, pred, fini).map(List::size).distinct().count() == 1;
         final int nclauses = init.size();
 
-        // Step 1A: determine iteration variables.
+        // Step 1A: determine iteration variables (V...).
         final List<Class<?>> iterationVariableTypes = new ArrayList<>();
         for (int i = 0; i < nclauses; ++i) {
             MethodHandle in = init.get(i);
@@ -4326,7 +4565,7 @@
             if (in == null && st == null) {
                 iterationVariableTypes.add(void.class);
             } else if (in != null && st != null) {
-                checkLoop1a(i, in, st);
+                loopChecks1a(i, in, st);
                 iterationVariableTypes.add(in.type().returnType());
             } else {
                 iterationVariableTypes.add(in == null ? st.type().returnType() : in.type().returnType());
@@ -4335,20 +4574,20 @@
         final List<Class<?>> commonPrefix = iterationVariableTypes.stream().filter(t -> t != void.class).
                 collect(Collectors.toList());
 
-        // Step 1B: determine loop parameters.
+        // Step 1B: determine loop parameters (A...).
         final List<Class<?>> commonSuffix = buildCommonSuffix(init, step, pred, fini, commonPrefix.size());
-        checkLoop1b(init, commonSuffix);
+        loopChecks1b(init, commonSuffix);
 
         // Step 1C: determine loop return type.
         // Step 1D: check other types.
         final Class<?> loopReturnType = fini.stream().filter(Objects::nonNull).map(MethodHandle::type).
                 map(MethodType::returnType).findFirst().orElse(void.class);
-        checkLoop1cd(pred, fini, loopReturnType);
+        loopChecks1cd(pred, fini, loopReturnType);
 
         // Step 2: determine parameter lists.
         final List<Class<?>> commonParameterSequence = new ArrayList<>(commonPrefix);
         commonParameterSequence.addAll(commonSuffix);
-        checkLoop2(step, pred, fini, commonParameterSequence);
+        loopChecks2(step, pred, fini, commonParameterSequence);
 
         // Step 3: fill in omitted functions.
         for (int i = 0; i < nclauses; ++i) {
@@ -4382,6 +4621,79 @@
         return MethodHandleImpl.makeLoop(loopReturnType, commonSuffix, finit, fstep, fpred, ffini);
     }
 
+    private static void loopChecks0(MethodHandle[][] clauses) {
+        if (clauses == null || clauses.length == 0) {
+            throw newIllegalArgumentException("null or no clauses passed");
+        }
+        if (Stream.of(clauses).anyMatch(Objects::isNull)) {
+            throw newIllegalArgumentException("null clauses are not allowed");
+        }
+        if (Stream.of(clauses).anyMatch(c -> c.length > 4)) {
+            throw newIllegalArgumentException("All loop clauses must be represented as MethodHandle arrays with at most 4 elements.");
+        }
+    }
+
+    private static void loopChecks1a(int i, MethodHandle in, MethodHandle st) {
+        if (in.type().returnType() != st.type().returnType()) {
+            throw misMatchedTypes("clause " + i + ": init and step return types", in.type().returnType(),
+                    st.type().returnType());
+        }
+    }
+
+    private static List<Class<?>> longestParameterList(Stream<MethodHandle> mhs, int skipSize) {
+        final List<Class<?>> empty = List.of();
+        final List<Class<?>> longest = mhs.filter(Objects::nonNull).
+                // take only those that can contribute to a common suffix because they are longer than the prefix
+                        map(MethodHandle::type).
+                        filter(t -> t.parameterCount() > skipSize).
+                        map(MethodType::parameterList).
+                        reduce((p, q) -> p.size() >= q.size() ? p : q).orElse(empty);
+        return longest.size() == 0 ? empty : longest.subList(skipSize, longest.size());
+    }
+
+    private static List<Class<?>> longestParameterList(List<List<Class<?>>> lists) {
+        final List<Class<?>> empty = List.of();
+        return lists.stream().reduce((p, q) -> p.size() >= q.size() ? p : q).orElse(empty);
+    }
+
+    private static List<Class<?>> buildCommonSuffix(List<MethodHandle> init, List<MethodHandle> step, List<MethodHandle> pred, List<MethodHandle> fini, int cpSize) {
+        final List<Class<?>> longest1 = longestParameterList(Stream.of(step, pred, fini).flatMap(List::stream), cpSize);
+        final List<Class<?>> longest2 = longestParameterList(init.stream(), 0);
+        return longestParameterList(Arrays.asList(longest1, longest2));
+    }
+
+    private static void loopChecks1b(List<MethodHandle> init, List<Class<?>> commonSuffix) {
+        if (init.stream().filter(Objects::nonNull).map(MethodHandle::type).
+                anyMatch(t -> !t.effectivelyIdenticalParameters(0, commonSuffix))) {
+            throw newIllegalArgumentException("found non-effectively identical init parameter type lists: " + init +
+                    " (common suffix: " + commonSuffix + ")");
+        }
+    }
+
+    private static void loopChecks1cd(List<MethodHandle> pred, List<MethodHandle> fini, Class<?> loopReturnType) {
+        if (fini.stream().filter(Objects::nonNull).map(MethodHandle::type).map(MethodType::returnType).
+                anyMatch(t -> t != loopReturnType)) {
+            throw newIllegalArgumentException("found non-identical finalizer return types: " + fini + " (return type: " +
+                    loopReturnType + ")");
+        }
+
+        if (!pred.stream().filter(Objects::nonNull).findFirst().isPresent()) {
+            throw newIllegalArgumentException("no predicate found", pred);
+        }
+        if (pred.stream().filter(Objects::nonNull).map(MethodHandle::type).map(MethodType::returnType).
+                anyMatch(t -> t != boolean.class)) {
+            throw newIllegalArgumentException("predicates must have boolean return type", pred);
+        }
+    }
+
+    private static void loopChecks2(List<MethodHandle> step, List<MethodHandle> pred, List<MethodHandle> fini, List<Class<?>> commonParameterSequence) {
+        if (Stream.of(step, pred, fini).flatMap(List::stream).filter(Objects::nonNull).map(MethodHandle::type).
+                anyMatch(t -> !t.effectivelyIdenticalParameters(0, commonParameterSequence))) {
+            throw newIllegalArgumentException("found non-effectively identical parameter type lists:\nstep: " + step +
+                    "\npred: " + pred + "\nfini: " + fini + " (common parameter sequence: " + commonParameterSequence + ")");
+        }
+    }
+
     private static List<MethodHandle> fillParameterTypes(List<MethodHandle> hs, final List<Class<?>> targetParams) {
         return hs.stream().map(h -> {
             int pc = h.type().parameterCount();
@@ -4395,26 +4707,60 @@
     }
 
     /**
-     * Constructs a {@code while} loop from an initializer, a body, and a predicate. This is a convenience wrapper for
-     * the {@linkplain #loop(MethodHandle[][]) generic loop combinator}.
+     * Constructs a {@code while} loop from an initializer, a body, and a predicate.
+     * This is a convenience wrapper for the {@linkplain #loop(MethodHandle[][]) generic loop combinator}.
+     * <p>
+     * The {@code pred} handle describes the loop condition; and {@code body}, its body. The loop resulting from this
+     * method will, in each iteration, first evaluate the predicate and then execute its body (if the predicate
+     * evaluates to {@code true}).
+     * The loop will terminate once the predicate evaluates to {@code false} (the body will not be executed in this case).
+     * <p>
+     * The {@code init} handle describes the initial value of an additional optional loop-local variable.
+     * In each iteration, this loop-local variable, if present, will be passed to the {@code body}
+     * and updated with the value returned from its invocation. The result of loop execution will be
+     * the final value of the additional loop-local variable (if present).
      * <p>
-     * The loop handle's result type is the same as the sole loop variable's, i.e., the result type of {@code init}.
-     * The parameter type list of {@code init} also determines that of the resulting handle. The {@code pred} handle
-     * must have an additional leading parameter of the same type as {@code init}'s result, and so must the {@code
-     * body}. These constraints follow directly from those described for the {@linkplain MethodHandles#loop(MethodHandle[][])
-     * generic loop combinator}.
+     * The following rules hold for these argument handles:<ul>
+     * <li>The {@code body} handle must not be {@code null}; its type must be of the form
+     * {@code (V A...)V}, where {@code V} is non-{@code void}, or else {@code (A...)void}.
+     * (In the {@code void} case, we assign the type {@code void} to the name {@code V},
+     * and we will write {@code (V A...)V} with the understanding that a {@code void} type {@code V}
+     * is quietly dropped from the parameter list, leaving {@code (A...)V}.)
+     * <li>The parameter list {@code (V A...)} of the body is called the <em>internal parameter list</em>.
+     * It will constrain the parameter lists of the other loop parts.
+     * <li>If the iteration variable type {@code V} is dropped from the internal parameter list, the resulting shorter
+     * list {@code (A...)} is called the <em>external parameter list</em>.
+     * <li>The body return type {@code V}, if non-{@code void}, determines the type of an
+     * additional state variable of the loop.
+     * The body must both accept and return a value of this type {@code V}.
+     * <li>If {@code init} is non-{@code null}, it must have return type {@code V}.
+     * Its parameter list (of some <a href="MethodHandles.html#astar">form {@code (A*)}</a>) must be
+     * <a href="MethodHandles.html#effid">effectively identical</a>
+     * to the external parameter list {@code (A...)}.
+     * <li>If {@code init} is {@code null}, the loop variable will be initialized to its
+     * {@linkplain #empty default value}.
+     * <li>The {@code pred} handle must not be {@code null}.  It must have {@code boolean} as its return type.
+     * Its parameter list (either empty or of the form {@code (V A*)}) must be
+     * effectively identical to the internal parameter list.
+     * </ul>
+     * <p>
+     * The resulting loop handle's result type and parameter signature are determined as follows:<ul>
+     * <li>The loop handle's result type is the result type {@code V} of the body.
+     * <li>The loop handle's parameter types are the types {@code (A...)},
+     * from the external parameter list.
+     * </ul>
      * <p>
      * Here is pseudocode for the resulting loop handle. In the code, {@code V}/{@code v} represent the type / value of
      * the sole loop variable as well as the result type of the loop; and {@code A}/{@code a}, that of the argument
      * passed to the loop.
      * <blockquote><pre>{@code
-     * V init(A);
-     * boolean pred(V, A);
-     * V body(V, A);
-     * V whileLoop(A a) {
-     *   V v = init(a);
-     *   while (pred(v, a)) {
-     *     v = body(v, a);
+     * V init(A...);
+     * boolean pred(V, A...);
+     * V body(V, A...);
+     * V whileLoop(A... a...) {
+     *   V v = init(a...);
+     *   while (pred(v, a...)) {
+     *     v = body(v, a...);
      *   }
      *   return v;
      * }
@@ -4439,58 +4785,96 @@
      * }</pre></blockquote>
      *
      * <p>
-     * @implSpec The implementation of this method is equivalent to:
+     * @apiNote The implementation of this method can be expressed as follows:
      * <blockquote><pre>{@code
      * MethodHandle whileLoop(MethodHandle init, MethodHandle pred, MethodHandle body) {
+     *     MethodHandle fini = (body.type().returnType() == void.class
+     *                         ? null : identity(body.type().returnType()));
      *     MethodHandle[]
-     *         checkExit = {null, null, pred, identity(init.type().returnType())},
-     *         varBody = {init, body};
+     *         checkExit = { null, null, pred, fini },
+     *         varBody   = { init, body };
      *     return loop(checkExit, varBody);
      * }
      * }</pre></blockquote>
      *
-     * @param init initializer: it should provide the initial value of the loop variable. This controls the loop's
-     *             result type. Passing {@code null} or a {@code void} init function will make the loop's result type
-     *             {@code void}.
-     * @param pred condition for the loop, which may not be {@code null}.
-     * @param body body of the loop, which may not be {@code null}.
+     * @param init optional initializer, providing the initial value of the loop variable.
+     *             May be {@code null}, implying a default initial value.  See above for other constraints.
+     * @param pred condition for the loop, which may not be {@code null}. Its result type must be {@code boolean}. See
+     *             above for other constraints.
+     * @param body body of the loop, which may not be {@code null}. It controls the loop parameters and result type.
+     *             See above for other constraints.
      *
-     * @return the value of the loop variable as the loop terminates.
-     * @throws IllegalArgumentException if any argument has a type inconsistent with the loop structure
+     * @return a method handle implementing the {@code while} loop as described by the arguments.
+     * @throws IllegalArgumentException if the rules for the arguments are violated.
+     * @throws NullPointerException if {@code pred} or {@code body} are {@code null}.
      *
-     * @see MethodHandles#loop(MethodHandle[][])
+     * @see #loop(MethodHandle[][])
+     * @see #doWhileLoop(MethodHandle, MethodHandle, MethodHandle)
      * @since 9
      */
     public static MethodHandle whileLoop(MethodHandle init, MethodHandle pred, MethodHandle body) {
-        MethodHandle fin = init == null || init.type().returnType() == void.class ? zero(void.class) :
-                identity(init.type().returnType());
-        MethodHandle[] checkExit = {null, null, pred, fin};
-        MethodHandle[] varBody = {init, body};
+        whileLoopChecks(init, pred, body);
+        MethodHandle fini = identityOrVoid(body.type().returnType());
+        MethodHandle[] checkExit = { null, null, pred, fini };
+        MethodHandle[] varBody = { init, body };
         return loop(checkExit, varBody);
     }
 
     /**
-     * Constructs a {@code do-while} loop from an initializer, a body, and a predicate. This is a convenience wrapper
-     * for the {@linkplain MethodHandles#loop(MethodHandle[][]) generic loop combinator}.
+     * Constructs a {@code do-while} loop from an initializer, a body, and a predicate.
+     * This is a convenience wrapper for the {@linkplain #loop(MethodHandle[][]) generic loop combinator}.
+     * <p>
+     * The {@code pred} handle describes the loop condition; and {@code body}, its body. The loop resulting from this
+     * method will, in each iteration, first execute its body and then evaluate the predicate.
+     * The loop will terminate once the predicate evaluates to {@code false} after an execution of the body.
+     * <p>
+     * The {@code init} handle describes the initial value of an additional optional loop-local variable.
+     * In each iteration, this loop-local variable, if present, will be passed to the {@code body}
+     * and updated with the value returned from its invocation. The result of loop execution will be
+     * the final value of the additional loop-local variable (if present).
      * <p>
-     * The loop handle's result type is the same as the sole loop variable's, i.e., the result type of {@code init}.
-     * The parameter type list of {@code init} also determines that of the resulting handle. The {@code pred} handle
-     * must have an additional leading parameter of the same type as {@code init}'s result, and so must the {@code
-     * body}. These constraints follow directly from those described for the {@linkplain MethodHandles#loop(MethodHandle[][])
-     * generic loop combinator}.
+     * The following rules hold for these argument handles:<ul>
+     * <li>The {@code body} handle must not be {@code null}; its type must be of the form
+     * {@code (V A...)V}, where {@code V} is non-{@code void}, or else {@code (A...)void}.
+     * (In the {@code void} case, we assign the type {@code void} to the name {@code V},
+     * and we will write {@code (V A...)V} with the understanding that a {@code void} type {@code V}
+     * is quietly dropped from the parameter list, leaving {@code (A...)V}.)
+     * <li>The parameter list {@code (V A...)} of the body is called the <em>internal parameter list</em>.
+     * It will constrain the parameter lists of the other loop parts.
+     * <li>If the iteration variable type {@code V} is dropped from the internal parameter list, the resulting shorter
+     * list {@code (A...)} is called the <em>external parameter list</em>.
+     * <li>The body return type {@code V}, if non-{@code void}, determines the type of an
+     * additional state variable of the loop.
+     * The body must both accept and return a value of this type {@code V}.
+     * <li>If {@code init} is non-{@code null}, it must have return type {@code V}.
+     * Its parameter list (of some <a href="MethodHandles.html#astar">form {@code (A*)}</a>) must be
+     * <a href="MethodHandles.html#effid">effectively identical</a>
+     * to the external parameter list {@code (A...)}.
+     * <li>If {@code init} is {@code null}, the loop variable will be initialized to its
+     * {@linkplain #empty default value}.
+     * <li>The {@code pred} handle must not be {@code null}.  It must have {@code boolean} as its return type.
+     * Its parameter list (either empty or of the form {@code (V A*)}) must be
+     * effectively identical to the internal parameter list.
+     * </ul>
+     * <p>
+     * The resulting loop handle's result type and parameter signature are determined as follows:<ul>
+     * <li>The loop handle's result type is the result type {@code V} of the body.
+     * <li>The loop handle's parameter types are the types {@code (A...)},
+     * from the external parameter list.
+     * </ul>
      * <p>
      * Here is pseudocode for the resulting loop handle. In the code, {@code V}/{@code v} represent the type / value of
      * the sole loop variable as well as the result type of the loop; and {@code A}/{@code a}, that of the argument
      * passed to the loop.
      * <blockquote><pre>{@code
-     * V init(A);
-     * boolean pred(V, A);
-     * V body(V, A);
-     * V doWhileLoop(A a) {
-     *   V v = init(a);
+     * V init(A...);
+     * boolean pred(V, A...);
+     * V body(V, A...);
+     * V doWhileLoop(A... a...) {
+     *   V v = init(a...);
      *   do {
-     *     v = body(v, a);
-     *   } while (pred(v, a));
+     *     v = body(v, a...);
+     *   } while (pred(v, a...));
      *   return v;
      * }
      * }</pre></blockquote>
@@ -4507,59 +4891,491 @@
      * }</pre></blockquote>
      *
      * <p>
-     * @implSpec The implementation of this method is equivalent to:
+     * @apiNote The implementation of this method can be expressed as follows:
      * <blockquote><pre>{@code
      * MethodHandle doWhileLoop(MethodHandle init, MethodHandle body, MethodHandle pred) {
-     *     MethodHandle[] clause = { init, body, pred, identity(init.type().returnType()) };
+     *     MethodHandle fini = (body.type().returnType() == void.class
+     *                         ? null : identity(body.type().returnType()));
+     *     MethodHandle[] clause = { init, body, pred, fini };
      *     return loop(clause);
      * }
      * }</pre></blockquote>
      *
+     * @param init optional initializer, providing the initial value of the loop variable.
+     *             May be {@code null}, implying a default initial value.  See above for other constraints.
+     * @param body body of the loop, which may not be {@code null}. It controls the loop parameters and result type.
+     *             See above for other constraints.
+     * @param pred condition for the loop, which may not be {@code null}. Its result type must be {@code boolean}. See
+     *             above for other constraints.
      *
-     * @param init initializer: it should provide the initial value of the loop variable. This controls the loop's
-     *             result type. Passing {@code null} or a {@code void} init function will make the loop's result type
-     *             {@code void}.
-     * @param pred condition for the loop, which may not be {@code null}.
-     * @param body body of the loop, which may not be {@code null}.
+     * @return a method handle implementing the {@code while} loop as described by the arguments.
+     * @throws IllegalArgumentException if the rules for the arguments are violated.
+     * @throws NullPointerException if {@code pred} or {@code body} are {@code null}.
      *
-     * @return the value of the loop variable as the loop terminates.
-     * @throws IllegalArgumentException if any argument has a type inconsistent with the loop structure
-     *
-     * @see MethodHandles#loop(MethodHandle[][])
+     * @see #loop(MethodHandle[][])
+     * @see #whileLoop(MethodHandle, MethodHandle, MethodHandle)
      * @since 9
      */
     public static MethodHandle doWhileLoop(MethodHandle init, MethodHandle body, MethodHandle pred) {
-        MethodHandle fin = init == null || init.type().returnType() == void.class ? zero(void.class) :
-                identity(init.type().returnType());
-        MethodHandle[] clause = {init, body, pred, fin};
+        whileLoopChecks(init, pred, body);
+        MethodHandle fini = identityOrVoid(body.type().returnType());
+        MethodHandle[] clause = {init, body, pred, fini };
         return loop(clause);
     }
 
+    private static void whileLoopChecks(MethodHandle init, MethodHandle pred, MethodHandle body) {
+        Objects.requireNonNull(pred);
+        Objects.requireNonNull(body);
+        MethodType bodyType = body.type();
+        Class<?> returnType = bodyType.returnType();
+        List<Class<?>> innerList = bodyType.parameterList();
+        List<Class<?>> outerList = innerList;
+        if (returnType == void.class) {
+            // OK
+        } else if (innerList.size() == 0 || innerList.get(0) != returnType) {
+            // leading V argument missing => error
+            MethodType expected = bodyType.insertParameterTypes(0, returnType);
+            throw misMatchedTypes("body function", bodyType, expected);
+        } else {
+            outerList = innerList.subList(1, innerList.size());
+        }
+        MethodType predType = pred.type();
+        if (predType.returnType() != boolean.class ||
+                !predType.effectivelyIdenticalParameters(0, innerList)) {
+            throw misMatchedTypes("loop predicate", predType, methodType(boolean.class, innerList));
+        }
+        if (init != null) {
+            MethodType initType = init.type();
+            if (initType.returnType() != returnType ||
+                    !initType.effectivelyIdenticalParameters(0, outerList)) {
+                throw misMatchedTypes("loop initializer", initType, methodType(returnType, outerList));
+            }
+        }
+    }
+
+    /**
+     * Constructs a loop that runs a given number of iterations.
+     * This is a convenience wrapper for the {@linkplain #loop(MethodHandle[][]) generic loop combinator}.
+     * <p>
+     * The number of iterations is determined by the {@code iterations} handle evaluation result.
+     * The loop counter {@code i} is an extra loop iteration variable of type {@code int}.
+     * It will be initialized to 0 and incremented by 1 in each iteration.
+     * <p>
+     * If the {@code body} handle returns a non-{@code void} type {@code V}, a leading loop iteration variable
+     * of that type is also present.  This variable is initialized using the optional {@code init} handle,
+     * or to the {@linkplain #empty default value} of type {@code V} if that handle is {@code null}.
+     * <p>
+     * In each iteration, the iteration variables are passed to an invocation of the {@code body} handle.
+     * A non-{@code void} value returned from the body (of type {@code V}) updates the leading
+     * iteration variable.
+     * The result of the loop handle execution will be the final {@code V} value of that variable
+     * (or {@code void} if there is no {@code V} variable).
+     * <p>
+     * The following rules hold for the argument handles:<ul>
+     * <li>The {@code iterations} handle must not be {@code null}, and must return
+     * the type {@code int}, referred to here as {@code I} in parameter type lists.
+     * <li>The {@code body} handle must not be {@code null}; its type must be of the form
+     * {@code (V I A...)V}, where {@code V} is non-{@code void}, or else {@code (I A...)void}.
+     * (In the {@code void} case, we assign the type {@code void} to the name {@code V},
+     * and we will write {@code (V I A...)V} with the understanding that a {@code void} type {@code V}
+     * is quietly dropped from the parameter list, leaving {@code (I A...)V}.)
+     * <li>The parameter list {@code (V I A...)} of the body contributes to a list
+     * of types called the <em>internal parameter list</em>.
+     * It will constrain the parameter lists of the other loop parts.
+     * <li>As a special case, if the body contributes only {@code V} and {@code I} types,
+     * with no additional {@code A} types, then the internal parameter list is extended by
+     * the argument types {@code A...} of the {@code iterations} handle.
+     * <li>If the iteration variable types {@code (V I)} are dropped from the internal parameter list, the resulting shorter
+     * list {@code (A...)} is called the <em>external parameter list</em>.
+     * <li>The body return type {@code V}, if non-{@code void}, determines the type of an
+     * additional state variable of the loop.
+     * The body must both accept a leading parameter and return a value of this type {@code V}.
+     * <li>If {@code init} is non-{@code null}, it must have return type {@code V}.
+     * Its parameter list (of some <a href="MethodHandles.html#astar">form {@code (A*)}</a>) must be
+     * <a href="MethodHandles.html#effid">effectively identical</a>
+     * to the external parameter list {@code (A...)}.
+     * <li>If {@code init} is {@code null}, the loop variable will be initialized to its
+     * {@linkplain #empty default value}.
+     * <li>The parameter list of {@code iterations} (of some form {@code (A*)}) must be
+     * effectively identical to the external parameter list {@code (A...)}.
+     * </ul>
+     * <p>
+     * The resulting loop handle's result type and parameter signature are determined as follows:<ul>
+     * <li>The loop handle's result type is the result type {@code V} of the body.
+     * <li>The loop handle's parameter types are the types {@code (A...)},
+     * from the external parameter list.
+     * </ul>
+     * <p>
+     * Here is pseudocode for the resulting loop handle. In the code, {@code V}/{@code v} represent the type / value of
+     * the second loop variable as well as the result type of the loop; and {@code A...}/{@code a...} represent
+     * arguments passed to the loop.
+     * <blockquote><pre>{@code
+     * int iterations(A...);
+     * V init(A...);
+     * V body(V, int, A...);
+     * V countedLoop(A... a...) {
+     *   int end = iterations(a...);
+     *   V v = init(a...);
+     *   for (int i = 0; i < end; ++i) {
+     *     v = body(v, i, a...);
+     *   }
+     *   return v;
+     * }
+     * }</pre></blockquote>
+     * <p>
+     * @apiNote Example with a fully conformant body method:
+     * <blockquote><pre>{@code
+     * // String s = "Lambdaman!"; for (int i = 0; i < 13; ++i) { s = "na " + s; } return s;
+     * // => a variation on a well known theme
+     * static String step(String v, int counter, String init) { return "na " + v; }
+     * // assume MH_step is a handle to the method above
+     * MethodHandle fit13 = MethodHandles.constant(int.class, 13);
+     * MethodHandle start = MethodHandles.identity(String.class);
+     * MethodHandle loop = MethodHandles.countedLoop(fit13, start, MH_step);
+     * assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke("Lambdaman!"));
+     * }</pre></blockquote>
+     * <p>
+     * @apiNote Example with the simplest possible body method type,
+     * and passing the number of iterations to the loop invocation:
+     * <blockquote><pre>{@code
+     * // String s = "Lambdaman!"; for (int i = 0; i < 13; ++i) { s = "na " + s; } return s;
+     * // => a variation on a well known theme
+     * static String step(String v, int counter ) { return "na " + v; }
+     * // assume MH_step is a handle to the method above
+     * MethodHandle count = MethodHandles.dropArguments(MethodHandles.identity(int.class), 1, String.class);
+     * MethodHandle start = MethodHandles.dropArguments(MethodHandles.identity(String.class), 0, int.class);
+     * MethodHandle loop = MethodHandles.countedLoop(count, start, MH_step);  // (v, i) -> "na " + v
+     * assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke(13, "Lambdaman!"));
+     * }</pre></blockquote>
+     * <p>
+     * @apiNote Example that treats the number of iterations, string to append to, and string to append
+     * as loop parameters:
+     * <blockquote><pre>{@code
+     * // String s = "Lambdaman!", t = "na"; for (int i = 0; i < 13; ++i) { s = t + " " + s; } return s;
+     * // => a variation on a well known theme
+     * static String step(String v, int counter, int iterations_, String pre, String start_) { return pre + " " + v; }
+     * // assume MH_step is a handle to the method above
+     * MethodHandle count = MethodHandles.identity(int.class);
+     * MethodHandle start = MethodHandles.dropArguments(MethodHandles.identity(String.class), 0, int.class, String.class);
+     * MethodHandle loop = MethodHandles.countedLoop(count, start, MH_step);  // (v, i, _, pre, _) -> pre + " " + v
+     * assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke(13, "na", "Lambdaman!"));
+     * }</pre></blockquote>
+     * <p>
+     * @apiNote Example that illustrates the usage of {@link #dropArgumentsToMatch(MethodHandle, int, List, int)}
+     * to enforce a loop type:
+     * <blockquote><pre>{@code
+     * // String s = "Lambdaman!", t = "na"; for (int i = 0; i < 13; ++i) { s = t + " " + s; } return s;
+     * // => a variation on a well known theme
+     * static String step(String v, int counter, String pre) { return pre + " " + v; }
+     * // assume MH_step is a handle to the method above
+     * MethodType loopType = methodType(String.class, String.class, int.class, String.class);
+     * MethodHandle count = MethodHandles.dropArgumentsToMatch(MethodHandles.identity(int.class),    0, loopType.parameterList(), 1);
+     * MethodHandle start = MethodHandles.dropArgumentsToMatch(MethodHandles.identity(String.class), 0, loopType.parameterList(), 2);
+     * MethodHandle body  = MethodHandles.dropArgumentsToMatch(MH_step,                              2, loopType.parameterList(), 0);
+     * MethodHandle loop = MethodHandles.countedLoop(count, start, body);  // (v, i, pre, _, _) -> pre + " " + v
+     * assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke("na", 13, "Lambdaman!"));
+     * }</pre></blockquote>
+     * <p>
+     * @apiNote The implementation of this method can be expressed as follows:
+     * <blockquote><pre>{@code
+     * MethodHandle countedLoop(MethodHandle iterations, MethodHandle init, MethodHandle body) {
+     *     return countedLoop(empty(iterations.type()), iterations, init, body);
+     * }
+     * }</pre></blockquote>
+     *
+     * @param iterations a non-{@code null} handle to return the number of iterations this loop should run. The handle's
+     *                   result type must be {@code int}. See above for other constraints.
+     * @param init optional initializer, providing the initial value of the loop variable.
+     *             May be {@code null}, implying a default initial value.  See above for other constraints.
+     * @param body body of the loop, which may not be {@code null}.
+     *             It controls the loop parameters and result type in the standard case (see above for details).
+     *             It must accept its own return type (if non-void) plus an {@code int} parameter (for the counter),
+     *             and may accept any number of additional types.
+     *             See above for other constraints.
+     *
+     * @return a method handle representing the loop.
+     * @throws NullPointerException if either of the {@code iterations} or {@code body} handles is {@code null}.
+     * @throws IllegalArgumentException if any argument violates the rules formulated above.
+     *
+     * @see #countedLoop(MethodHandle, MethodHandle, MethodHandle, MethodHandle)
+     * @since 9
+     */
+    public static MethodHandle countedLoop(MethodHandle iterations, MethodHandle init, MethodHandle body) {
+        return countedLoop(empty(iterations.type()), iterations, init, body);
+    }
+
     /**
-     * Constructs a loop that runs a given number of iterations. The loop counter is an {@code int} initialized from the
-     * {@code iterations} handle evaluation result. The counter is passed to the {@code body} function, so that must
-     * accept an initial {@code int} argument. The result of the loop execution is the final value of the additional
-     * local state. This is a convenience wrapper for the {@linkplain MethodHandles#loop(MethodHandle[][]) generic loop
-     * combinator}.
+     * Constructs a loop that counts over a range of numbers.
+     * This is a convenience wrapper for the {@linkplain #loop(MethodHandle[][]) generic loop combinator}.
+     * <p>
+     * The loop counter {@code i} is a loop iteration variable of type {@code int}.
+     * The {@code start} and {@code end} handles determine the start (inclusive) and end (exclusive)
+     * values of the loop counter.
+     * The loop counter will be initialized to the {@code int} value returned from the evaluation of the
+     * {@code start} handle and run to the value returned from {@code end} (exclusively) with a step width of 1.
+     * <p>
+     * If the {@code body} handle returns a non-{@code void} type {@code V}, a leading loop iteration variable
+     * of that type is also present.  This variable is initialized using the optional {@code init} handle,
+     * or to the {@linkplain #empty default value} of type {@code V} if that handle is {@code null}.
+     * <p>
+     * In each iteration, the iteration variables are passed to an invocation of the {@code body} handle.
+     * A non-{@code void} value returned from the body (of type {@code V}) updates the leading
+     * iteration variable.
+     * The result of the loop handle execution will be the final {@code V} value of that variable
+     * (or {@code void} if there is no {@code V} variable).
      * <p>
-     * The result type and parameter type list of {@code init} determine those of the resulting handle. The {@code
-     * iterations} handle must accept the same parameter types as {@code init} but return an {@code int}. The {@code
-     * body} handle must accept the same parameter types as well, preceded by an {@code int} parameter for the counter,
-     * and a parameter of the same type as {@code init}'s result. These constraints follow directly from those described
-     * for the {@linkplain MethodHandles#loop(MethodHandle[][]) generic loop combinator}.
+     * The following rules hold for the argument handles:<ul>
+     * <li>The {@code start} and {@code end} handles must not be {@code null}, and must both return
+     * the common type {@code int}, referred to here as {@code I} in parameter type lists.
+     * <li>The {@code body} handle must not be {@code null}; its type must be of the form
+     * {@code (V I A...)V}, where {@code V} is non-{@code void}, or else {@code (I A...)void}.
+     * (In the {@code void} case, we assign the type {@code void} to the name {@code V},
+     * and we will write {@code (V I A...)V} with the understanding that a {@code void} type {@code V}
+     * is quietly dropped from the parameter list, leaving {@code (I A...)V}.)
+     * <li>The parameter list {@code (V I A...)} of the body contributes to a list
+     * of types called the <em>internal parameter list</em>.
+     * It will constrain the parameter lists of the other loop parts.
+     * <li>As a special case, if the body contributes only {@code V} and {@code I} types,
+     * with no additional {@code A} types, then the internal parameter list is extended by
+     * the argument types {@code A...} of the {@code end} handle.
+     * <li>If the iteration variable types {@code (V I)} are dropped from the internal parameter list, the resulting shorter
+     * list {@code (A...)} is called the <em>external parameter list</em>.
+     * <li>The body return type {@code V}, if non-{@code void}, determines the type of an
+     * additional state variable of the loop.
+     * The body must both accept a leading parameter and return a value of this type {@code V}.
+     * <li>If {@code init} is non-{@code null}, it must have return type {@code V}.
+     * Its parameter list (of some <a href="MethodHandles.html#astar">form {@code (A*)}</a>) must be
+     * <a href="MethodHandles.html#effid">effectively identical</a>
+     * to the external parameter list {@code (A...)}.
+     * <li>If {@code init} is {@code null}, the loop variable will be initialized to its
+     * {@linkplain #empty default value}.
+     * <li>The parameter list of {@code start} (of some form {@code (A*)}) must be
+     * effectively identical to the external parameter list {@code (A...)}.
+     * <li>Likewise, the parameter list of {@code end} must be effectively identical
+     * to the external parameter list.
+     * </ul>
+     * <p>
+     * The resulting loop handle's result type and parameter signature are determined as follows:<ul>
+     * <li>The loop handle's result type is the result type {@code V} of the body.
+     * <li>The loop handle's parameter types are the types {@code (A...)},
+     * from the external parameter list.
+     * </ul>
      * <p>
      * Here is pseudocode for the resulting loop handle. In the code, {@code V}/{@code v} represent the type / value of
-     * the sole loop variable as well as the result type of the loop; and {@code A}/{@code a}, that of the argument
-     * passed to the loop.
+     * the second loop variable as well as the result type of the loop; and {@code A...}/{@code a...} represent
+     * arguments passed to the loop.
+     * <blockquote><pre>{@code
+     * int start(A...);
+     * int end(A...);
+     * V init(A...);
+     * V body(V, int, A...);
+     * V countedLoop(A... a...) {
+     *   int e = end(a...);
+     *   int s = start(a...);
+     *   V v = init(a...);
+     *   for (int i = s; i < e; ++i) {
+     *     v = body(v, i, a...);
+     *   }
+     *   return v;
+     * }
+     * }</pre></blockquote>
+     *
+     * <p>
+     * @apiNote The implementation of this method can be expressed as follows:
      * <blockquote><pre>{@code
-     * int iterations(A);
-     * V init(A);
-     * V body(int, V, A);
-     * V countedLoop(A a) {
-     *   int end = iterations(a);
-     *   V v = init(a);
-     *   for (int i = 0; i < end; ++i) {
-     *     v = body(i, v, a);
+     * MethodHandle countedLoop(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body) {
+     *     MethodHandle returnVar = dropArguments(identity(init.type().returnType()), 0, int.class, int.class);
+     *     // assume MH_increment and MH_predicate are handles to implementation-internal methods with
+     *     // the following semantics:
+     *     // MH_increment: (int limit, int counter) -> counter + 1
+     *     // MH_predicate: (int limit, int counter) -> counter < limit
+     *     Class<?> counterType = start.type().returnType();  // int
+     *     Class<?> returnType = body.type().returnType();
+     *     MethodHandle incr = MH_increment, pred = MH_predicate, retv = null;
+     *     if (returnType != void.class) {  // ignore the V variable
+     *         incr = dropArguments(incr, 1, returnType);  // (limit, v, i) => (limit, i)
+     *         pred = dropArguments(pred, 1, returnType);  // ditto
+     *         retv = dropArguments(identity(returnType), 0, counterType); // ignore limit
+     *     }
+     *     body = dropArguments(body, 0, counterType);  // ignore the limit variable
+     *     MethodHandle[]
+     *         loopLimit  = { end, null, pred, retv }, // limit = end(); i < limit || return v
+     *         bodyClause = { init, body },            // v = init(); v = body(v, i)
+     *         indexVar   = { start, incr };           // i = start(); i = i + 1
+     *     return loop(loopLimit, bodyClause, indexVar);
+     * }
+     * }</pre></blockquote>
+     *
+     * @param start a non-{@code null} handle to return the start value of the loop counter, which must be {@code int}.
+     *              See above for other constraints.
+     * @param end a non-{@code null} handle to return the end value of the loop counter (the loop will run to
+     *            {@code end-1}). The result type must be {@code int}. See above for other constraints.
+     * @param init optional initializer, providing the initial value of the loop variable.
+     *             May be {@code null}, implying a default initial value.  See above for other constraints.
+     * @param body body of the loop, which may not be {@code null}.
+     *             It controls the loop parameters and result type in the standard case (see above for details).
+     *             It must accept its own return type (if non-void) plus an {@code int} parameter (for the counter),
+     *             and may accept any number of additional types.
+     *             See above for other constraints.
+     *
+     * @return a method handle representing the loop.
+     * @throws NullPointerException if any of the {@code start}, {@code end}, or {@code body} handles is {@code null}.
+     * @throws IllegalArgumentException if any argument violates the rules formulated above.
+     *
+     * @see #countedLoop(MethodHandle, MethodHandle, MethodHandle)
+     * @since 9
+     */
+    public static MethodHandle countedLoop(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body) {
+        countedLoopChecks(start, end, init, body);
+        Class<?> counterType = start.type().returnType();  // int, but who's counting?
+        Class<?> limitType   = end.type().returnType();    // yes, int again
+        Class<?> returnType  = body.type().returnType();
+        MethodHandle incr = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopStep);
+        MethodHandle pred = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopPred);
+        MethodHandle retv = null;
+        if (returnType != void.class) {
+            incr = dropArguments(incr, 1, returnType);  // (limit, v, i) => (limit, i)
+            pred = dropArguments(pred, 1, returnType);  // ditto
+            retv = dropArguments(identity(returnType), 0, counterType);
+        }
+        body = dropArguments(body, 0, counterType);  // ignore the limit variable
+        MethodHandle[]
+            loopLimit  = { end, null, pred, retv }, // limit = end(); i < limit || return v
+            bodyClause = { init, body },            // v = init(); v = body(v, i)
+            indexVar   = { start, incr };           // i = start(); i = i + 1
+        return loop(loopLimit, bodyClause, indexVar);
+    }
+
+    private static void countedLoopChecks(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body) {
+        Objects.requireNonNull(start);
+        Objects.requireNonNull(end);
+        Objects.requireNonNull(body);
+        Class<?> counterType = start.type().returnType();
+        if (counterType != int.class) {
+            MethodType expected = start.type().changeReturnType(int.class);
+            throw misMatchedTypes("start function", start.type(), expected);
+        } else if (end.type().returnType() != counterType) {
+            MethodType expected = end.type().changeReturnType(counterType);
+            throw misMatchedTypes("end function", end.type(), expected);
+        }
+        MethodType bodyType = body.type();
+        Class<?> returnType = bodyType.returnType();
+        List<Class<?>> innerList = bodyType.parameterList();
+        // strip leading V value if present
+        int vsize = (returnType == void.class ? 0 : 1);
+        if (vsize != 0 && (innerList.size() == 0 || innerList.get(0) != returnType)) {
+            // argument list has no "V" => error
+            MethodType expected = bodyType.insertParameterTypes(0, returnType);
+            throw misMatchedTypes("body function", bodyType, expected);
+        } else if (innerList.size() <= vsize || innerList.get(vsize) != counterType) {
+            // missing I type => error
+            MethodType expected = bodyType.insertParameterTypes(vsize, counterType);
+            throw misMatchedTypes("body function", bodyType, expected);
+        }
+        List<Class<?>> outerList = innerList.subList(vsize + 1, innerList.size());
+        if (outerList.isEmpty()) {
+            // special case; take lists from end handle
+            outerList = end.type().parameterList();
+            innerList = bodyType.insertParameterTypes(vsize + 1, outerList).parameterList();
+        }
+        MethodType expected = methodType(counterType, outerList);
+        if (!start.type().effectivelyIdenticalParameters(0, outerList)) {
+            throw misMatchedTypes("start parameter types", start.type(), expected);
+        }
+        if (end.type() != start.type() &&
+            !end.type().effectivelyIdenticalParameters(0, outerList)) {
+            throw misMatchedTypes("end parameter types", end.type(), expected);
+        }
+        if (init != null) {
+            MethodType initType = init.type();
+            if (initType.returnType() != returnType ||
+                !initType.effectivelyIdenticalParameters(0, outerList)) {
+                throw misMatchedTypes("loop initializer", initType, methodType(returnType, outerList));
+            }
+        }
+    }
+
+    /**
+     * Constructs a loop that ranges over the values produced by an {@code Iterator<T>}.
+     * This is a convenience wrapper for the {@linkplain #loop(MethodHandle[][]) generic loop combinator}.
+     * <p>
+     * The iterator itself will be determined by the evaluation of the {@code iterator} handle.
+     * Each value it produces will be stored in a loop iteration variable of type {@code T}.
+     * <p>
+     * If the {@code body} handle returns a non-{@code void} type {@code V}, a leading loop iteration variable
+     * of that type is also present.  This variable is initialized using the optional {@code init} handle,
+     * or to the {@linkplain #empty default value} of type {@code V} if that handle is {@code null}.
+     * <p>
+     * In each iteration, the iteration variables are passed to an invocation of the {@code body} handle.
+     * A non-{@code void} value returned from the body (of type {@code V}) updates the leading
+     * iteration variable.
+     * The result of the loop handle execution will be the final {@code V} value of that variable
+     * (or {@code void} if there is no {@code V} variable).
+     * <p>
+     * The following rules hold for the argument handles:<ul>
+     * <li>The {@code body} handle must not be {@code null}; its type must be of the form
+     * {@code (V T A...)V}, where {@code V} is non-{@code void}, or else {@code (T A...)void}.
+     * (In the {@code void} case, we assign the type {@code void} to the name {@code V},
+     * and we will write {@code (V T A...)V} with the understanding that a {@code void} type {@code V}
+     * is quietly dropped from the parameter list, leaving {@code (T A...)V}.)
+     * <li>The parameter list {@code (V T A...)} of the body contributes to a list
+     * of types called the <em>internal parameter list</em>.
+     * It will constrain the parameter lists of the other loop parts.
+     * <li>As a special case, if the body contributes only {@code V} and {@code T} types,
+     * with no additional {@code A} types, then the internal parameter list is extended by
+     * the argument types {@code A...} of the {@code iterator} handle; if it is {@code null} the
+     * single type {@code Iterable} is added and constitutes the {@code A...} list.
+     * <li>If the iteration variable types {@code (V T)} are dropped from the internal parameter list, the resulting shorter
+     * list {@code (A...)} is called the <em>external parameter list</em>.
+     * <li>The body return type {@code V}, if non-{@code void}, determines the type of an
+     * additional state variable of the loop.
+     * The body must both accept a leading parameter and return a value of this type {@code V}.
+     * <li>If {@code init} is non-{@code null}, it must have return type {@code V}.
+     * Its parameter list (of some <a href="MethodHandles.html#astar">form {@code (A*)}</a>) must be
+     * <a href="MethodHandles.html#effid">effectively identical</a>
+     * to the external parameter list {@code (A...)}.
+     * <li>If {@code init} is {@code null}, the loop variable will be initialized to its
+     * {@linkplain #empty default value}.
+     * <li>If the {@code iterator} handle is non-{@code null}, it must have the return
+     * type {@code java.util.Iterator} or a subtype thereof.
+     * The iterator it produces when the loop is executed will be assumed
+     * to yield values which can be converted to type {@code T}.
+     * <li>The parameter list of an {@code iterator} that is non-{@code null} (of some form {@code (A*)}) must be
+     * effectively identical to the external parameter list {@code (A...)}.
+     * <li>If {@code iterator} is {@code null} it defaults to a method handle which behaves
+     * like {@link java.lang.Iterable#iterator()}.  In that case, the internal parameter list
+     * {@code (V T A...)} must have at least one {@code A} type, and the default iterator
+     * handle parameter is adjusted to accept the leading {@code A} type, as if by
+     * the {@link MethodHandle#asType asType} conversion method.
+     * The leading {@code A} type must be {@code Iterable} or a subtype thereof, or an array type.
+     * This conversion step, done at loop construction time, must not throw a {@code WrongMethodTypeException}.
+     * </ul>
+     * <p>
+     * The type {@code T} may be either a primitive or reference.
+     * Since type {@code Iterator<T>} is erased in the method handle representation to the raw type {@code Iterator},
+     * the {@code iteratedLoop} combinator adjusts the leading argument type for {@code body} to {@code Object}
+     * as if by the {@link MethodHandle#asType asType} conversion method.
+     * Therefore, if an iterator of the wrong type appears as the loop is executed, runtime exceptions may occur
+     * as the result of dynamic conversions performed by {@link MethodHandle#asType(MethodType)}.
+     * <p>
+     * The resulting loop handle's result type and parameter signature are determined as follows:<ul>
+     * <li>The loop handle's result type is the result type {@code V} of the body.
+     * <li>The loop handle's parameter types are the types {@code (A...)},
+     * from the external parameter list.
+     * </ul>
+     * <p>
+     * Here is pseudocode for the resulting loop handle. In the code, {@code V}/{@code v} represent the type / value of
+     * the loop variable as well as the result type of the loop; {@code T}/{@code t}, that of the elements of the
+     * structure the loop iterates over, and {@code A...}/{@code a...} represent arguments passed to the loop.
+     * <blockquote><pre>{@code
+     * Iterator<T> iterator(A...);  // defaults to Iterable::iterator
+     * V init(A...);
+     * V body(V,T,A...);
+     * V iteratedLoop(A... a...) {
+     *   Iterator<T> it = iterator(a...);
+     *   V v = init(a...);
+     *   for (T t : it) {
+     *     v = body(v, t, a...);
      *   }
      *   return v;
      * }
@@ -4567,243 +5383,164 @@
      * <p>
      * @apiNote Example:
      * <blockquote><pre>{@code
-     * // String s = "Lambdaman!"; for (int i = 0; i < 13; ++i) { s = "na " + s; } return s;
-     * // => a variation on a well known theme
-     * static String start(String arg) { return arg; }
-     * static String step(int counter, String v, String arg) { return "na " + v; }
-     * // assume MH_start and MH_step are handles to the two methods above
-     * MethodHandle fit13 = MethodHandles.constant(int.class, 13);
-     * MethodHandle loop = MethodHandles.countedLoop(fit13, MH_start, MH_step);
-     * assertEquals("na na na na na na na na na na na na na Lambdaman!", loop.invoke("Lambdaman!"));
-     * }</pre></blockquote>
-     *
-     * <p>
-     * @implSpec The implementation of this method is equivalent to:
-     * <blockquote><pre>{@code
-     * MethodHandle countedLoop(MethodHandle iterations, MethodHandle init, MethodHandle body) {
-     *     return countedLoop(null, iterations, init, body);  // null => constant zero
-     * }
-     * }</pre></blockquote>
-     *
-     * @param iterations a handle to return the number of iterations this loop should run.
-     * @param init initializer for additional loop state. This determines the loop's result type.
-     *             Passing {@code null} or a {@code void} init function will make the loop's result type
-     *             {@code void}.
-     * @param body the body of the loop, which must not be {@code null}.
-     *             It must accept an initial {@code int} parameter (for the counter), and then any
-     *             additional loop-local variable plus loop parameters.
-     *
-     * @return a method handle representing the loop.
-     * @throws IllegalArgumentException if any argument has a type inconsistent with the loop structure
-     *
-     * @since 9
-     */
-    public static MethodHandle countedLoop(MethodHandle iterations, MethodHandle init, MethodHandle body) {
-        return countedLoop(null, iterations, init, body);
-    }
-
-    /**
-     * Constructs a loop that counts over a range of numbers. The loop counter is an {@code int} that will be
-     * initialized to the {@code int} value returned from the evaluation of the {@code start} handle and run to the
-     * value returned from {@code end} (exclusively) with a step width of 1. The counter value is passed to the {@code
-     * body} function in each iteration; it has to accept an initial {@code int} parameter
-     * for that. The result of the loop execution is the final value of the additional local state
-     * obtained by running {@code init}.
-     * This is a
-     * convenience wrapper for the {@linkplain MethodHandles#loop(MethodHandle[][]) generic loop combinator}.
-     * <p>
-     * The constraints for the {@code init} and {@code body} handles are the same as for {@link
-     * #countedLoop(MethodHandle, MethodHandle, MethodHandle)}. Additionally, the {@code start} and {@code end} handles
-     * must return an {@code int} and accept the same parameters as {@code init}.
-     * <p>
-     * Here is pseudocode for the resulting loop handle. In the code, {@code V}/{@code v} represent the type / value of
-     * the sole loop variable as well as the result type of the loop; and {@code A}/{@code a}, that of the argument
-     * passed to the loop.
-     * <blockquote><pre>{@code
-     * int start(A);
-     * int end(A);
-     * V init(A);
-     * V body(int, V, A);
-     * V countedLoop(A a) {
-     *   int s = start(a);
-     *   int e = end(a);
-     *   V v = init(a);
-     *   for (int i = s; i < e; ++i) {
-     *     v = body(i, v, a);
-     *   }
-     *   return v;
-     * }
-     * }</pre></blockquote>
-     *
-     * <p>
-     * @implSpec The implementation of this method is equivalent to:
-     * <blockquote><pre>{@code
-     * MethodHandle countedLoop(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body) {
-     *     MethodHandle returnVar = dropArguments(identity(init.type().returnType()), 0, int.class, int.class);
-     *     // assume MH_increment and MH_lessThan are handles to x+1 and x<y of type int,
-     *     // assume MH_decrement is a handle to x-1 of type int
-     *     MethodHandle[]
-     *         indexVar = {start, MH_increment}, // i = start; i = i+1
-     *         loopLimit = {end, null,
-     *                       filterArgument(MH_lessThan, 0, MH_decrement), returnVar}, // i-1<end
-     *         bodyClause = {init,
-     *                       filterArgument(dropArguments(body, 1, int.class), 0, MH_decrement}; // v = body(i-1, v)
-     *     return loop(indexVar, loopLimit, bodyClause);
-     * }
-     * }</pre></blockquote>
-     *
-     * @param start a handle to return the start value of the loop counter.
-     *              If it is {@code null}, a constant zero is assumed.
-     * @param end a non-{@code null} handle to return the end value of the loop counter (the loop will run to {@code end-1}).
-     * @param init initializer for additional loop state. This determines the loop's result type.
-     *             Passing {@code null} or a {@code void} init function will make the loop's result type
-     *             {@code void}.
-     * @param body the body of the loop, which must not be {@code null}.
-     *             It must accept an initial {@code int} parameter (for the counter), and then any
-     *             additional loop-local variable plus loop parameters.
-     *
-     * @return a method handle representing the loop.
-     * @throws IllegalArgumentException if any argument has a type inconsistent with the loop structure
-     *
-     * @since 9
-     */
-    public static MethodHandle countedLoop(MethodHandle start, MethodHandle end, MethodHandle init, MethodHandle body) {
-        Class<?> resultType;
-        MethodHandle actualInit;
-        if (init == null) {
-            resultType = body == null ? void.class : body.type().returnType();
-            actualInit = empty(methodType(resultType));
-        } else {
-            resultType = init.type().returnType();
-            actualInit = init;
-        }
-        MethodHandle defaultResultHandle = resultType == void.class ? zero(void.class) : identity(resultType);
-        MethodHandle actualBody = body == null ? dropArguments(defaultResultHandle, 0, int.class) : body;
-        MethodHandle returnVar = dropArguments(defaultResultHandle, 0, int.class, int.class);
-        MethodHandle actualEnd = end == null ? constant(int.class, 0) : end;
-        MethodHandle decr = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_decrementCounter);
-        MethodHandle[] indexVar = {start, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopStep)};
-        MethodHandle[] loopLimit = {actualEnd, null,
-                filterArgument(MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_countedLoopPred), 0, decr),
-                returnVar};
-        MethodHandle[] bodyClause = {actualInit, filterArgument(dropArguments(actualBody, 1, int.class), 0, decr)};
-        return loop(indexVar, loopLimit, bodyClause);
-    }
-
-    /**
-     * Constructs a loop that ranges over the elements produced by an {@code Iterator<T>}.
-     * The iterator will be produced by the evaluation of the {@code iterator} handle.
-     * This handle must have {@link java.util.Iterator} as its return type.
-     * If this handle is passed as {@code null} the method {@link Iterable#iterator} will be used instead,
-     * and will be applied to a leading argument of the loop handle.
-     * Each value produced by the iterator is passed to the {@code body}, which must accept an initial {@code T} parameter.
-     * The result of the loop execution is the final value of the additional local state
-     * obtained by running {@code init}.
-     * <p>
-     * This is a convenience wrapper for the
-     * {@linkplain MethodHandles#loop(MethodHandle[][]) generic loop combinator}, and the constraints imposed on the {@code body}
-     * handle follow directly from those described for the latter.
-     * <p>
-     * Here is pseudocode for the resulting loop handle. In the code, {@code V}/{@code v} represent the type / value of
-     * the loop variable as well as the result type of the loop; {@code T}/{@code t}, that of the elements of the
-     * structure the loop iterates over, and {@code A}/{@code a}, that of the argument passed to the loop.
-     * <blockquote><pre>{@code
-     * Iterator<T> iterator(A);  // defaults to Iterable::iterator
-     * V init(A);
-     * V body(T,V,A);
-     * V iteratedLoop(A a) {
-     *   Iterator<T> it = iterator(a);
-     *   V v = init(a);
-     *   for (T t : it) {
-     *     v = body(t, v, a);
-     *   }
-     *   return v;
-     * }
-     * }</pre></blockquote>
-     * <p>
-     * The type {@code T} may be either a primitive or reference.
-     * Since type {@code Iterator<T>} is erased in the method handle representation to the raw type
-     * {@code Iterator}, the {@code iteratedLoop} combinator adjusts the leading argument type for {@code body}
-     * to {@code Object} as if by the {@link MethodHandle#asType asType} conversion method.
-     * Therefore, if an iterator of the wrong type appears as the loop is executed,
-     * runtime exceptions may occur as the result of dynamic conversions performed by {@code asType}.
-     * <p>
-     * @apiNote Example:
-     * <blockquote><pre>{@code
-     * // reverse a list
-     * static List<String> reverseStep(String e, List<String> r, List<String> l) {
+     * // get an iterator from a list
+     * static List<String> reverseStep(List<String> r, String e) {
      *   r.add(0, e);
      *   return r;
      * }
-     * static List<String> newArrayList(List<String> l) { return new ArrayList<>(); }
-     * // assume MH_reverseStep, MH_newArrayList are handles to the above methods
+     * static List<String> newArrayList() { return new ArrayList<>(); }
+     * // assume MH_reverseStep and MH_newArrayList are handles to the above methods
      * MethodHandle loop = MethodHandles.iteratedLoop(null, MH_newArrayList, MH_reverseStep);
      * List<String> list = Arrays.asList("a", "b", "c", "d", "e");
      * List<String> reversedList = Arrays.asList("e", "d", "c", "b", "a");
      * assertEquals(reversedList, (List<String>) loop.invoke(list));
      * }</pre></blockquote>
      * <p>
-     * @implSpec The implementation of this method is equivalent to (excluding error handling):
+     * @apiNote The implementation of this method can be expressed approximately as follows:
      * <blockquote><pre>{@code
      * MethodHandle iteratedLoop(MethodHandle iterator, MethodHandle init, MethodHandle body) {
-     *     // assume MH_next and MH_hasNext are handles to methods of Iterator
-     *     Class<?> itype = iterator.type().returnType();
-     *     Class<?> ttype = body.type().parameterType(0);
-     *     MethodHandle returnVar = dropArguments(identity(init.type().returnType()), 0, itype);
+     *     // assume MH_next, MH_hasNext, MH_startIter are handles to methods of Iterator/Iterable
+     *     Class<?> returnType = body.type().returnType();
+     *     Class<?> ttype = body.type().parameterType(returnType == void.class ? 0 : 1);
      *     MethodHandle nextVal = MH_next.asType(MH_next.type().changeReturnType(ttype));
+     *     MethodHandle retv = null, step = body, startIter = iterator;
+     *     if (returnType != void.class) {
+     *         // the simple thing first:  in (I V A...), drop the I to get V
+     *         retv = dropArguments(identity(returnType), 0, Iterator.class);
+     *         // body type signature (V T A...), internal loop types (I V A...)
+     *         step = swapArguments(body, 0, 1);  // swap V <-> T
+     *     }
+     *     if (startIter == null)  startIter = MH_getIter;
      *     MethodHandle[]
-     *         iterVar = {iterator, null, MH_hasNext, returnVar}, // it = iterator(); while (it.hasNext)
-     *         bodyClause = {init, filterArgument(body, 0, nextVal)};  // v = body(t, v, a);
+     *         iterVar    = { startIter, null, MH_hasNext, retv }, // it = iterator; while (it.hasNext())
+     *         bodyClause = { init, filterArguments(step, 0, nextVal) };  // v = body(v, t, a)
      *     return loop(iterVar, bodyClause);
      * }
      * }</pre></blockquote>
      *
-     * @param iterator a handle to return the iterator to start the loop.
-     *             The handle must have {@link java.util.Iterator} as its return type.
-     *             Passing {@code null} will make the loop call {@link Iterable#iterator()} on the first
-     *             incoming value.
-     * @param init initializer for additional loop state. This determines the loop's result type.
-     *             Passing {@code null} or a {@code void} init function will make the loop's result type
-     *             {@code void}.
-     * @param body the body of the loop, which must not be {@code null}.
-     *             It must accept an initial {@code T} parameter (for the iterated values), and then any
-     *             additional loop-local variable plus loop parameters.
+     * @param iterator an optional handle to return the iterator to start the loop.
+     *                 If non-{@code null}, the handle must return {@link java.util.Iterator} or a subtype.
+     *                 See above for other constraints.
+     * @param init optional initializer, providing the initial value of the loop variable.
+     *             May be {@code null}, implying a default initial value.  See above for other constraints.
+     * @param body body of the loop, which may not be {@code null}.
+     *             It controls the loop parameters and result type in the standard case (see above for details).
+     *             It must accept its own return type (if non-void) plus a {@code T} parameter (for the iterated values),
+     *             and may accept any number of additional types.
+     *             See above for other constraints.
      *
      * @return a method handle embodying the iteration loop functionality.
-     * @throws IllegalArgumentException if any argument has a type inconsistent with the loop structure
+     * @throws NullPointerException if the {@code body} handle is {@code null}.
+     * @throws IllegalArgumentException if any argument violates the above requirements.
      *
      * @since 9
      */
     public static MethodHandle iteratedLoop(MethodHandle iterator, MethodHandle init, MethodHandle body) {
-        checkIteratedLoop(iterator, body);
-        Class<?> resultType = init == null ?
-                body == null ? void.class : body.type().returnType() :
-                init.type().returnType();
-        boolean voidResult = resultType == void.class;
-
-        MethodHandle initIterator;
-        if (iterator == null) {
-            MethodHandle initit = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_initIterator);
-            initIterator = initit.asType(initit.type().changeParameterType(0,
-                    body.type().parameterType(voidResult ? 1 : 2)));
-        } else {
-            initIterator = iterator.asType(iterator.type().changeReturnType(Iterator.class));
+        Class<?> iterableType = iteratedLoopChecks(iterator, init, body);
+        Class<?> returnType = body.type().returnType();
+        MethodHandle hasNext = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_iteratePred);
+        MethodHandle nextRaw = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_iterateNext);
+        MethodHandle startIter;
+        MethodHandle nextVal;
+        {
+            MethodType iteratorType;
+            if (iterator == null) {
+                // derive argument type from body, if available, else use Iterable
+                startIter = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_initIterator);
+                iteratorType = startIter.type().changeParameterType(0, iterableType);
+            } else {
+                // force return type to the internal iterator class
+                iteratorType = iterator.type().changeReturnType(Iterator.class);
+                startIter = iterator;
+            }
+            Class<?> ttype = body.type().parameterType(returnType == void.class ? 0 : 1);
+            MethodType nextValType = nextRaw.type().changeReturnType(ttype);
+
+            // perform the asType transforms under an exception transformer, as per spec.:
+            try {
+                startIter = startIter.asType(iteratorType);
+                nextVal = nextRaw.asType(nextValType);
+            } catch (WrongMethodTypeException ex) {
+                throw new IllegalArgumentException(ex);
+            }
+        }
+
+        MethodHandle retv = null, step = body;
+        if (returnType != void.class) {
+            // the simple thing first:  in (I V A...), drop the I to get V
+            retv = dropArguments(identity(returnType), 0, Iterator.class);
+            // body type signature (V T A...), internal loop types (I V A...)
+            step = swapArguments(body, 0, 1);  // swap V <-> T
         }
 
-        Class<?> ttype = body.type().parameterType(0);
-
-        MethodHandle returnVar =
-                dropArguments(voidResult ? zero(void.class) : identity(resultType), 0, Iterator.class);
-        MethodHandle initnx = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_iterateNext);
-        MethodHandle nextVal = initnx.asType(initnx.type().changeReturnType(ttype));
-
-        MethodHandle[] iterVar = {initIterator, null, MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_iteratePred),
-                returnVar};
-        MethodHandle[] bodyClause = {init, filterArgument(body, 0, nextVal)};
-
+        MethodHandle[]
+            iterVar    = { startIter, null, hasNext, retv },
+            bodyClause = { init, filterArgument(step, 0, nextVal) };
         return loop(iterVar, bodyClause);
     }
 
+    private static Class<?> iteratedLoopChecks(MethodHandle iterator, MethodHandle init, MethodHandle body) {
+        Objects.requireNonNull(body);
+        MethodType bodyType = body.type();
+        Class<?> returnType = bodyType.returnType();
+        List<Class<?>> innerList = bodyType.parameterList();
+        // strip leading V value if present
+        int vsize = (returnType == void.class ? 0 : 1);
+        if (vsize != 0 && (innerList.size() == 0 || innerList.get(0) != returnType)) {
+            // argument list has no "V" => error
+            MethodType expected = bodyType.insertParameterTypes(0, returnType);
+            throw misMatchedTypes("body function", bodyType, expected);
+        } else if (innerList.size() <= vsize) {
+            // missing T type => error
+            MethodType expected = bodyType.insertParameterTypes(vsize, Object.class);
+            throw misMatchedTypes("body function", bodyType, expected);
+        }
+        //Class<?> elementType = innerList.get(vsize);  // do not need this
+        List<Class<?>> outerList = innerList.subList(vsize + 1, innerList.size());
+        if (outerList.isEmpty()) {
+            // special case; take lists from iterator handle
+            outerList = ((iterator != null)
+                    ? iterator.type().parameterList()
+                    : Arrays.asList(Iterable.class));
+            innerList = bodyType.insertParameterTypes(vsize + 1, outerList).parameterList();
+        }
+        if (iterator != null) {
+            MethodType itype = iterator.type();
+            if (!Iterator.class.isAssignableFrom(itype.returnType())) {
+                throw newIllegalArgumentException("iteratedLoop first argument must have Iterator return type");
+            }
+            if (!itype.effectivelyIdenticalParameters(0, outerList)) {
+                MethodType expected = methodType(itype.returnType(), outerList);
+                throw misMatchedTypes("iterator parameters", itype, expected);
+            }
+        }
+        if (init != null) {
+            MethodType initType = init.type();
+            if (initType.returnType() != returnType ||
+                    !initType.effectivelyIdenticalParameters(0, outerList)) {
+                throw misMatchedTypes("loop initializer", initType, methodType(returnType, outerList));
+            }
+        }
+        Class<?> iterableType = outerList.isEmpty() ? null : outerList.get(0);
+        if (iterableType != null && !Iterable.class.isAssignableFrom(iterableType) && !iterableType.isArray()) {
+            throw newIllegalArgumentException(
+                    "inferred first loop argument must be an array or inherit from Iterable: " + iterableType);
+        }
+        return iterableType;  // help the caller a bit
+    }
+
+    /*non-public*/ static MethodHandle swapArguments(MethodHandle mh, int i, int j) {
+        // there should be a better way to uncross my wires
+        int arity = mh.type().parameterCount();
+        int[] order = new int[arity];
+        for (int k = 0; k < arity; k++)  order[k] = k;
+        order[i] = j; order[j] = i;
+        Class<?>[] types = mh.type().parameterArray();
+        Class<?> ti = types[i]; types[i] = types[j]; types[j] = ti;
+        MethodType swapType = methodType(mh.type().returnType(), types);
+        return permuteArguments(mh, swapType, order);
+    }
+
     /**
      * Makes a method handle that adapts a {@code target} method handle by wrapping it in a {@code try-finally} block.
      * Another method handle, {@code cleanup}, represents the functionality of the {@code finally} block. Any exception
@@ -4885,7 +5622,7 @@
         List<Class<?>> cleanupParamTypes = cleanup.type().parameterList();
         Class<?> rtype = target.type().returnType();
 
-        checkTryFinally(target, cleanup);
+        tryFinallyChecks(target, cleanup);
 
         // Match parameter lists: if the cleanup has a shorter parameter list than the target, add ignored arguments.
         // The cleanup parameter list (minus the leading Throwable and result parameters) must be a sublist of the
@@ -4896,210 +5633,22 @@
         return MethodHandleImpl.makeTryFinally(target.asFixedArity(), cleanup.asFixedArity(), rtype, targetParamTypes);
     }
 
-    /**
-     * Adapts a target method handle by pre-processing some of its arguments, starting at a given position, and then
-     * calling the target with the result of the pre-processing, inserted into the original sequence of arguments just
-     * before the folded arguments.
-     * <p>
-     * This method is closely related to {@link #foldArguments(MethodHandle, MethodHandle)}, but allows to control the
-     * position in the parameter list at which folding takes place. The argument controlling this, {@code pos}, is a
-     * zero-based index. The aforementioned method {@link #foldArguments(MethodHandle, MethodHandle)} assumes position
-     * 0.
-     * <p>
-     * @apiNote Example:
-     * <blockquote><pre>{@code
-    import static java.lang.invoke.MethodHandles.*;
-    import static java.lang.invoke.MethodType.*;
-    ...
-    MethodHandle trace = publicLookup().findVirtual(java.io.PrintStream.class,
-    "println", methodType(void.class, String.class))
-    .bindTo(System.out);
-    MethodHandle cat = lookup().findVirtual(String.class,
-    "concat", methodType(String.class, String.class));
-    assertEquals("boojum", (String) cat.invokeExact("boo", "jum"));
-    MethodHandle catTrace = foldArguments(cat, 1, trace);
-    // also prints "jum":
-    assertEquals("boojum", (String) catTrace.invokeExact("boo", "jum"));
-     * }</pre></blockquote>
-     * <p>Here is pseudocode for the resulting adapter. In the code, {@code T}
-     * represents the result type of the {@code target} and resulting adapter.
-     * {@code V}/{@code v} represent the type and value of the parameter and argument
-     * of {@code target} that precedes the folding position; {@code V} also is
-     * the result type of the {@code combiner}. {@code A}/{@code a} denote the
-     * types and values of the {@code N} parameters and arguments at the folding
-     * position. {@code Z}/{@code z} and {@code B}/{@code b} represent the types
-     * and values of the {@code target} parameters and arguments that precede and
-     * follow the folded parameters and arguments starting at {@code pos},
-     * respectively.
-     * <blockquote><pre>{@code
-     * // there are N arguments in A...
-     * T target(Z..., V, A[N]..., B...);
-     * V combiner(A...);
-     * T adapter(Z... z, A... a, B... b) {
-     *   V v = combiner(a...);
-     *   return target(z..., v, a..., b...);
-     * }
-     * // and if the combiner has a void return:
-     * T target2(Z..., A[N]..., B...);
-     * void combiner2(A...);
-     * T adapter2(Z... z, A... a, B... b) {
-     *   combiner2(a...);
-     *   return target2(z..., a..., b...);
-     * }
-     * }</pre></blockquote>
-     * <p>
-     * <em>Note:</em> The resulting adapter is never a {@linkplain MethodHandle#asVarargsCollector
-     * variable-arity method handle}, even if the original target method handle was.
-     *
-     * @param target the method handle to invoke after arguments are combined
-     * @param pos the position at which to start folding and at which to insert the folding result; if this is {@code
-     *            0}, the effect is the same as for {@link #foldArguments(MethodHandle, MethodHandle)}.
-     * @param combiner method handle to call initially on the incoming arguments
-     * @return method handle which incorporates the specified argument folding logic
-     * @throws NullPointerException if either argument is null
-     * @throws IllegalArgumentException if {@code combiner}'s return type
-     *          is non-void and not the same as the argument type at position {@code pos} of
-     *          the target signature, or if the {@code N} argument types at position {@code pos}
-     *          of the target signature
-     *          (skipping one matching the {@code combiner}'s return type)
-     *          are not identical with the argument types of {@code combiner}
-     *
-     * @see #foldArguments(MethodHandle, MethodHandle)
-     * @since 9
-     */
-    public static MethodHandle foldArguments(MethodHandle target, int pos, MethodHandle combiner) {
-        MethodType targetType = target.type();
-        MethodType combinerType = combiner.type();
-        Class<?> rtype = foldArgumentChecks(pos, targetType, combinerType);
-        BoundMethodHandle result = target.rebind();
-        boolean dropResult = rtype == void.class;
-        LambdaForm lform = result.editor().foldArgumentsForm(1 + pos, dropResult, combinerType.basicType());
-        MethodType newType = targetType;
-        if (!dropResult) {
-            newType = newType.dropParameterTypes(pos, pos + 1);
-        }
-        result = result.copyWithExtendL(newType, lform, combiner);
-        return result;
-    }
-
-    /**
-     * As {@see foldArguments(MethodHandle, int, MethodHandle)}, but with the
-     * added capability of selecting the arguments from the targets parameters
-     * to call the combiner with. This allows us to avoid some simple cases of
-     * permutations and padding the combiner with dropArguments to select the
-     * right argument, which may ultimately produce fewer intermediaries.
-     */
-    static MethodHandle foldArguments(MethodHandle target, int pos, MethodHandle combiner, int ... argPositions) {
-        MethodType targetType = target.type();
-        MethodType combinerType = combiner.type();
-        Class<?> rtype = foldArgumentChecks(pos, targetType, combinerType, argPositions);
-        BoundMethodHandle result = target.rebind();
-        boolean dropResult = rtype == void.class;
-        LambdaForm lform = result.editor().foldArgumentsForm(1 + pos, dropResult, combinerType.basicType(), argPositions);
-        MethodType newType = targetType;
-        if (!dropResult) {
-            newType = newType.dropParameterTypes(pos, pos + 1);
-        }
-        result = result.copyWithExtendL(newType, lform, combiner);
-        return result;
-    }
-
-    private static void checkLoop0(MethodHandle[][] clauses) {
-        if (clauses == null || clauses.length == 0) {
-            throw newIllegalArgumentException("null or no clauses passed");
-        }
-        if (Stream.of(clauses).anyMatch(Objects::isNull)) {
-            throw newIllegalArgumentException("null clauses are not allowed");
-        }
-        if (Stream.of(clauses).anyMatch(c -> c.length > 4)) {
-            throw newIllegalArgumentException("All loop clauses must be represented as MethodHandle arrays with at most 4 elements.");
-        }
-    }
-
-    private static void checkLoop1a(int i, MethodHandle in, MethodHandle st) {
-        if (in.type().returnType() != st.type().returnType()) {
-            throw misMatchedTypes("clause " + i + ": init and step return types", in.type().returnType(),
-                    st.type().returnType());
-        }
-    }
-
-    private static List<Class<?>> buildCommonSuffix(List<MethodHandle> init, List<MethodHandle> step, List<MethodHandle> pred, List<MethodHandle> fini, int cpSize) {
-        final List<Class<?>> empty = List.of();
-        final List<MethodHandle> nonNullInits = init.stream().filter(Objects::nonNull).collect(Collectors.toList());
-        if (nonNullInits.isEmpty()) {
-            final List<Class<?>> longest = Stream.of(step, pred, fini).flatMap(List::stream).filter(Objects::nonNull).
-                    // take only those that can contribute to a common suffix because they are longer than the prefix
-                    map(MethodHandle::type).filter(t -> t.parameterCount() > cpSize).map(MethodType::parameterList).
-                    reduce((p, q) -> p.size() >= q.size() ? p : q).orElse(empty);
-            return longest.size() == 0 ? empty : longest.subList(cpSize, longest.size());
-        } else {
-            return nonNullInits.stream().map(MethodHandle::type).map(MethodType::parameterList).
-                    reduce((p, q) -> p.size() >= q.size() ? p : q).get();
-        }
-    }
-
-    private static void checkLoop1b(List<MethodHandle> init, List<Class<?>> commonSuffix) {
-        if (init.stream().filter(Objects::nonNull).map(MethodHandle::type).map(MethodType::parameterList).
-                anyMatch(pl -> !pl.equals(commonSuffix.subList(0, pl.size())))) {
-            throw newIllegalArgumentException("found non-effectively identical init parameter type lists: " + init +
-                    " (common suffix: " + commonSuffix + ")");
-        }
-    }
-
-    private static void checkLoop1cd(List<MethodHandle> pred, List<MethodHandle> fini, Class<?> loopReturnType) {
-        if (fini.stream().filter(Objects::nonNull).map(MethodHandle::type).map(MethodType::returnType).
-                anyMatch(t -> t != loopReturnType)) {
-            throw newIllegalArgumentException("found non-identical finalizer return types: " + fini + " (return type: " +
-                    loopReturnType + ")");
-        }
-
-        if (!pred.stream().filter(Objects::nonNull).findFirst().isPresent()) {
-            throw newIllegalArgumentException("no predicate found", pred);
-        }
-        if (pred.stream().filter(Objects::nonNull).map(MethodHandle::type).map(MethodType::returnType).
-                anyMatch(t -> t != boolean.class)) {
-            throw newIllegalArgumentException("predicates must have boolean return type", pred);
-        }
-    }
-
-    private static void checkLoop2(List<MethodHandle> step, List<MethodHandle> pred, List<MethodHandle> fini, List<Class<?>> commonParameterSequence) {
-        final int cpSize = commonParameterSequence.size();
-        if (Stream.of(step, pred, fini).flatMap(List::stream).filter(Objects::nonNull).map(MethodHandle::type).
-                map(MethodType::parameterList).
-                anyMatch(pl -> pl.size() > cpSize || !pl.equals(commonParameterSequence.subList(0, pl.size())))) {
-            throw newIllegalArgumentException("found non-effectively identical parameter type lists:\nstep: " + step +
-                    "\npred: " + pred + "\nfini: " + fini + " (common parameter sequence: " + commonParameterSequence + ")");
-        }
-    }
-
-    private static void checkIteratedLoop(MethodHandle iterator, MethodHandle body) {
-        if (null != iterator && !Iterator.class.isAssignableFrom(iterator.type().returnType())) {
-            throw newIllegalArgumentException("iteratedLoop first argument must have Iterator return type");
-        }
-        if (null == body) {
-            throw newIllegalArgumentException("iterated loop body must not be null");
-        }
-    }
-
-    private static void checkTryFinally(MethodHandle target, MethodHandle cleanup) {
+    private static void tryFinallyChecks(MethodHandle target, MethodHandle cleanup) {
         Class<?> rtype = target.type().returnType();
         if (rtype != cleanup.type().returnType()) {
             throw misMatchedTypes("target and return types", cleanup.type().returnType(), rtype);
         }
-        List<Class<?>> cleanupParamTypes = cleanup.type().parameterList();
-        if (!Throwable.class.isAssignableFrom(cleanupParamTypes.get(0))) {
+        MethodType cleanupType = cleanup.type();
+        if (!Throwable.class.isAssignableFrom(cleanupType.parameterType(0))) {
             throw misMatchedTypes("cleanup first argument and Throwable", cleanup.type(), Throwable.class);
         }
-        if (rtype != void.class && cleanupParamTypes.get(1) != rtype) {
+        if (rtype != void.class && cleanupType.parameterType(1) != rtype) {
             throw misMatchedTypes("cleanup second argument and target return type", cleanup.type(), rtype);
         }
         // The cleanup parameter list (minus the leading Throwable and result parameters) must be a sublist of the
         // target parameter list.
         int cleanupArgIndex = rtype == void.class ? 1 : 2;
-        List<Class<?>> cleanupArgSuffix = cleanupParamTypes.subList(cleanupArgIndex, cleanupParamTypes.size());
-        List<Class<?>> targetParamTypes = target.type().parameterList();
-        if (targetParamTypes.size() < cleanupArgSuffix.size() ||
-                !cleanupArgSuffix.equals(targetParamTypes.subList(0, cleanupParamTypes.size() - cleanupArgIndex))) {
+        if (!cleanupType.effectivelyIdenticalParameters(cleanupArgIndex, target.type().parameterList())) {
             throw misMatchedTypes("cleanup parameters after (Throwable,result) and target parameter list prefix",
                     cleanup.type(), target.type());
         }
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodType.java	Wed Oct 05 06:28:22 2016 -0700
@@ -809,6 +809,28 @@
         return sj.toString();
     }
 
+    /** True if my parameter list is effectively identical to the given full list,
+     *  after skipping the given number of my own initial parameters.
+     *  In other words, after disregarding {@code skipPos} parameters,
+     *  my remaining parameter list is no longer than the {@code fullList}, and
+     *  is equal to the same-length initial sublist of {@code fullList}.
+     */
+    /*non-public*/
+    boolean effectivelyIdenticalParameters(int skipPos, List<Class<?>> fullList) {
+        int myLen = ptypes.length, fullLen = fullList.size();
+        if (skipPos > myLen || myLen - skipPos > fullLen)
+            return false;
+        List<Class<?>> myList = Arrays.asList(ptypes);
+        if (skipPos != 0) {
+            myList = myList.subList(skipPos, myLen);
+            myLen -= skipPos;
+        }
+        if (fullLen == myLen)
+            return myList.equals(fullList);
+        else
+            return myList.equals(fullList.subList(0, myLen));
+    }
+
     /** True if the old return type can always be viewed (w/o casting) under new return type,
      *  and the new parameters can be viewed (w/o casting) under the old parameter types.
      */
--- a/jdk/src/java.base/share/classes/java/net/MulticastSocket.java	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/net/MulticastSocket.java	Wed Oct 05 06:28:22 2016 -0700
@@ -93,23 +93,19 @@
     /**
      * Create a multicast socket.
      *
-     * <p>If there is a security manager,
-     * its {@code checkListen} method is first called
-     * with 0 as its argument to ensure the operation is allowed.
-     * This could result in a SecurityException.
+     * <p>
+     * If there is a security manager, its {@code checkListen} method is first
+     * called with 0 as its argument to ensure the operation is allowed. This
+     * could result in a SecurityException.
      * <p>
      * When the socket is created the
-     * {@link DatagramSocket#setReuseAddress(boolean)} method is
-     * called to enable the SO_REUSEADDR socket option. When
-     * {@link StandardSocketOptions#SO_REUSEPORT SO_REUSEPORT} is
-     * supported then
-     * {@link DatagramSocketImpl#setOption(SocketOption, Object)}
-     * is called to enable the socket option.
+     * {@link DatagramSocket#setReuseAddress(boolean)} method is called to
+     * enable the SO_REUSEADDR socket option.
      *
-     * @exception IOException if an I/O exception occurs
-     * while creating the MulticastSocket
-     * @exception  SecurityException  if a security manager exists and its
-     *             {@code checkListen} method doesn't allow the operation.
+     * @exception IOException if an I/O exception occurs while creating the
+     * MulticastSocket
+     * @exception SecurityException if a security manager exists and its
+     * {@code checkListen} method doesn't allow the operation.
      * @see SecurityManager#checkListen
      * @see java.net.DatagramSocket#setReuseAddress(boolean)
      * @see java.net.DatagramSocketImpl#setOption(SocketOption, Object)
@@ -174,17 +170,13 @@
         // Enable SO_REUSEADDR before binding
         setReuseAddress(true);
 
-        // Enable SO_REUSEPORT if supported before binding
-        if (supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
-            this.setOption(StandardSocketOptions.SO_REUSEPORT, true);
-        }
-
         if (bindaddr != null) {
             try {
                 bind(bindaddr);
             } finally {
-                if (!isBound())
+                if (!isBound()) {
                     close();
+                }
             }
         }
     }
--- a/jdk/src/java.base/share/classes/java/text/DecimalFormat.java	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/text/DecimalFormat.java	Wed Oct 05 06:28:22 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -968,7 +968,7 @@
      *     Decimal  : min = 0. max = 3.
      *
      */
-    private void checkAndSetFastPathStatus() {
+    private boolean checkAndSetFastPathStatus() {
 
         boolean fastPathWasOn = isFastPath;
 
@@ -998,12 +998,27 @@
         } else
             isFastPath = false;
 
+        resetFastPathData(fastPathWasOn);
+        fastPathCheckNeeded = false;
+
+        /*
+         * Returns true after successfully checking the fast path condition and
+         * setting the fast path data. The return value is used by the
+         * fastFormat() method to decide whether to call the resetFastPathData
+         * method to reinitialize fast path data or is it already initialized
+         * in this method.
+         */
+        return true;
+    }
+
+    private void resetFastPathData(boolean fastPathWasOn) {
         // Since some instance properties may have changed while still falling
         // in the fast-path case, we need to reinitialize fastPathData anyway.
         if (isFastPath) {
             // We need to instantiate fastPathData if not already done.
-            if (fastPathData == null)
+            if (fastPathData == null) {
                 fastPathData = new FastPathData();
+            }
 
             // Sets up the locale specific constants used when formatting.
             // '0' is our default representation of zero.
@@ -1011,22 +1026,27 @@
             fastPathData.groupingChar = symbols.getGroupingSeparator();
 
             // Sets up fractional constants related to currency/decimal pattern.
-            fastPathData.fractionalMaxIntBound = (isCurrencyFormat) ? 99 : 999;
-            fastPathData.fractionalScaleFactor = (isCurrencyFormat) ? 100.0d : 1000.0d;
+            fastPathData.fractionalMaxIntBound = (isCurrencyFormat)
+                    ? 99 : 999;
+            fastPathData.fractionalScaleFactor = (isCurrencyFormat)
+                    ? 100.0d : 1000.0d;
 
             // Records the need for adding prefix or suffix
-            fastPathData.positiveAffixesRequired =
-                (positivePrefix.length() != 0) || (positiveSuffix.length() != 0);
-            fastPathData.negativeAffixesRequired =
-                (negativePrefix.length() != 0) || (negativeSuffix.length() != 0);
+            fastPathData.positiveAffixesRequired
+                    = (positivePrefix.length() != 0)
+                        || (positiveSuffix.length() != 0);
+            fastPathData.negativeAffixesRequired
+                    = (negativePrefix.length() != 0)
+                        || (negativeSuffix.length() != 0);
 
             // Creates a cached char container for result, with max possible size.
             int maxNbIntegralDigits = 10;
             int maxNbGroups = 3;
-            int containerSize =
-                Math.max(positivePrefix.length(), negativePrefix.length()) +
-                maxNbIntegralDigits + maxNbGroups + 1 + maximumFractionDigits +
-                Math.max(positiveSuffix.length(), negativeSuffix.length());
+            int containerSize
+                    = Math.max(positivePrefix.length(), negativePrefix.length())
+                    + maxNbIntegralDigits + maxNbGroups + 1
+                    + maximumFractionDigits
+                    + Math.max(positiveSuffix.length(), negativeSuffix.length());
 
             fastPathData.fastPathContainer = new char[containerSize];
 
@@ -1038,17 +1058,18 @@
 
             // Sets up fixed index positions for integral and fractional digits.
             // Sets up decimal point in cached result container.
-            int longestPrefixLength =
-                Math.max(positivePrefix.length(), negativePrefix.length());
-            int decimalPointIndex =
-                maxNbIntegralDigits + maxNbGroups + longestPrefixLength;
-
-            fastPathData.integralLastIndex    = decimalPointIndex - 1;
+            int longestPrefixLength
+                    = Math.max(positivePrefix.length(),
+                            negativePrefix.length());
+            int decimalPointIndex
+                    = maxNbIntegralDigits + maxNbGroups + longestPrefixLength;
+
+            fastPathData.integralLastIndex = decimalPointIndex - 1;
             fastPathData.fractionalFirstIndex = decimalPointIndex + 1;
-            fastPathData.fastPathContainer[decimalPointIndex] =
-                isCurrencyFormat ?
-                symbols.getMonetaryDecimalSeparator() :
-                symbols.getDecimalSeparator();
+            fastPathData.fastPathContainer[decimalPointIndex]
+                    = isCurrencyFormat
+                            ? symbols.getMonetaryDecimalSeparator()
+                            : symbols.getDecimalSeparator();
 
         } else if (fastPathWasOn) {
             // Previous state was fast-path and is no more.
@@ -1059,8 +1080,6 @@
             fastPathData.charsPositivePrefix = null;
             fastPathData.charsNegativePrefix = null;
         }
-
-        fastPathCheckNeeded = false;
     }
 
     /**
@@ -1554,9 +1573,11 @@
      * @return the formatted result for {@code d} as a string.
      */
     String fastFormat(double d) {
+        boolean isDataSet = false;
         // (Re-)Evaluates fast-path status if needed.
-        if (fastPathCheckNeeded)
-            checkAndSetFastPathStatus();
+        if (fastPathCheckNeeded) {
+            isDataSet = checkAndSetFastPathStatus();
+        }
 
         if (!isFastPath )
             // DecimalFormat instance is not in a fast-path state.
@@ -1580,9 +1601,21 @@
         if (d > MAX_INT_AS_DOUBLE)
             // Filters out values that are outside expected fast-path range
             return null;
-        else
+        else {
+            if (!isDataSet) {
+                /*
+                 * If the fast path data is not set through
+                 * checkAndSetFastPathStatus() and fulfil the
+                 * fast path conditions then reset the data
+                 * directly through resetFastPathData()
+                 */
+                resetFastPathData(isFastPath);
+            }
             fastDoubleFormat(d, negative);
 
+        }
+
+
         // Returns a new string from updated fastPathContainer.
         return new String(fastPathData.fastPathContainer,
                           fastPathData.firstUsedIndex,
--- a/jdk/src/java.base/share/classes/java/util/ArrayList.java	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/ArrayList.java	Wed Oct 05 06:28:22 2016 -0700
@@ -876,6 +876,8 @@
         int lastRet = -1; // index of last element returned; -1 if no such
         int expectedModCount = modCount;
 
+        Itr() {}
+
         public boolean hasNext() {
             return cursor != size;
         }
--- a/jdk/src/java.base/share/classes/java/util/Locale.java	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/Locale.java	Wed Oct 05 06:28:22 2016 -0700
@@ -1027,7 +1027,7 @@
      * not contain ALL valid codes that can be used to create Locales.
      * </ul>
      *
-     * @return Am array of ISO 639 two-letter language codes.
+     * @return An array of ISO 639 two-letter language codes.
      */
     public static String[] getISOLanguages() {
         if (isoLanguages == null) {
--- a/jdk/src/java.base/share/classes/sun/security/rsa/RSASignature.java	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/rsa/RSASignature.java	Wed Oct 05 06:28:22 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -182,14 +182,15 @@
     }
 
     // verify the data and return the result. See JCA doc
+    // should be reset to the state after engineInitVerify call.
     protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
-        if (sigBytes.length != RSACore.getByteLength(publicKey)) {
-            throw new SignatureException("Signature length not correct: got " +
+        try {
+            if (sigBytes.length != RSACore.getByteLength(publicKey)) {
+                throw new SignatureException("Signature length not correct: got " +
                     sigBytes.length + " but was expecting " +
                     RSACore.getByteLength(publicKey));
-        }
-        byte[] digest = getDigestValue();
-        try {
+            }
+            byte[] digest = getDigestValue();
             byte[] decrypted = RSACore.rsa(sigBytes, publicKey);
             byte[] unpadded = padding.unpad(decrypted);
             byte[] decodedDigest = decodeSignature(digestOID, unpadded);
@@ -202,6 +203,8 @@
             return false;
         } catch (IOException e) {
             throw new SignatureException("Signature encoding error", e);
+        } finally {
+            resetDigest();
         }
     }
 
--- a/jdk/src/java.base/share/conf/security/java.security	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.base/share/conf/security/java.security	Wed Oct 05 06:28:22 2016 -0700
@@ -894,3 +894,44 @@
     disallowReferenceUriSchemes file http https,\
     noDuplicateIds,\
     noRetrievalMethodLoops
+
+#
+# Serialization process-wide filter
+#
+# A filter, if configured, is used by java.io.ObjectInputStream during
+# deserialization to check the contents of the stream.
+# A filter is configured as a sequence of patterns, each pattern is either
+# matched against the name of a class in the stream or defines a limit.
+# Patterns are separated by ";" (semicolon).
+# Whitespace is significant and is considered part of the pattern.
+#
+# If a pattern includes a "=", it sets a limit.
+# If a limit appears more than once the last value is used.
+# Limits are checked before classes regardless of the order in the sequence of patterns.
+# If any of the limits are exceeded, the filter status is REJECTED.
+#
+#   maxdepth=value - the maximum depth of a graph
+#   maxrefs=value  - the maximum number of internal references
+#   maxbytes=value - the maximum number of bytes in the input stream
+#   maxarray=value - the maximum array length allowed
+#
+# Other patterns, from left to right, match the class or package name as
+# returned from Class.getName.
+# If the class is an array type, the class or package to be matched is the element type.
+# Arrays of any number of dimensions are treated the same as the element type.
+# For example, a pattern of "!example.Foo", rejects creation of any instance or
+# array of example.Foo.
+#
+# If the pattern starts with "!", the status is REJECTED if the remaining pattern
+#   is matched; otherwise the status is ALLOWED if the pattern matches.
+# If the pattern contains "/", the non-empty prefix up to the "/" is the module name;
+#   if the module name matches the module name of the class then
+#   the remaining pattern is matched with the class name.
+#   If there is no "/", the module name is not compared.
+# If the pattern ends with ".**" it matches any class in the package and all subpackages.
+# If the pattern ends with ".*" it matches any class in the package.
+# If the pattern ends with "*", it matches any class with the pattern as a prefix.
+# If the pattern is equal to the class name, it matches.
+# Otherwise, the status is UNDECIDED.
+#
+#jdk.serialFilter=pattern;pattern
--- a/jdk/src/java.base/unix/classes/sun/nio/fs/UnixDirectoryStream.java	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.base/unix/classes/sun/nio/fs/UnixDirectoryStream.java	Wed Oct 05 06:28:22 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -116,7 +116,7 @@
         synchronized (this) {
             if (iterator != null)
                 throw new IllegalStateException("Iterator already obtained");
-            iterator = new UnixDirectoryIterator(ds);
+            iterator = new UnixDirectoryIterator();
             return iterator;
         }
     }
@@ -130,17 +130,14 @@
      * Iterator implementation
      */
     private class UnixDirectoryIterator implements Iterator<Path> {
-        private final DirectoryStream<Path> stream;
-
         // true when at EOF
         private boolean atEof;
 
         // next entry to return
         private Path nextEntry;
 
-        UnixDirectoryIterator(DirectoryStream<Path> stream) {
+        UnixDirectoryIterator() {
             atEof = false;
-            this.stream = stream;
         }
 
         // Return true if file name is "." or ".."
--- a/jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c	Wed Oct 05 06:28:22 2016 -0700
@@ -1302,7 +1302,7 @@
  * Sets the multicast loopback mode.
  */
 static void setMulticastLoopbackMode(JNIEnv *env, jobject this, int fd,
-                                  jint opt, jobject value) {
+                                     jint opt, jobject value) {
 #ifdef AF_INET6
 #ifdef __linux__
     mcast_set_loop_v4(env, this, fd, value);
@@ -1330,10 +1330,9 @@
  * Signature: (ILjava/lang/Object;)V
  */
 JNIEXPORT void JNICALL
-Java_java_net_PlainDatagramSocketImpl_socketSetOption0(JNIEnv *env,
-                                                      jobject this,
-                                                      jint opt,
-                                                      jobject value) {
+Java_java_net_PlainDatagramSocketImpl_socketSetOption0
+  (JNIEnv *env, jobject this, jint opt, jobject value)
+{
     int fd;
     int level, optname, optlen;
     int optval;
@@ -1380,7 +1379,7 @@
      * level and option name.
      */
     if (NET_MapSocketOption(opt, &level, &optname)) {
-        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
+        JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
         return;
     }
 
@@ -1699,8 +1698,9 @@
  * Signature: (I)Ljava/lang/Object;
  */
 JNIEXPORT jobject JNICALL
-Java_java_net_PlainDatagramSocketImpl_socketGetOption(JNIEnv *env, jobject this,
-                                                      jint opt) {
+Java_java_net_PlainDatagramSocketImpl_socketGetOption
+  (JNIEnv *env, jobject this, jint opt)
+{
     int fd;
     int level, optname, optlen;
     union {
@@ -1751,7 +1751,7 @@
      * level and option name.
      */
     if (NET_MapSocketOption(opt, &level, &optname)) {
-        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
+        JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
         return NULL;
     }
 
--- a/jdk/src/java.base/unix/native/libnet/PlainSocketImpl.c	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.base/unix/native/libnet/PlainSocketImpl.c	Wed Oct 05 06:28:22 2016 -0700
@@ -855,9 +855,9 @@
  * Signature: (IZLjava/lang/Object;)V
  */
 JNIEXPORT void JNICALL
-Java_java_net_PlainSocketImpl_socketSetOption0(JNIEnv *env, jobject this,
-                                              jint cmd, jboolean on,
-                                              jobject value) {
+Java_java_net_PlainSocketImpl_socketSetOption0
+  (JNIEnv *env, jobject this, jint cmd, jboolean on, jobject value)
+{
     int fd;
     int level, optname, optlen;
     union {
@@ -887,7 +887,7 @@
      * level and option name.
      */
     if (NET_MapSocketOption(cmd, &level, &optname)) {
-        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
+        JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
         return;
     }
 
@@ -951,9 +951,9 @@
  * Signature: (I)I
  */
 JNIEXPORT jint JNICALL
-Java_java_net_PlainSocketImpl_socketGetOption(JNIEnv *env, jobject this,
-                                              jint cmd, jobject iaContainerObj) {
-
+Java_java_net_PlainSocketImpl_socketGetOption
+  (JNIEnv *env, jobject this, jint cmd, jobject iaContainerObj)
+{
     int fd;
     int level, optname, optlen;
     union {
@@ -1004,7 +1004,7 @@
      * level and option name.
      */
     if (NET_MapSocketOption(cmd, &level, &optname)) {
-        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
+        JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
         return -1;
     }
 
--- a/jdk/src/java.base/unix/native/libnet/SocketInputStream.c	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.base/unix/native/libnet/SocketInputStream.c	Wed Oct 05 06:28:22 2016 -0700
@@ -58,15 +58,15 @@
         result = NET_TimeoutWithCurrentTime(fd, timeout, prevtime);
         if (result <= 0) {
             if (result == 0) {
-                JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException", "Read timed out");
+                JNU_ThrowByName(env, "java/net/SocketTimeoutException", "Read timed out");
             } else if (result == -1) {
                 if (errno == EBADF) {
-                    JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Socket closed");
+                    JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
                 } else if (errno == ENOMEM) {
                     JNU_ThrowOutOfMemoryError(env, "NET_Timeout native heap allocation failed");
                 } else {
                     JNU_ThrowByNameWithMessageAndLastError
-                            (env, JNU_JAVANETPKG "SocketException", "select/poll failed");
+                            (env, "java/net/SocketException", "select/poll failed");
                 }
             }
             return -1;
@@ -100,19 +100,14 @@
     jint fd, nread;
 
     if (IS_NULL(fdObj)) {
-        /* shouldn't this be a NullPointerException? -br */
-        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+        JNU_ThrowByName(env, "java/net/SocketException",
                         "Socket closed");
         return -1;
-    } else {
-        fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
-        /* Bug 4086704 - If the Socket associated with this file descriptor
-         * was closed (sysCloseFD), then the file descriptor is set to -1.
-         */
-        if (fd == -1) {
-            JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
-            return -1;
-        }
+    }
+    fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
+    if (fd == -1) {
+        JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
+        return -1;
     }
 
     /*
@@ -154,17 +149,17 @@
                     break;
 
                 case EBADF:
-                    JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+                    JNU_ThrowByName(env, "java/net/SocketException",
                         "Socket closed");
                     break;
 
                 case EINTR:
-                     JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
+                     JNU_ThrowByName(env, "java/io/InterruptedIOException",
                            "Operation interrupted");
                      break;
                 default:
                     JNU_ThrowByNameWithMessageAndLastError
-                        (env, JNU_JAVANETPKG "SocketException", "Read failed");
+                        (env, "java/net/SocketException", "Read failed");
             }
         }
     } else {
--- a/jdk/src/java.base/unix/native/libnio/ch/NativeThread.c	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.base/unix/native/libnio/ch/NativeThread.c	Wed Oct 05 06:28:22 2016 -0700
@@ -37,6 +37,11 @@
   #include <sys/signal.h>
   /* Also defined in net/linux_close.c */
   #define INTERRUPT_SIGNAL (__SIGRTMAX - 2)
+#elif _AIX
+  #include <pthread.h>
+  #include <sys/signal.h>
+  /* Also defined in net/aix_close.c */
+  #define INTERRUPT_SIGNAL (SIGRTMAX - 1)
 #elif __solaris__
   #include <thread.h>
   #include <signal.h>
@@ -59,7 +64,7 @@
 Java_sun_nio_ch_NativeThread_init(JNIEnv *env, jclass cl)
 {
     /* Install the null handler for INTERRUPT_SIGNAL.  This might overwrite the
-     * handler previously installed by java/net/linux_close.c, but that's okay
+     * handler previously installed by <platform>_close.c, but that's okay
      * since neither handler actually does anything.  We install our own
      * handler here simply out of paranoia; ultimately the two mechanisms
      * should somehow be unified, perhaps within the VM.
--- a/jdk/src/java.base/windows/native/libnet/DualStackPlainDatagramSocketImpl.c	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.base/windows/native/libnet/DualStackPlainDatagramSocketImpl.c	Wed Oct 05 06:28:22 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -475,13 +475,14 @@
  * Method:    socketSetIntOption
  * Signature: (III)V
  */
-JNIEXPORT void JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketSetIntOption
-  (JNIEnv *env, jclass clazz, jint fd , jint cmd, jint value) {
+JNIEXPORT void JNICALL
+Java_java_net_DualStackPlainDatagramSocketImpl_socketSetIntOption
+  (JNIEnv *env, jclass clazz, jint fd, jint cmd, jint value)
+{
     int level = 0, opt = 0;
 
     if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
-        JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
-                                     "Invalid option");
+        JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
         return;
     }
 
@@ -495,14 +496,15 @@
  * Method:    socketGetIntOption
  * Signature: (II)I
  */
-JNIEXPORT jint JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_socketGetIntOption
-  (JNIEnv *env, jclass clazz, jint fd, jint cmd) {
-    int level = 0, opt = 0, result=0;
+JNIEXPORT jint JNICALL
+Java_java_net_DualStackPlainDatagramSocketImpl_socketGetIntOption
+  (JNIEnv *env, jclass clazz, jint fd, jint cmd)
+{
+    int level = 0, opt = 0, result = 0;
     int result_len = sizeof(result);
 
     if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
-        JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
-                                     "Invalid option");
+        JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
         return -1;
     }
 
@@ -519,8 +521,10 @@
  * Method:    dataAvailable
  * Signature: ()I
  */
-JNIEXPORT jint JNICALL Java_java_net_DualStackPlainDatagramSocketImpl_dataAvailable
-(JNIEnv *env, jobject this) {
+JNIEXPORT jint JNICALL
+Java_java_net_DualStackPlainDatagramSocketImpl_dataAvailable
+  (JNIEnv *env, jobject this)
+{
     SOCKET fd;
     int  rv = -1;
     jobject fdObj = (*env)->GetObjectField(env, this, pdsi_fdID);
--- a/jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c	Wed Oct 05 06:28:22 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -369,18 +369,17 @@
  * Method:    setIntOption
  * Signature: (III)V
  */
-JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_setIntOption
-  (JNIEnv *env, jclass clazz, jint fd, jint cmd, jint value) {
-
+JNIEXPORT void JNICALL
+Java_java_net_DualStackPlainSocketImpl_setIntOption
+  (JNIEnv *env, jclass clazz, jint fd, jint cmd, jint value)
+{
     int level = 0, opt = 0;
     struct linger linger = {0, 0};
     char *parg;
     int arglen;
 
     if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
-        JNU_ThrowByNameWithLastError(env,
-                                     JNU_JAVANETPKG "SocketException",
-                                     "Invalid option");
+        JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
         return;
     }
 
@@ -410,8 +409,8 @@
  * Signature: (II)I
  */
 JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_getIntOption
-  (JNIEnv *env, jclass clazz, jint fd, jint cmd) {
-
+  (JNIEnv *env, jclass clazz, jint fd, jint cmd)
+{
     int level = 0, opt = 0;
     int result=0;
     struct linger linger = {0, 0};
@@ -419,9 +418,7 @@
     int arglen;
 
     if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
-        JNU_ThrowByNameWithLastError(env,
-                                     JNU_JAVANETPKG "SocketException",
-                                     "Unsupported socket option");
+        JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
         return -1;
     }
 
--- a/jdk/src/java.base/windows/native/libnet/SocketInputStream.c	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.base/windows/native/libnet/SocketInputStream.c	Wed Oct 05 06:28:22 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -62,18 +62,18 @@
                                             jobject fdObj, jbyteArray data,
                                             jint off, jint len, jint timeout)
 {
+    char BUF[MAX_BUFFER_LEN];
     char *bufP;
-    char BUF[MAX_BUFFER_LEN];
-    jint fd, newfd;
-    jint nread;
+    jint fd, newfd, nread;
 
     if (IS_NULL(fdObj)) {
-        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
+        JNU_ThrowByName(env, "java/net/SocketException",
+                        "Socket closed");
         return -1;
     }
     fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
     if (fd == -1) {
-        NET_ThrowSocketException(env, "Socket closed");
+        JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
         return -1;
     }
 
@@ -103,10 +103,10 @@
 
             if (ret <= 0) {
                 if (ret == 0) {
-                    JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
+                    JNU_ThrowByName(env, "java/net/SocketTimeoutException",
                                     "Read timed out");
                 } else if (ret == -1) {
-                    JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
+                    JNU_ThrowByName(env, "java/net/SocketException", "socket closed");
                 }
                 if (bufP != BUF) {
                     free(bufP);
@@ -117,7 +117,7 @@
             /*check if the socket has been closed while we were in timeout*/
             newfd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
             if (newfd == -1) {
-                NET_ThrowSocketException(env, "Socket Closed");
+                JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
                 if (bufP != BUF) {
                     free(bufP);
                 }
@@ -134,11 +134,11 @@
             // Check if the socket has been closed since we last checked.
             // This could be a reason for recv failing.
             if ((*env)->GetIntField(env, fdObj, IO_fd_fdID) == -1) {
-                NET_ThrowSocketException(env, "Socket closed");
+                JNU_ThrowByName(env, "java/net/SocketException", "Socket closed");
             } else {
                 switch (WSAGetLastError()) {
                     case WSAEINTR:
-                        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+                        JNU_ThrowByName(env, "java/net/SocketException",
                             "socket closed");
                         break;
 
@@ -153,7 +153,7 @@
                         break;
 
                     case WSAETIMEDOUT :
-                        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
+                        JNU_ThrowByName(env, "java/net/SocketTimeoutException",
                                        "Read timed out");
                         break;
 
--- a/jdk/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.base/windows/native/libnet/TwoStacksPlainDatagramSocketImpl.c	Wed Oct 05 06:28:22 2016 -0700
@@ -1795,9 +1795,9 @@
  * Signature: (ILjava/lang/Object;)V
  */
 JNIEXPORT void JNICALL
-Java_java_net_TwoStacksPlainDatagramSocketImpl_socketNativeSetOption(JNIEnv *env,jobject this,
-                                                      jint opt,jobject value) {
-
+Java_java_net_TwoStacksPlainDatagramSocketImpl_socketNativeSetOption
+  (JNIEnv *env,jobject this, jint opt,jobject value)
+{
     int fd=-1, fd1=-1;
     int levelv4 = 0, levelv6 = 0, optnamev4 = 0, optnamev6 = 0, optlen = 0;
     union {
@@ -1828,13 +1828,13 @@
      */
     if (fd1 != -1) {
         if (NET_MapSocketOptionV6(opt, &levelv6, &optnamev6)) {
-            JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
+            JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
             return;
         }
     }
     if (fd != -1) {
         if (NET_MapSocketOption(opt, &levelv4, &optnamev4)) {
-            JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
+            JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
             return;
         }
     }
@@ -2163,9 +2163,9 @@
  * Signature: (I)Ljava/lang/Object;
  */
 JNIEXPORT jobject JNICALL
-Java_java_net_TwoStacksPlainDatagramSocketImpl_socketGetOption(JNIEnv *env, jobject this,
-                                                      jint opt) {
-
+Java_java_net_TwoStacksPlainDatagramSocketImpl_socketGetOption
+  (JNIEnv *env, jobject this, jint opt)
+{
     int fd=-1, fd1=-1;
     int level, optname, optlen;
     union {
@@ -2197,13 +2197,13 @@
      * level and option name.
      */
     if (NET_MapSocketOption(opt, &level, &optname)) {
-        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
+        JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
         return NULL;
     }
 
     if (fd == -1) {
         if (NET_MapSocketOptionV6(opt, &level, &optname)) {
-            JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
+            JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
             return NULL;
         }
         fd = fd1; /* must be IPv6 only */
--- a/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c	Wed Oct 05 06:28:22 2016 -0700
@@ -838,10 +838,9 @@
  * Signature: (IZLjava/lang/Object;)V
  */
 JNIEXPORT void JNICALL
-Java_java_net_TwoStacksPlainSocketImpl_socketNativeSetOption(JNIEnv *env,
-                                              jobject this,
-                                              jint cmd, jboolean on,
-                                              jobject value) {
+Java_java_net_TwoStacksPlainSocketImpl_socketNativeSetOption
+  (JNIEnv *env, jobject this, jint cmd, jboolean on, jobject value)
+{
     int fd, fd1;
     int level = 0, optname = 0, optlen = 0;
     union {
@@ -923,11 +922,10 @@
 
     /*
      * Map the Java level socket option to the platform specific
-     * level
+     * level and option name.
      */
     if (NET_MapSocketOption(cmd, &level, &optname)) {
-        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
-                        "Invalid option");
+        JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
         return;
     }
 
@@ -1006,15 +1004,16 @@
  * Signature: (I)I
  */
 JNIEXPORT jint JNICALL
-Java_java_net_TwoStacksPlainSocketImpl_socketGetOption(JNIEnv *env, jobject this,
-                                              jint opt, jobject iaContainerObj) {
-
+Java_java_net_TwoStacksPlainSocketImpl_socketGetOption
+  (JNIEnv *env, jobject this, jint opt, jobject iaContainerObj)
+{
     int fd, fd1;
     int level = 0, optname = 0, optlen = 0;
     union {
         int i;
         struct linger ling;
     } optval;
+
     /*
      * Get SOCKET and check it hasn't been closed
      */
@@ -1073,7 +1072,7 @@
      * level and option name.
      */
     if (NET_MapSocketOption(opt, &level, &optname)) {
-        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Invalid option");
+        JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
         return -1;
     }
 
--- a/jdk/src/java.base/windows/native/libnet/net_util_md.c	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.base/windows/native/libnet/net_util_md.c	Wed Oct 05 06:28:22 2016 -0700
@@ -203,19 +203,6 @@
 }
 
 void
-NET_ThrowSocketException(JNIEnv *env, char* msg)
-{
-    static jclass cls = NULL;
-    if (cls == NULL) {
-        cls = (*env)->FindClass(env, "java/net/SocketException");
-        CHECK_NULL(cls);
-        cls = (*env)->NewGlobalRef(env, cls);
-        CHECK_NULL(cls);
-    }
-    (*env)->ThrowNew(env, cls, msg);
-}
-
-void
 NET_ThrowByNameWithLastError(JNIEnv *env, const char *name,
                    const char *defaultDetail) {
     char errmsg[255];
--- a/jdk/src/java.base/windows/native/libnet/net_util_md.h	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.base/windows/native/libnet/net_util_md.h	Wed Oct 05 06:28:22 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -299,8 +299,6 @@
 void NET_ThrowByNameWithLastError(JNIEnv *env, const char *name,
          const char *defaultDetail);
 
-void NET_ThrowSocketException(JNIEnv *env, char* msg);
-
 /*
  * differs from NET_Timeout() as follows:
  *
--- a/jdk/src/java.desktop/share/classes/java/beans/MetaData.java	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/java/beans/MetaData.java	Wed Oct 05 06:28:22 2016 -0700
@@ -510,102 +510,6 @@
             return new Expression(oldInstance, Collections.class, "synchronizedSortedMap", new Object[]{map});
         }
     }
-
-    static final class CheckedCollection_PersistenceDelegate extends java_util_Collections {
-        protected Expression instantiate(Object oldInstance, Encoder out) {
-            Object type = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedCollection.type");
-            List<?> list = new ArrayList<>((Collection<?>) oldInstance);
-            return new Expression(oldInstance, Collections.class, "checkedCollection", new Object[]{list, type});
-        }
-    }
-
-    static final class CheckedList_PersistenceDelegate extends java_util_Collections {
-        protected Expression instantiate(Object oldInstance, Encoder out) {
-            Object type = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedCollection.type");
-            List<?> list = new LinkedList<>((Collection<?>) oldInstance);
-            return new Expression(oldInstance, Collections.class, "checkedList", new Object[]{list, type});
-        }
-    }
-
-    static final class CheckedRandomAccessList_PersistenceDelegate extends java_util_Collections {
-        protected Expression instantiate(Object oldInstance, Encoder out) {
-            Object type = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedCollection.type");
-            List<?> list = new ArrayList<>((Collection<?>) oldInstance);
-            return new Expression(oldInstance, Collections.class, "checkedList", new Object[]{list, type});
-        }
-    }
-
-    static final class CheckedSet_PersistenceDelegate extends java_util_Collections {
-        protected Expression instantiate(Object oldInstance, Encoder out) {
-            Object type = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedCollection.type");
-            Set<?> set = new HashSet<>((Set<?>) oldInstance);
-            return new Expression(oldInstance, Collections.class, "checkedSet", new Object[]{set, type});
-        }
-    }
-
-    static final class CheckedSortedSet_PersistenceDelegate extends java_util_Collections {
-        protected Expression instantiate(Object oldInstance, Encoder out) {
-            Object type = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedCollection.type");
-            SortedSet<?> set = new TreeSet<>((SortedSet<?>) oldInstance);
-            return new Expression(oldInstance, Collections.class, "checkedSortedSet", new Object[]{set, type});
-        }
-    }
-
-    static final class CheckedMap_PersistenceDelegate extends java_util_Collections {
-        protected Expression instantiate(Object oldInstance, Encoder out) {
-            Object keyType   = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedMap.keyType");
-            Object valueType = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedMap.valueType");
-            Map<?,?> map = new HashMap<>((Map<?,?>) oldInstance);
-            return new Expression(oldInstance, Collections.class, "checkedMap", new Object[]{map, keyType, valueType});
-        }
-    }
-
-    static final class CheckedSortedMap_PersistenceDelegate extends java_util_Collections {
-        protected Expression instantiate(Object oldInstance, Encoder out) {
-            Object keyType   = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedMap.keyType");
-            Object valueType = MetaData.getPrivateFieldValue(oldInstance, "java.util.Collections$CheckedMap.valueType");
-            SortedMap<?,?> map = new TreeMap<>((SortedMap<?,?>) oldInstance);
-            return new Expression(oldInstance, Collections.class, "checkedSortedMap", new Object[]{map, keyType, valueType});
-        }
-    }
-}
-
-/**
- * The persistence delegate for {@code java.util.EnumMap} classes.
- *
- * @author Sergey A. Malenkov
- */
-static final class java_util_EnumMap_PersistenceDelegate extends PersistenceDelegate {
-    protected boolean mutatesTo(Object oldInstance, Object newInstance) {
-        return super.mutatesTo(oldInstance, newInstance) && (getType(oldInstance) == getType(newInstance));
-    }
-
-    protected Expression instantiate(Object oldInstance, Encoder out) {
-        return new Expression(oldInstance, EnumMap.class, "new", new Object[] {getType(oldInstance)});
-    }
-
-    private static Object getType(Object instance) {
-        return MetaData.getPrivateFieldValue(instance, "java.util.EnumMap.keyType");
-    }
-}
-
-/**
- * The persistence delegate for {@code java.util.EnumSet} classes.
- *
- * @author Sergey A. Malenkov
- */
-static final class java_util_EnumSet_PersistenceDelegate extends PersistenceDelegate {
-    protected boolean mutatesTo(Object oldInstance, Object newInstance) {
-        return super.mutatesTo(oldInstance, newInstance) && (getType(oldInstance) == getType(newInstance));
-    }
-
-    protected Expression instantiate(Object oldInstance, Encoder out) {
-        return new Expression(oldInstance, EnumSet.class, "noneOf", new Object[] {getType(oldInstance)});
-    }
-
-    private static Object getType(Object instance) {
-        return MetaData.getPrivateFieldValue(instance, "java.util.EnumSet.elementType");
-    }
 }
 
 // Collection
@@ -1313,9 +1217,6 @@
 
         internalPersistenceDelegates.put("java.sql.Date", new java_util_Date_PersistenceDelegate());
         internalPersistenceDelegates.put("java.sql.Time", new java_util_Date_PersistenceDelegate());
-
-        internalPersistenceDelegates.put("java.util.JumboEnumSet", new java_util_EnumSet_PersistenceDelegate());
-        internalPersistenceDelegates.put("java.util.RegularEnumSet", new java_util_EnumSet_PersistenceDelegate());
     }
 
     @SuppressWarnings("rawtypes")
--- a/jdk/src/java.rmi/share/classes/java/rmi/server/UnicastRemoteObject.java	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.rmi/share/classes/java/rmi/server/UnicastRemoteObject.java	Wed Oct 05 06:28:22 2016 -0700
@@ -24,9 +24,11 @@
  */
 package java.rmi.server;
 
+import java.io.ObjectInputFilter;
 import java.rmi.*;
 import sun.rmi.server.UnicastServerRef;
 import sun.rmi.server.UnicastServerRef2;
+import sun.rmi.transport.LiveRef;
 
 /**
  * Used for exporting a remote object with JRMP and obtaining a stub
@@ -38,11 +40,11 @@
  * generated stubs is deprecated. This includes the API in this class that
  * requires the use of static stubs, as well as the runtime support for
  * loading static stubs.  Generating stubs dynamically is preferred, using one
- * of the five non-deprecated ways of exporting objects as listed below. Do
+ * of the non-deprecated ways of exporting objects as listed below. Do
  * not run {@code rmic} to generate static stub classes. It is unnecessary, and
  * it is also deprecated.</em>
  *
- * <p>There are six ways to export remote objects:
+ * <p>There are eight ways to export remote objects:
  *
  * <ol>
  *
@@ -67,12 +69,19 @@
  * {@link #exportObject(Remote, int, RMIClientSocketFactory, RMIServerSocketFactory)
  * exportObject(Remote, port, csf, ssf)} method.
  *
+ * <li>Calling the
+ * {@link #exportObject(Remote, int, ObjectInputFilter) exportObject(Remote, port, filter)} method.
+ *
+ * <li>Calling the
+ * {@link #exportObject(Remote, int, RMIClientSocketFactory, RMIServerSocketFactory, ObjectInputFilter)
+ * exportObject(Remote, port, csf, ssf, filter)} method.
+ *
  * </ol>
  *
  * <p>The fourth technique, {@link #exportObject(Remote)},
  * always uses statically generated stubs and is deprecated.
  *
- * <p>The other five techniques all use the following approach: if the
+ * <p>The other techniques all use the following approach: if the
  * {@code java.rmi.server.ignoreStubClasses} property is {@code true}
  * (case insensitive) or if a static stub cannot be found, stubs are generated
  * dynamically using {@link java.lang.reflect.Proxy Proxy} objects. Otherwise,
@@ -130,6 +139,22 @@
  *
  * </ul>
  *
+ * <p>
+ * Exported remote objects receive method invocations from the stubs
+ * as described in the RMI specification. Each invocation's operation and
+ * parameters are unmarshaled using a custom {@link java.io.ObjectInputStream}.
+ * If an {@link ObjectInputFilter} is provided and is not {@code null} when the object
+ * is exported, it is used to filter the parameters as they are unmarshaled from the stream.
+ * The filter is used for all invocations and all parameters regardless of
+ * the method being invoked or the parameter values.
+ * If no filter is provided or is {@code null} for the exported object then the
+ * {@code ObjectInputStream} default filter, if any, is used. The default filter is
+ * configured with {@link ObjectInputFilter.Config#setSerialFilter(ObjectInputFilter)
+ * ObjectInputFilter.Config.setSerialFilter}.
+ * If the filter rejects any of the parameters, the {@code InvalidClassException}
+ * thrown by {@code ObjectInputStream} is reported as the cause of an
+ * {@link UnmarshalException}.
+ *
  * @implNote
  * Depending upon which constructor or static method is used for exporting an
  * object, {@link RMISocketFactory} may be used for creating sockets.
@@ -347,6 +372,58 @@
     }
 
     /**
+     * Exports the remote object to make it available to receive incoming
+     * calls, using the particular supplied port
+     * and {@linkplain ObjectInputFilter filter}.
+     *
+     * <p>The object is exported with a server socket
+     * created using the {@link RMISocketFactory} class.
+     *
+     * @param obj the remote object to be exported
+     * @param port the port to export the object on
+     * @param filter an ObjectInputFilter applied when deserializing invocation arguments;
+     *               may be {@code null}
+     * @return remote object stub
+     * @exception RemoteException if export fails
+     * @since 9
+     */
+    public static Remote exportObject(Remote obj, int port,
+                                      ObjectInputFilter filter)
+            throws RemoteException
+    {
+        return exportObject(obj, new UnicastServerRef(new LiveRef(port), filter));
+    }
+
+    /**
+     * Exports the remote object to make it available to receive incoming
+     * calls, using a transport specified by the given socket factory
+     * and {@linkplain ObjectInputFilter filter}.
+     *
+     * <p>Either socket factory may be {@code null}, in which case
+     * the corresponding client or server socket creation method of
+     * {@link RMISocketFactory} is used instead.
+     *
+     * @param obj the remote object to be exported
+     * @param port the port to export the object on
+     * @param csf the client-side socket factory for making calls to the
+     * remote object
+     * @param ssf the server-side socket factory for receiving remote calls
+     * @param filter an ObjectInputFilter applied when deserializing invocation arguments;
+     *               may be {@code null}
+     * @return remote object stub
+     * @exception RemoteException if export fails
+     * @since 9
+     */
+    public static Remote exportObject(Remote obj, int port,
+                                      RMIClientSocketFactory csf,
+                                      RMIServerSocketFactory ssf,
+                                      ObjectInputFilter filter)
+        throws RemoteException
+    {
+        return exportObject(obj, new UnicastServerRef2(port, csf, ssf, filter));
+    }
+
+    /**
      * Removes the remote object, obj, from the RMI runtime. If
      * successful, the object can no longer accept incoming RMI calls.
      * If the force parameter is true, the object is forcibly unexported
--- a/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java	Wed Oct 05 06:28:22 2016 -0700
@@ -27,6 +27,8 @@
 
 import java.io.IOException;
 import java.io.ObjectInput;
+import java.io.ObjectInputFilter;
+import java.io.ObjectInputStream;
 import java.io.ObjectOutput;
 import java.io.ObjectStreamClass;
 import java.lang.reflect.InvocationTargetException;
@@ -62,6 +64,10 @@
  * UnicastServerRef implements the remote reference layer server-side
  * behavior for remote objects exported with the "UnicastRef" reference
  * type.
+ * If an {@link ObjectInputFilter ObjectInputFilter} is supplied it is
+ * invoked during deserialization to filter the arguments,
+ * otherwise the default filter of {@link ObjectInputStream ObjectInputStream}
+ * applies.
  *
  * @author  Ann Wollrath
  * @author  Roger Riggs
@@ -103,6 +109,9 @@
      */
     private transient Skeleton skel;
 
+    // The ObjectInputFilter for checking the invocation arguments
+    private final transient ObjectInputFilter filter;
+
     /** maps method hash to Method object for each remote method */
     private transient Map<Long,Method> hashToMethod_Map = null;
 
@@ -121,16 +130,29 @@
 
     /**
      * Create a new (empty) Unicast server remote reference.
+     * The filter is null to defer to the  default ObjectInputStream filter, if any.
      */
     public UnicastServerRef() {
+        this.filter = null;
     }
 
     /**
      * Construct a Unicast server remote reference for a specified
      * liveRef.
+     * The filter is null to defer to the  default ObjectInputStream filter, if any.
      */
     public UnicastServerRef(LiveRef ref) {
         super(ref);
+        this.filter = null;
+    }
+
+    /**
+     * Construct a Unicast server remote reference for a specified
+     * liveRef and filter.
+     */
+    public UnicastServerRef(LiveRef ref, ObjectInputFilter filter) {
+        super(ref);
+        this.filter = filter;
     }
 
     /**
@@ -139,6 +161,7 @@
      */
     public UnicastServerRef(int port) {
         super(new LiveRef(port));
+        this.filter = null;
     }
 
     /**
@@ -363,9 +386,23 @@
         }
     }
 
+    /**
+     * Sets a filter for invocation arguments, if a filter has been set.
+     * Called by dispatch before the arguments are read.
+     */
     protected void unmarshalCustomCallData(ObjectInput in)
-        throws IOException, ClassNotFoundException
-    {}
+            throws IOException, ClassNotFoundException {
+        if (filter != null &&
+                in instanceof ObjectInputStream) {
+            // Set the filter on the stream
+            ObjectInputStream ois = (ObjectInputStream) in;
+
+            AccessController.doPrivileged((PrivilegedAction<Void>)() -> {
+                ois.setObjectInputFilter(filter);
+                return null;
+            });
+        }
+    }
 
     /**
      * Handle server-side dispatch using the RMI 1.1 stub/skeleton
--- a/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef2.java	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef2.java	Wed Oct 05 06:28:22 2016 -0700
@@ -25,12 +25,13 @@
 
 package sun.rmi.server;
 
-import java.io.IOException;
+import java.io.ObjectInputFilter;
 import java.io.ObjectOutput;
-import java.rmi.*;
-import java.rmi.server.*;
-import sun.rmi.transport.*;
-import sun.rmi.transport.tcp.*;
+import java.rmi.server.RMIClientSocketFactory;
+import java.rmi.server.RMIServerSocketFactory;
+import java.rmi.server.RemoteRef;
+
+import sun.rmi.transport.LiveRef;
 
 /**
  * Server-side ref for a remote impl that uses a custom socket factory.
@@ -59,6 +60,16 @@
     }
 
     /**
+     * Construct a Unicast server remote reference for a specified
+     * liveRef and filter.
+     */
+    public UnicastServerRef2(LiveRef ref,
+                             ObjectInputFilter filter)
+    {
+        super(ref, filter);
+    }
+
+    /**
      * Construct a Unicast server remote reference to be exported
      * on the specified port.
      */
@@ -70,6 +81,18 @@
     }
 
     /**
+     * Construct a Unicast server remote reference to be exported
+     * on the specified port.
+     */
+    public UnicastServerRef2(int port,
+                             RMIClientSocketFactory csf,
+                             RMIServerSocketFactory ssf,
+                             ObjectInputFilter filter)
+    {
+        super(new LiveRef(port, csf, ssf), filter);
+    }
+
+    /**
      * Returns the class of the ref type to be serialized
      */
     public String getRefClass(ObjectOutput out)
--- a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Cipher.java	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Cipher.java	Wed Oct 05 06:28:22 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -344,7 +344,7 @@
     private void implInit(int opmode, Key key, byte[] iv,
             SecureRandom random)
             throws InvalidKeyException, InvalidAlgorithmParameterException {
-        cancelOperation();
+        reset(true);
         if (fixedKeySize != -1 && key.getEncoded().length != fixedKeySize) {
             throw new InvalidKeyException("Key size is invalid");
         }
@@ -404,23 +404,26 @@
         if (initialized == false) {
             return;
         }
-        initialized = false;
+
         if ((session == null) || (token.explicitCancel == false)) {
             return;
         }
-        // cancel operation by finishing it
-        int bufLen = doFinalLength(0);
-        byte[] buffer = new byte[bufLen];
         try {
-            if (encrypt) {
-                token.p11.C_EncryptFinal(session.id(), 0, buffer, 0, bufLen);
+            if (session.hasObjects() == false) {
+                session = token.killSession(session);
+                return;
             } else {
-                token.p11.C_DecryptFinal(session.id(), 0, buffer, 0, bufLen);
+                // cancel operation by finishing it
+                int bufLen = doFinalLength(0);
+                byte[] buffer = new byte[bufLen];
+                if (encrypt) {
+                    token.p11.C_EncryptFinal(session.id(), 0, buffer, 0, bufLen);
+                } else {
+                    token.p11.C_DecryptFinal(session.id(), 0, buffer, 0, bufLen);
+                }
             }
         } catch (PKCS11Exception e) {
             throw new ProviderException("Cancel failed", e);
-        } finally {
-            reset();
         }
     }
 
@@ -483,7 +486,9 @@
     }
 
     // reset the states to the pre-initialized values
-    private void reset() {
+    private void reset(boolean doCancel) {
+        if (doCancel) cancelOperation();
+
         initialized = false;
         bytesBuffered = 0;
         padBufferLen = 0;
@@ -610,7 +615,7 @@
                 throw (ShortBufferException)
                         (new ShortBufferException().initCause(e));
             }
-            reset();
+            reset(false);
             throw new ProviderException("update() failed", e);
         }
     }
@@ -728,7 +733,7 @@
                 throw (ShortBufferException)
                         (new ShortBufferException().initCause(e));
             }
-            reset();
+            reset(false);
             throw new ProviderException("update() failed", e);
         }
     }
@@ -740,6 +745,7 @@
         if (outLen < requiredOutLen) {
             throw new ShortBufferException();
         }
+        boolean doCancel = true;
         try {
             ensureInitialized();
             int k = 0;
@@ -753,7 +759,12 @@
                 }
                 k += token.p11.C_EncryptFinal(session.id(),
                         0, out, (outOfs + k), (outLen - k));
+                doCancel = false;
             } else {
+                // Special handling to match SunJCE provider behavior
+                if (bytesBuffered == 0 && padBufferLen == 0) {
+                    return 0;
+                }
                 if (paddingObj != null) {
                     if (padBufferLen != 0) {
                         k = token.p11.C_DecryptUpdate(session.id(), 0,
@@ -762,20 +773,24 @@
                     }
                     k += token.p11.C_DecryptFinal(session.id(), 0, padBuffer, k,
                             padBuffer.length - k);
+                    doCancel = false;
+
                     int actualPadLen = paddingObj.unpad(padBuffer, k);
                     k -= actualPadLen;
                     System.arraycopy(padBuffer, 0, out, outOfs, k);
                 } else {
                     k = token.p11.C_DecryptFinal(session.id(), 0, out, outOfs,
                             outLen);
+                    doCancel = false;
                 }
             }
             return k;
         } catch (PKCS11Exception e) {
+            doCancel = false;
             handleException(e);
             throw new ProviderException("doFinal() failed", e);
         } finally {
-            reset();
+            reset(doCancel);
         }
     }
 
@@ -788,6 +803,7 @@
             throw new ShortBufferException();
         }
 
+        boolean doCancel = true;
         try {
             ensureInitialized();
 
@@ -818,7 +834,13 @@
                 }
                 k += token.p11.C_EncryptFinal(session.id(),
                         outAddr, outArray, (outOfs + k), (outLen - k));
+                doCancel = false;
             } else {
+                // Special handling to match SunJCE provider behavior
+                if (bytesBuffered == 0 && padBufferLen == 0) {
+                    return 0;
+                }
+
                 if (paddingObj != null) {
                     if (padBufferLen != 0) {
                         k = token.p11.C_DecryptUpdate(session.id(),
@@ -828,6 +850,8 @@
                     }
                     k += token.p11.C_DecryptFinal(session.id(),
                             0, padBuffer, k, padBuffer.length - k);
+                    doCancel = false;
+
                     int actualPadLen = paddingObj.unpad(padBuffer, k);
                     k -= actualPadLen;
                     outArray = padBuffer;
@@ -835,6 +859,7 @@
                 } else {
                     k = token.p11.C_DecryptFinal(session.id(),
                             outAddr, outArray, outOfs, outLen);
+                    doCancel = false;
                 }
             }
             if ((!encrypt && paddingObj != null) ||
@@ -846,10 +871,11 @@
             }
             return k;
         } catch (PKCS11Exception e) {
+            doCancel = false;
             handleException(e);
             throw new ProviderException("doFinal() failed", e);
         } finally {
-            reset();
+            reset(doCancel);
         }
     }
 
--- a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Signature.java	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Signature.java	Wed Oct 05 06:28:22 2016 -0700
@@ -616,8 +616,11 @@
                     return dsaToASN1(signature);
                 }
             }
-        } catch (PKCS11Exception e) {
-            throw new ProviderException(e);
+        } catch (PKCS11Exception pe) {
+            throw new ProviderException(pe);
+        } catch (SignatureException | ProviderException e) {
+            cancelOperation();
+            throw e;
         } finally {
             initialized = false;
             session = token.releaseSession(session);
@@ -669,8 +672,8 @@
                 }
             }
             return true;
-        } catch (PKCS11Exception e) {
-            long errorCode = e.getErrorCode();
+        } catch (PKCS11Exception pe) {
+            long errorCode = pe.getErrorCode();
             if (errorCode == CKR_SIGNATURE_INVALID) {
                 return false;
             }
@@ -682,10 +685,11 @@
             if (errorCode == CKR_DATA_LEN_RANGE) {
                 return false;
             }
-            throw new ProviderException(e);
+            throw new ProviderException(pe);
+        }  catch (SignatureException | ProviderException e) {
+            cancelOperation();
+            throw e;
         } finally {
-            // XXX we should not release the session if we abort above
-            // before calling C_Verify
             initialized = false;
             session = token.releaseSession(session);
         }
--- a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/Secmod.java	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/Secmod.java	Wed Oct 05 06:28:22 2016 -0700
@@ -743,6 +743,7 @@
         Map<Bytes,TrustAttributes> trustMap = new HashMap<Bytes,TrustAttributes>();
         Token token = provider.getToken();
         Session session = null;
+        boolean exceptionOccurred = true;
         try {
             session = token.getOpSession();
             int MAX_NUM = 8192;
@@ -762,8 +763,13 @@
                     // skip put on pkcs11 error
                 }
             }
+            exceptionOccurred = false;
         } finally {
-            token.releaseSession(session);
+            if (exceptionOccurred) {
+                token.killSession(session);
+            } else {
+                token.releaseSession(session);
+            }
         }
         return trustMap;
     }
--- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeCipherWithJavaPadding.java	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeCipherWithJavaPadding.java	Wed Oct 05 06:28:22 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -160,8 +160,11 @@
                 ShortBufferException {
             int tbSize = (trailingBytes == null? 0:trailingBytes.position());
             int dataLen = tbSize + lastData.length;
-            // check total length
-            if ((dataLen < 1) || (dataLen % blockSize != 0)) {
+
+            // Special handling to match SunJCE provider behavior
+            if (dataLen <= 0) {
+                return 0;
+            } else if (dataLen % blockSize != 0) {
                 UcryptoProvider.debug("PKCS5Padding: unpad, buffered " + tbSize +
                                  " bytes, last block " + lastData.length + " bytes");
 
@@ -402,7 +405,6 @@
         throws ShortBufferException, IllegalBlockSizeException,
                BadPaddingException {
         int estimatedOutLen = engineGetOutputSize(inLen);
-
         if (out.length - outOfs < estimatedOutLen) {
             throw new ShortBufferException("Actual: " + (out.length - outOfs) +
                 ". Estimated Out Length: " + estimatedOutLen);
--- a/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeRSASignature.java	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/jdk.crypto.ucrypto/solaris/classes/com/oracle/security/ucrypto/NativeRSASignature.java	Wed Oct 05 06:28:22 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -258,27 +258,38 @@
 
     @Override
     protected synchronized byte[] engineSign() throws SignatureException {
-        byte[] sig = new byte[sigLength];
-        int rv = doFinal(sig, 0, sigLength);
-        if (rv < 0) {
-            throw new SignatureException(new UcryptoException(-rv));
+        try {
+            byte[] sig = new byte[sigLength];
+            int rv = doFinal(sig, 0, sigLength);
+            if (rv < 0) {
+                throw new SignatureException(new UcryptoException(-rv));
+            }
+            return sig;
+        } finally {
+            // doFinal should already be called, no need to cancel
+            reset(false);
         }
-        return sig;
     }
 
     @Override
     protected synchronized int engineSign(byte[] outbuf, int offset, int len)
         throws SignatureException {
-        if (outbuf == null || (offset < 0) || (outbuf.length < (offset + sigLength))
-            || (len < sigLength)) {
-            throw new SignatureException("Invalid output buffer. offset: " +
-                offset + ". len: " + len + ". sigLength: " + sigLength);
+        boolean doCancel = true;
+        try {
+            if (outbuf == null || (offset < 0) || (outbuf.length < (offset + sigLength))
+                || (len < sigLength)) {
+                throw new SignatureException("Invalid output buffer. offset: " +
+                    offset + ". len: " + len + ". sigLength: " + sigLength);
+            }
+            int rv = doFinal(outbuf, offset, sigLength);
+            doCancel = false;
+            if (rv < 0) {
+                throw new SignatureException(new UcryptoException(-rv));
+            }
+            return sigLength;
+        } finally {
+            reset(doCancel);
         }
-        int rv = doFinal(outbuf, offset, sigLength);
-        if (rv < 0) {
-            throw new SignatureException(new UcryptoException(-rv));
-        }
-        return sigLength;
     }
 
     @Override
@@ -329,19 +340,25 @@
     @Override
     protected synchronized boolean engineVerify(byte[] sigBytes, int sigOfs, int sigLen)
         throws SignatureException {
-        if (sigBytes == null || (sigOfs < 0) || (sigBytes.length < (sigOfs + this.sigLength))
-            || (sigLen != this.sigLength)) {
-            throw new SignatureException("Invalid signature length: got " +
-                sigLen + " but was expecting " + this.sigLength);
-        }
+        boolean doCancel = true;
+        try {
+            if (sigBytes == null || (sigOfs < 0) || (sigBytes.length < (sigOfs + this.sigLength))
+                || (sigLen != this.sigLength)) {
+                throw new SignatureException("Invalid signature length: got " +
+                    sigLen + " but was expecting " + this.sigLength);
+            }
 
-        int rv = doFinal(sigBytes, sigOfs, sigLen);
-        if (rv == 0) {
-            return true;
-        } else {
-            UcryptoProvider.debug("Signature: " + mech + " verification error " +
+            int rv = doFinal(sigBytes, sigOfs, sigLen);
+            doCancel = false;
+            if (rv == 0) {
+                return true;
+            } else {
+                UcryptoProvider.debug("Signature: " + mech + " verification error " +
                              new UcryptoException(-rv).getMessage());
-            return false;
+                return false;
+            }
+        } finally {
+            reset(doCancel);
         }
     }
 
@@ -432,13 +449,9 @@
 
     // returns 0 (success) or negative (ucrypto error occurred)
     private int doFinal(byte[] sigBytes, int sigOfs, int sigLen) {
-        try {
-            ensureInitialized();
-            int k = nativeFinal(pCtxt.id, sign, sigBytes, sigOfs, sigLen);
-            return k;
-        } finally {
-            reset(false);
-        }
+        ensureInitialized();
+        int k = nativeFinal(pCtxt.id, sign, sigBytes, sigOfs, sigLen);
+        return k;
     }
 
     // check and return RSA key size in number of bytes
--- a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/extra/EditingHistory.java	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/extra/EditingHistory.java	Wed Oct 05 06:28:22 2016 -0700
@@ -48,7 +48,9 @@
     private History currentDelegate;
 
     protected EditingHistory(ConsoleReader in, Iterable<? extends String> originalHistory) {
-        this.fullHistory = new MemoryHistory();
+        MemoryHistory fullHistory = new MemoryHistory();
+        fullHistory.setIgnoreDuplicates(false);
+        this.fullHistory = fullHistory;
         this.currentDelegate = fullHistory;
         bind(in, CTRL_UP,
              (Runnable) () -> moveHistoryToSnippet(in, ((EditingHistory) in.getHistory())::previousSnippet));
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java	Wed Oct 05 06:28:22 2016 -0700
@@ -103,6 +103,18 @@
             basename = en.baseName;
             entryname = en.entryName;
         }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (!(o instanceof Entry)) return false;
+            return this.file.equals(((Entry)o).file);
+        }
+
+        @Override
+        public int hashCode() {
+            return file.hashCode();
+        }
     }
 
     class EntryName {
@@ -124,10 +136,10 @@
             if (name.startsWith("./")) {
                 name = name.substring(2);
             }
-            this.baseName = name;
-            this.entryName = (version > BASE_VERSION)
-                    ? VERSIONS_DIR + version + "/" + this.baseName
-                    : this.baseName;
+            baseName = name;
+            entryName = (version > BASE_VERSION)
+                    ? VERSIONS_DIR + version + "/" + baseName
+                    : baseName;
         }
     }
 
@@ -137,7 +149,7 @@
     Map<String, Entry> entryMap = new HashMap<>();
 
     // All entries need to be added/updated.
-    Map<String, Entry> entries = new LinkedHashMap<>();
+    Set<Entry> entries = new LinkedHashSet<>();
 
     // All packages.
     Set<String> packages = new HashSet<>();
@@ -855,8 +867,7 @@
                     moduleInfoPaths.put(entryName, f.toPath());
                     if (isUpdate)
                         entryMap.put(entryName, entry);
-                } else if (!entries.containsKey(entryName)) {
-                    entries.put(entryName, entry);
+                } else if (entries.add(entry)) {
                     jarEntries.add(entryName);
                     if (entry.basename.endsWith(".class") && !entryName.startsWith(VERSIONS_DIR))
                         packages.add(toPackageName(entry.basename));
@@ -864,8 +875,7 @@
                         entryMap.put(entryName, entry);
                 }
             } else if (f.isDirectory()) {
-                if (!entries.containsKey(entryName)) {
-                    entries.put(entryName, entry);
+                if (entries.add(entry)) {
                     if (isUpdate) {
                         entryMap.put(entryName, entry);
                     }
@@ -923,8 +933,7 @@
             in.transferTo(zos);
             zos.closeEntry();
         }
-        for (String entryname : entries.keySet()) {
-            Entry entry = entries.get(entryname);
+        for (Entry entry : entries) {
             addFile(zos, entry);
         }
         zos.close();
@@ -1049,7 +1058,7 @@
                     Entry ent = entryMap.get(name);
                     addFile(zos, ent);
                     entryMap.remove(name);
-                    entries.remove(name);
+                    entries.remove(ent);
                 }
 
                 jarEntries.add(name);
@@ -1059,8 +1068,8 @@
         }
 
         // add the remaining new files
-        for (String entryname : entries.keySet()) {
-            addFile(zos, entries.get(entryname));
+        for (Entry entry : entries) {
+            addFile(zos, entry);
         }
         if (!foundManifest) {
             if (newManifest != null) {
@@ -1248,6 +1257,9 @@
      * Adds a new file entry to the ZIP output stream.
      */
     void addFile(ZipOutputStream zos, Entry entry) throws IOException {
+        // skip the generation of directory entries for META-INF/versions/*/
+        if (entry.basename.isEmpty()) return;
+
         File file = entry.file;
         String name = entry.entryname;
         boolean isDir = entry.isDir;
--- a/jdk/src/jdk.jdwp.agent/share/native/libjdwp/invoker.c	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/jdk.jdwp.agent/share/native/libjdwp/invoker.c	Wed Oct 05 06:28:22 2016 -0700
@@ -211,6 +211,62 @@
     return error;
 }
 
+/*
+ * Delete saved global references - if any - for:
+ * - a potentially thrown Exception
+ * - a returned refernce/array value
+ * See invoker_doInvoke() and invoke* methods where global references
+ * are being saved.
+ */
+static void
+deletePotentiallySavedGlobalRefs(JNIEnv *env, InvokeRequest *request)
+{
+    /* Delete potentially saved return value */
+    if ((request->invokeType == INVOKE_CONSTRUCTOR) ||
+        (returnTypeTag(request->methodSignature) == JDWP_TAG(OBJECT)) ||
+        (returnTypeTag(request->methodSignature) == JDWP_TAG(ARRAY))) {
+        if (request->returnValue.l != NULL) {
+            tossGlobalRef(env, &(request->returnValue.l));
+        }
+    }
+    /* Delete potentially saved exception */
+    if (request->exception != NULL) {
+        tossGlobalRef(env, &(request->exception));
+    }
+}
+
+/*
+ * Delete global argument references from the request which got put there before a
+ * invoke request was carried out. See fillInvokeRequest().
+ */
+static void
+deleteGlobalArgumentRefs(JNIEnv *env, InvokeRequest *request)
+{
+    void *cursor;
+    jint argIndex = 0;
+    jvalue *argument = request->arguments;
+    jbyte argumentTag = firstArgumentTypeTag(request->methodSignature, &cursor);
+
+    if (request->clazz != NULL) {
+        tossGlobalRef(env, &(request->clazz));
+    }
+    if (request->instance != NULL) {
+        tossGlobalRef(env, &(request->instance));
+    }
+    /* Delete global argument references */
+    while (argIndex < request->argumentCount) {
+        if ((argumentTag == JDWP_TAG(OBJECT)) ||
+            (argumentTag == JDWP_TAG(ARRAY))) {
+            if (argument->l != NULL) {
+                tossGlobalRef(env, &(argument->l));
+            }
+        }
+        argument++;
+        argIndex++;
+        argumentTag = nextArgumentTypeTag(&cursor);
+    }
+}
+
 static jvmtiError
 fillInvokeRequest(JNIEnv *env, InvokeRequest *request,
                   jbyte invokeType, jbyte options, jint id,
@@ -322,6 +378,8 @@
 invokeConstructor(JNIEnv *env, InvokeRequest *request)
 {
     jobject object;
+
+    JDI_ASSERT_MSG(request->clazz, "Request clazz null");
     object = JNI_FUNC_PTR(env,NewObjectA)(env, request->clazz,
                                      request->method,
                                      request->arguments);
@@ -338,6 +396,7 @@
         case JDWP_TAG(OBJECT):
         case JDWP_TAG(ARRAY): {
             jobject object;
+            JDI_ASSERT_MSG(request->clazz, "Request clazz null");
             object = JNI_FUNC_PTR(env,CallStaticObjectMethodA)(env,
                                        request->clazz,
                                        request->method,
@@ -426,6 +485,7 @@
         case JDWP_TAG(OBJECT):
         case JDWP_TAG(ARRAY): {
             jobject object;
+            JDI_ASSERT_MSG(request->instance, "Request instance null");
             object = JNI_FUNC_PTR(env,CallObjectMethodA)(env,
                                  request->instance,
                                  request->method,
@@ -513,6 +573,8 @@
         case JDWP_TAG(OBJECT):
         case JDWP_TAG(ARRAY): {
             jobject object;
+            JDI_ASSERT_MSG(request->clazz, "Request clazz null");
+            JDI_ASSERT_MSG(request->instance, "Request instance null");
             object = JNI_FUNC_PTR(env,CallNonvirtualObjectMethodA)(env,
                                            request->instance,
                                            request->clazz,
@@ -609,6 +671,8 @@
     JNIEnv *env;
     jboolean startNow;
     InvokeRequest *request;
+    jbyte options;
+    jbyte invokeType;
 
     JDI_ASSERT(thread);
 
@@ -625,6 +689,9 @@
     if (startNow) {
         request->started = JNI_TRUE;
     }
+    options = request->options;
+    invokeType = request->invokeType;
+
     debugMonitorExit(invokerLock);
 
     if (!startNow) {
@@ -639,7 +706,7 @@
 
         JNI_FUNC_PTR(env,ExceptionClear)(env);
 
-        switch (request->invokeType) {
+        switch (invokeType) {
             case INVOKE_CONSTRUCTOR:
                 invokeConstructor(env, request);
                 break;
@@ -647,7 +714,7 @@
                 invokeStatic(env, request);
                 break;
             case INVOKE_INSTANCE:
-                if (request->options & JDWP_INVOKE_OPTIONS(NONVIRTUAL) ) {
+                if (options & JDWP_INVOKE_OPTIONS(NONVIRTUAL) ) {
                     invokeNonvirtual(env, request);
                 } else {
                     invokeVirtual(env, request);
@@ -725,12 +792,23 @@
     }
 
     /*
+     * At this time, there's no need to retain global references on
+     * arguments since the reply is processed. No one will deal with
+     * this request ID anymore, so we must call deleteGlobalArgumentRefs().
+     *
+     * We cannot delete saved exception or return value references
+     * since otherwise a deleted handle would escape when writing
+     * the response to the stream. Instead, we clean those refs up
+     * after writing the respone.
+     */
+    deleteGlobalArgumentRefs(env, request);
+
+    /*
      * Give up the lock before I/O operation
      */
     debugMonitorExit(invokerLock);
     eventHandler_unlock();
 
-
     if (!detached) {
         outStream_initReply(&out, id);
         (void)outStream_writeValue(env, &out, tag, returnValue);
@@ -738,6 +816,16 @@
         (void)outStream_writeObjectRef(env, &out, exc);
         outStream_sendReply(&out);
     }
+
+    /*
+     * Delete potentially saved global references of return value
+     * and exception
+     */
+    eventHandler_lock(); // for proper lock order
+    debugMonitorEnter(invokerLock);
+    deletePotentiallySavedGlobalRefs(env, request);
+    debugMonitorExit(invokerLock);
+    eventHandler_unlock();
 }
 
 jboolean
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java	Wed Oct 05 06:28:22 2016 -0700
@@ -86,6 +86,9 @@
             task.options.help = true;
         }, "--help", "-h"),
         new Option<JlinkTask>(true, (task, opt, arg) -> {
+            // if used multiple times, the last one wins!
+            // So, clear previous values, if any.
+            task.options.modulePath.clear();
             String[] dirs = arg.split(File.pathSeparator);
             int i = 0;
             Arrays.stream(dirs)
@@ -93,6 +96,9 @@
                   .forEach(task.options.modulePath::add);
         }, "--module-path", "-p"),
         new Option<JlinkTask>(true, (task, opt, arg) -> {
+            // if used multiple times, the last one wins!
+            // So, clear previous values, if any.
+            task.options.limitMods.clear();
             for (String mn : arg.split(",")) {
                 if (mn.isEmpty()) {
                     throw taskHelper.newBadArgs("err.mods.must.be.specified",
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java	Wed Oct 05 06:28:22 2016 -0700
@@ -307,9 +307,10 @@
 
     private boolean filterOutUnsupportedTags(byte[] b) {
         List<Locale> locales;
+        List<String> originalTags = Arrays.asList(new String(b).split(" "));
 
         try {
-            locales = Arrays.asList(new String(b).split(" ")).stream()
+            locales = originalTags.stream()
                 .filter(tag -> !tag.isEmpty())
                 .map(IncludeLocalesPlugin::tagToLocale)
                 .collect(Collectors.toList());
@@ -319,6 +320,9 @@
         }
 
         byte[] filteredBytes = filterLocales(locales).stream()
+            // Make sure the filtered language tags do exist in the
+            // original supported tags for compatibility codes, e.g., "iw"
+            .filter(originalTags::contains)
             .collect(Collectors.joining(" "))
             .getBytes();
 
@@ -331,6 +335,11 @@
         return true;
     }
 
+    /*
+     * Filter list of locales according to the secified priorityList. Note
+     * that returned list of language tags may include extra ones, such as
+     * compatibility ones (e.g., "iw" -> "iw", "he").
+     */
     private List<String> filterLocales(List<Locale> locales) {
         List<String> ret =
             Locale.filter(priorityList, locales, Locale.FilteringMode.EXTENDED_FILTERING).stream()
--- a/jdk/src/jdk.management/share/native/libmanagement_ext/DiagnosticCommandImpl.c	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/src/jdk.management/share/native/libmanagement_ext/DiagnosticCommandImpl.c	Wed Oct 05 06:28:22 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -45,6 +45,13 @@
   return jmm_interface->GetDiagnosticCommands(env);
 }
 
+#define EXCEPTION_CHECK_AND_FREE(x) do { \
+                                        if ((*env)->ExceptionCheck(env)) { \
+                                            free(x); \
+                                            return NULL; \
+                                        } \
+                                    } while(0)
+
 jobject getDiagnosticCommandArgumentInfoArray(JNIEnv *env, jstring command,
                                               int num_arg) {
   int i;
@@ -59,6 +66,7 @@
   dcmd_arg_info_array = (dcmdArgInfo*) malloc(num_arg * sizeof(dcmdArgInfo));
   /* According to ISO C it is perfectly legal for malloc to return zero if called with a zero argument */
   if (dcmd_arg_info_array == NULL && num_arg != 0) {
+    JNU_ThrowOutOfMemoryError(env, 0);
     return NULL;
   }
   jmm_interface->GetDiagnosticCommandArgumentsInfo(env, command,
@@ -76,14 +84,24 @@
     return NULL;
   }
   for (i=0; i<num_arg; i++) {
+    jstring jname, jdesc,jtype,jdefStr;
+
+    jname = (*env)->NewStringUTF(env,dcmd_arg_info_array[i].name);
+    EXCEPTION_CHECK_AND_FREE(dcmd_arg_info_array);
+
+    jdesc = (*env)->NewStringUTF(env,dcmd_arg_info_array[i].description);
+    EXCEPTION_CHECK_AND_FREE(dcmd_arg_info_array);
+
+    jtype = (*env)->NewStringUTF(env,dcmd_arg_info_array[i].type);
+    EXCEPTION_CHECK_AND_FREE(dcmd_arg_info_array);
+
+    jdefStr = (*env)->NewStringUTF(env, dcmd_arg_info_array[i].default_string);
+    EXCEPTION_CHECK_AND_FREE(dcmd_arg_info_array);
     obj = JNU_NewObjectByName(env,
                               "com/sun/management/internal/DiagnosticCommandArgumentInfo",
                               "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZI)V",
-                              (*env)->NewStringUTF(env,dcmd_arg_info_array[i].name),
-                              (*env)->NewStringUTF(env,dcmd_arg_info_array[i].description),
-                              (*env)->NewStringUTF(env,dcmd_arg_info_array[i].type),
-                              dcmd_arg_info_array[i].default_string == NULL ? NULL:
-                              (*env)->NewStringUTF(env, dcmd_arg_info_array[i].default_string),
+                              jname, jdesc, jtype,
+                              dcmd_arg_info_array[i].default_string == NULL ? NULL: jdefStr,
                               dcmd_arg_info_array[i].mandatory,
                               dcmd_arg_info_array[i].option,
                               dcmd_arg_info_array[i].multiple,
@@ -93,6 +111,7 @@
       return NULL;
     }
     (*env)->SetObjectArrayElement(env, result, i, obj);
+    EXCEPTION_CHECK_AND_FREE(dcmd_arg_info_array);
   }
   free(dcmd_arg_info_array);
   arraysCls = (*env)->FindClass(env, "java/util/Arrays");
@@ -125,6 +144,7 @@
   jint ret = jmm_interface->GetOptionalSupport(env, &mos);
   jsize num_commands;
   dcmdInfo* dcmd_info_array;
+  jstring jname, jdesc, jimpact;
 
   if (commands == NULL) {
       JNU_ThrowNullPointerException(env, "Invalid String Array");
@@ -139,7 +159,6 @@
 
   result = (*env)->NewObjectArray(env, num_commands, dcmdInfoCls, NULL);
   if (result == NULL) {
-      JNU_ThrowOutOfMemoryError(env, 0);
       return NULL;
   }
   if (num_commands == 0) {
@@ -159,15 +178,22 @@
                                                    dcmd_info_array[i].num_arguments);
       if (args == NULL) {
           free(dcmd_info_array);
-          JNU_ThrowOutOfMemoryError(env, 0);
           return NULL;
       }
+
+      jname = (*env)->NewStringUTF(env,dcmd_info_array[i].name);
+      EXCEPTION_CHECK_AND_FREE(dcmd_info_array);
+
+      jdesc = (*env)->NewStringUTF(env,dcmd_info_array[i].description);
+      EXCEPTION_CHECK_AND_FREE(dcmd_info_array);
+
+      jimpact = (*env)->NewStringUTF(env,dcmd_info_array[i].impact);
+      EXCEPTION_CHECK_AND_FREE(dcmd_info_array);
+
       obj = JNU_NewObjectByName(env,
                                 "com/sun/management/internal/DiagnosticCommandInfo",
                                 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLjava/util/List;)V",
-                                (*env)->NewStringUTF(env,dcmd_info_array[i].name),
-                                (*env)->NewStringUTF(env,dcmd_info_array[i].description),
-                                (*env)->NewStringUTF(env,dcmd_info_array[i].impact),
+                                jname, jdesc, jimpact,
                                 dcmd_info_array[i].permission_class==NULL?NULL:(*env)->NewStringUTF(env,dcmd_info_array[i].permission_class),
                                 dcmd_info_array[i].permission_name==NULL?NULL:(*env)->NewStringUTF(env,dcmd_info_array[i].permission_name),
                                 dcmd_info_array[i].permission_action==NULL?NULL:(*env)->NewStringUTF(env,dcmd_info_array[i].permission_action),
@@ -175,10 +201,11 @@
                                 args);
       if (obj == NULL) {
           free(dcmd_info_array);
-          JNU_ThrowOutOfMemoryError(env, 0);
           return NULL;
       }
+
       (*env)->SetObjectArrayElement(env, result, i, obj);
+      EXCEPTION_CHECK_AND_FREE(dcmd_info_array);
   }
   free(dcmd_info_array);
   return result;
--- a/jdk/test/ProblemList.txt	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/test/ProblemList.txt	Wed Oct 05 06:28:22 2016 -0700
@@ -136,6 +136,8 @@
 
 java/lang/instrument/DaemonThread/TestDaemonThread.java         8161225 generic-all
 
+java/lang/instrument/DaemonThread/TestDaemonThread.java         8167001 generic-all
+
 java/lang/management/MemoryMXBean/Pending.java                  8158837 generic-all
 java/lang/management/MemoryMXBean/PendingAllGC.sh               8158760 generic-all
 
@@ -275,8 +277,6 @@
 
 java/util/spi/ResourceBundleControlProvider/UserDefaultControlTest.java 8062512 generic-all
 
-java/util/Arrays/ParallelPrefix.java                            8080165,8085982 generic-all
-
 java/util/BitSet/BitSetStreamTest.java                          8079538 generic-all
 
 ############################################################################
--- a/jdk/test/com/sun/jdi/InvokeHangTest.java	Fri Sep 30 02:52:38 2016 -0700
+++ b/jdk/test/com/sun/jdi/InvokeHangTest.java	Wed Oct 05 06:28:22 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,7 @@
  *  @author jjh
  *
  *  @modules jdk.jdi
+ *  @library /test/lib
  *  @run build TestScaffold VMConnection TargetListener TargetAdapter
  *  @run compile -g InvokeHangTest.java
  *  @run driver InvokeHangTest
@@ -133,7 +134,7 @@
     BreakpointRequest request2;
     static volatile int bkpts = 0;
     Thread timerThread;
-    static int waitTime = 20000;
+    static long waitTime = jdk.test.lib.Utils.adjustTimeout(20000);
 
     InvokeHangTest (String args[]) {
         super(args);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/jdi/OomDebugTest.java	Wed Oct 05 06:28:22 2016 -0700
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 2016 Red Hat Inc.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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 8153711
+ *  @summary JDWP: Memory Leak (global references not deleted after invokeMethod).
+ *
+ *  @author Severin Gehwolf <sgehwolf@redhat.com>
+ *
+ *  @library ..
+ *  @run build TestScaffold VMConnection TargetListener TargetAdapter
+ *  @run compile -g OomDebugTest.java
+ *  @run main OomDebugTest OomDebugTestTarget test1
+ *  @run main OomDebugTest OomDebugTestTarget test2
+ *  @run main OomDebugTest OomDebugTestTarget test3
+ *  @run main OomDebugTest OomDebugTestTarget test4
+ *  @run main OomDebugTest OomDebugTestTarget test5
+ */
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+
+import com.sun.jdi.ArrayReference;
+import com.sun.jdi.ArrayType;
+import com.sun.jdi.ClassType;
+import com.sun.jdi.Field;
+import com.sun.jdi.InvocationException;
+import com.sun.jdi.Method;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.ReferenceType;
+import com.sun.jdi.StackFrame;
+import com.sun.jdi.VMOutOfMemoryException;
+import com.sun.jdi.Value;
+import com.sun.jdi.event.BreakpointEvent;
+import com.sun.jdi.event.ExceptionEvent;
+
+/***************** Target program **********************/
+
+class OomDebugTestTarget {
+
+    OomDebugTestTarget() {
+        System.out.println("DEBUG: invoked constructor");
+    }
+    static class FooCls {
+        @SuppressWarnings("unused")
+        private byte[] bytes = new byte[3000000];
+    };
+
+    FooCls fooCls = new FooCls();
+    byte[] byteArray = new byte[0];
+
+    void testMethod(FooCls foo) {
+        System.out.println("DEBUG: invoked 'void testMethod(FooCls)', foo == " + foo);
+    }
+
+    void testPrimitive(byte[] foo) {
+        System.out.println("DEBUG: invoked 'void testPrimitive(byte[])', foo == " + foo);
+    }
+
+    byte[] testPrimitiveArrRetval() {
+        System.out.println("DEBUG: invoked 'byte[] testPrimitiveArrRetval()'");
+        return new byte[3000000];
+    }
+
+    FooCls testFooClsRetval() {
+        System.out.println("DEBUG: invoked 'FooCls testFooClsRetval()'");
+        return new FooCls();
+    }
+
+    public void entry() {}
+
+    public static void main(String[] args){
+        System.out.println("DEBUG: OomDebugTestTarget.main");
+        new OomDebugTestTarget().entry();
+    }
+}
+
+/***************** Test program ************************/
+
+public class OomDebugTest extends TestScaffold {
+
+    private static final String[] ALL_TESTS = new String[] {
+            "test1", "test2", "test3", "test4", "test5"
+    };
+    private static final Set<String> ALL_TESTS_SET = new HashSet<String>();
+    static {
+        ALL_TESTS_SET.addAll(Arrays.asList(ALL_TESTS));
+    }
+    private static final String TEST_CLASSES = System.getProperty("test.classes", ".");
+    private static final File RESULT_FILE = new File(TEST_CLASSES, "results.properties");
+    private static final String LAST_TEST = ALL_TESTS[ALL_TESTS.length - 1];
+    private ReferenceType targetClass;
+    private ObjectReference thisObject;
+    private int failedTests;
+    private final String testMethod;
+
+    public OomDebugTest(String[] args) {
+        super(args);
+        if (args.length != 2) {
+            throw new RuntimeException("Test failed unexpectedly.");
+        }
+        this.testMethod = args[1];
+    }
+
+    @Override
+    protected void runTests() throws Exception {
+        try {
+            addListener(new TargetAdapter() {
+
+                @Override
+                public void exceptionThrown(ExceptionEvent event) {
+                    String name = event.exception().referenceType().name();
+                    System.err.println("DEBUG: Exception thrown in debuggee was: " + name);
+                }
+            });
+            /*
+             * Get to the top of entry()
+             * to determine targetClass and mainThread
+             */
+            BreakpointEvent bpe = startTo("OomDebugTestTarget", "entry", "()V");
+            targetClass = bpe.location().declaringType();
+
+            mainThread = bpe.thread();
+
+            StackFrame frame = mainThread.frame(0);
+            thisObject = frame.thisObject();
+            java.lang.reflect.Method m = findTestMethod();
+            m.invoke(this);
+        } catch (NoSuchMethodException e) {
+            e.printStackTrace();
+            failure();
+        } catch (SecurityException e) {
+            e.printStackTrace();
+            failure();
+        }
+        /*
+         * resume the target, listening for events
+         */
+        listenUntilVMDisconnect();
+    }
+
+    private java.lang.reflect.Method findTestMethod()
+            throws NoSuchMethodException, SecurityException {
+        return OomDebugTest.class.getDeclaredMethod(testMethod);
+    }
+
+    private void failure() {
+        failedTests++;
+    }
+
+    /*
+     * Test case: Object reference as method parameter.
+     */
+    @SuppressWarnings("unused") // called via reflection
+    private void test1() throws Exception {
+        System.out.println("DEBUG: ------------> Running test1");
+        try {
+            Field field = targetClass.fieldByName("fooCls");
+            ClassType clsType = (ClassType)field.type();
+            Method constructor = getConstructorForClass(clsType);
+            for (int i = 0; i < 15; i++) {
+                @SuppressWarnings({ "rawtypes", "unchecked" })
+                ObjectReference objRef = clsType.newInstance(mainThread,
+                                                             constructor,
+                                                             new ArrayList(0),
+                                                             ObjectReference.INVOKE_NONVIRTUAL);
+                if (objRef.isCollected()) {
+                    System.out.println("DEBUG: Object got GC'ed before we can use it. NO-OP.");
+                    continue;
+                }
+                invoke("testMethod", "(LOomDebugTestTarget$FooCls;)V", objRef);
+            }
+        } catch (InvocationException e) {
+            handleFailure(e);
+        }
+    }
+
+    /*
+     * Test case: Array reference as method parameter.
+     */
+    @SuppressWarnings("unused") // called via reflection
+    private void test2() throws Exception {
+        System.out.println("DEBUG: ------------> Running test2");
+        try {
+            Field field = targetClass.fieldByName("byteArray");
+            ArrayType arrType = (ArrayType)field.type();
+
+            for (int i = 0; i < 15; i++) {
+                ArrayReference byteArrayVal = arrType.newInstance(3000000);
+                if (byteArrayVal.isCollected()) {
+                    System.out.println("DEBUG: Object got GC'ed before we can use it. NO-OP.");
+                    continue;
+                }
+                invoke("testPrimitive", "([B)V", byteArrayVal);
+            }
+        } catch (VMOutOfMemoryException e) {
+            defaultHandleOOMFailure(e);
+        }
+    }
+
+    /*
+     * Test case: Array reference as return value.
+     */
+    @SuppressWarnings("unused") // called via reflection
+    private void test3() throws Exception {
+        System.out.println("DEBUG: ------------> Running test3");
+        try {
+            for (int i = 0; i < 15; i++) {
+                invoke("testPrimitiveArrRetval",
+                       "()[B",
+                       Collections.EMPTY_LIST,
+                       vm().mirrorOfVoid());
+            }
+        } catch (InvocationException e) {
+            handleFailure(e);
+        }
+    }
+
+    /*
+     * Test case: Object reference as return value.
+     */
+    @SuppressWarnings("unused") // called via reflection
+    private void test4() throws Exception {
+        System.out.println("DEBUG: ------------> Running test4");
+        try {
+            for (int i = 0; i < 15; i++) {
+                invoke("testFooClsRetval",
+                       "()LOomDebugTestTarget$FooCls;",
+                       Collections.EMPTY_LIST,
+                       vm().mirrorOfVoid());
+            }
+        } catch (InvocationException e) {
+            handleFailure(e);
+        }
+    }
+
+    /*
+     * Test case: Constructor
+     */
+    @SuppressWarnings({ "unused", "unchecked", "rawtypes" }) // called via reflection
+    private void test5() throws Exception {
+        System.out.println("DEBUG: ------------> Running test5");
+        try {
+            ClassType type = (ClassType)thisObject.type();
+            for (int i = 0; i < 15; i++) {
+                type.newInstance(mainThread,
+                                 findMethod(targetClass, "<init>", "()V"),
+                                 new ArrayList(0),
+                                 ObjectReference.INVOKE_NONVIRTUAL);
+            }
+        } catch (InvocationException e) {
+            handleFailure(e);
+        }
+    }
+
+    private Method getConstructorForClass(ClassType clsType) {
+        List<Method> methods = clsType.methodsByName("<init>");
+        if (methods.size() != 1) {
+            throw new RuntimeException("FAIL. Expected only one, the default, constructor");
+        }
+        return methods.get(0);
+    }
+
+    private void handleFailure(InvocationException e) {
+        // There is no good way to see the OOME diagnostic message in the target since the
+        // TestScaffold might throw an exception while trying to print the stack trace. I.e
+        // it might get a a VMDisconnectedException before the stack trace printing finishes.
+        System.err.println("FAILURE: InvocationException thrown. Trying to determine cause...");
+        defaultHandleOOMFailure(e);
+    }
+
+    private void defaultHandleOOMFailure(Exception e) {
+        e.printStackTrace();
+        failure();
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    void invoke(String methodName, String methodSig, Value value)
+            throws Exception {
+        List args = new ArrayList(1);
+        args.add(value);
+        invoke(methodName, methodSig, args, value);
+    }
+
+    void invoke(String methodName,
+                String methodSig,
+                @SuppressWarnings("rawtypes") List args,
+                Value value) throws Exception {
+        Method method = findMethod(targetClass, methodName, methodSig);
+        if ( method == null) {
+            failure("FAILED: Can't find method: "
+                    + methodName  + " for class = " + targetClass);
+            return;
+        }
+        invoke(method, args, value);
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    void invoke(Method method, List args, Value value) throws Exception {
+        thisObject.invokeMethod(mainThread, method, args, 0);
+        System.out.println("DEBUG: Done invoking method via debugger.");
+    }
+
+    Value fieldValue(String fieldName) {
+        Field field = targetClass.fieldByName(fieldName);
+        return thisObject.getValue(field);
+    }
+
+    // Determine the pass/fail status on some heuristic and don't fail the
+    // test if < 3 of the total number of tests (currently 5) fail. This also
+    // has the nice side effect that all tests are first attempted and only
+    // all tests ran an overall pass/fail status is determined.
+    private static void determineOverallTestStatus(OomDebugTest oomTest)
+                                   throws IOException, FileNotFoundException {
+        Properties resultProps = new Properties();
+        if (!RESULT_FILE.exists()) {
+            RESULT_FILE.createNewFile();
+        }
+        FileInputStream fin = null;
+        try {
+            fin = new FileInputStream(RESULT_FILE);
+            resultProps.load(fin);
+            resultProps.put(oomTest.testMethod,
+                            Integer.toString(oomTest.failedTests));
+        } finally {
+            if (fin != null) {
+                fin.close();
+            }
+        }
+        System.out.println("DEBUG: Finished running test '"
+                           + oomTest.testMethod + "'.");
+        if (LAST_TEST.equals(oomTest.testMethod)) {
+            System.out.println("DEBUG: Determining overall test status.");
+            Set<String> actualTestsRun = new HashSet<String>();
+            int totalTests = ALL_TESTS.length;
+            int failedTests = 0;
+            for (Object key: resultProps.keySet()) {
+                actualTestsRun.add((String)key);
+                Object propVal = resultProps.get(key);
+                int value = Integer.parseInt((String)propVal);
+                failedTests += value;
+            }
+            if (!ALL_TESTS_SET.equals(actualTestsRun)) {
+                String errorMsg = "Test failed! Expected to run tests '"
+                        + ALL_TESTS_SET + "', but only these were run '"
+                        + actualTestsRun + "'";
+                throw new RuntimeException(errorMsg);
+            }
+            if (failedTests >= 3) {
+                String errorMsg = "Test failed. Expected < 3 sub-tests to fail "
+                                  + "for a pass. Got " + failedTests
+                                  + " failed tests out of " + totalTests + ".";
+                throw new RuntimeException(errorMsg);
+            }
+            RESULT_FILE.delete();
+            System.out.println("All " + totalTests + " tests passed.");
+        } else {
+            System.out.println("DEBUG: More tests to run. Coninuing.");
+            FileOutputStream fout = null;
+            try {
+                fout = new FileOutputStream(RESULT_FILE);
+                resultProps.store(fout, "Storing results after test "
+                                         + oomTest.testMethod);
+            } finally {
+                if (fout != null) {
+                    fout.close();
+                }
+            }
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        System.setProperty("test.vm.opts", "-Xmx40m"); // Set debuggee VM option
+        OomDebugTest oomTest = new OomDebugTest(args);
+        try {
+            oomTest.startTests();
+        } catch (Throwable e) {
+            System.out.println("DEBUG: Got exception for test run. " + e);
+            e.printStackTrace();
+            oomTest.failure();
+        }
+        determineOverallTestStatus(oomTest);
+    }
+
+}
--- a/jdk/test/java/beans/XMLEncoder/EnumPrivate.java	Fri Sep 30 02:52:38 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-enum EnumPrivate {
-    A0,B0,C0,D0,E0,F0,G0,H0,I0,J0,K0,L0,M0,N0,O0,P0,Q0,R0,S0,T0,U0,V0,W0,X0,Y0,Z0,
-    A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,
-    A2,B2,C2,D2,E2,F2,G2,H2,I2,J2,K2,L2,M2,N2,O2,P2,Q2,R2,S2,T2,U2,V2,W2,X2,Y2,Z2,
-    A3,B3,C3,D3,E3,F3,G3,H3,I3,J3,K3,L3,M3,N3,O3,P3,Q3,R3,S3,T3,U3,V3,W3,X3,Y3,Z3,
-    A4,B4,C4,D4,E4,F4,G4,H4,I4,J4,K4,L4,M4,N4,O4,P4,Q4,R4,S4,T4,U4,V4,W4,X4,Y4,Z4,
-    A5,B5,C5,D5,E5,F5,G5,H5,I5,J5,K5,L5,M5,N5,O5,P5,Q5,R5,S5,T5,U5,V5,W5,X5,Y5,Z5,
-    A6,B6,C6,D6,E6,F6,G6,H6,I6,J6,K6,L6,M6,N6,O6,P6,Q6,R6,S6,T6,U6,V6,W6,X6,Y6,Z6,
-    A7,B7,C7,D7,E7,F7,G7,H7,I7,J7,K7,L7,M7,N7,O7,P7,Q7,R7,S7,T7,U7,V7,W7,X7,Y7,Z7,
-    A8,B8,C8,D8,E8,F8,G8,H8,I8,J8,K8,L8,M8,N8,O8,P8,Q8,R8,S8,T8,U8,V8,W8,X8,Y8,Z8,
-    A9,B9,C9,D9,E9,F9,G9,H9,I9,J9,K9,L9,M9,N9,O9,P9,Q9,R9,S9,T9,U9,V9,W9,X9,Y9,Z9,
-}
--- a/jdk/test/java/beans/XMLEncoder/EnumPublic.java	Fri Sep 30 02:52:38 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-/*
- * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-public enum EnumPublic {A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z}
--- a/jdk/test/java/beans/XMLEncoder/java_util_Collections_CheckedCollection.java	Fri Sep 30 02:52:38 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6505888
- * @summary Tests CheckedCollection encoding
- * @author Sergey Malenkov
- */
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-public final class java_util_Collections_CheckedCollection extends AbstractTest<Collection<String>> {
-    public static void main(String[] args) {
-        new java_util_Collections_CheckedCollection().test(true);
-    }
-
-    protected Collection<String> getObject() {
-        List<String> list = Collections.singletonList("string");
-        return Collections.checkedCollection(list, String.class);
-    }
-
-    protected Collection<String> getAnotherObject() {
-        List<String> list = Collections.emptyList();
-        return Collections.checkedCollection(list, String.class);
-    }
-}
--- a/jdk/test/java/beans/XMLEncoder/java_util_Collections_CheckedList.java	Fri Sep 30 02:52:38 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6505888
- * @summary Tests CheckedList encoding
- * @author Sergey Malenkov
- */
-
-import java.util.Collections;
-import java.util.List;
-
-public final class java_util_Collections_CheckedList extends AbstractTest<List<String>> {
-    public static void main(String[] args) {
-        new java_util_Collections_CheckedList().test(true);
-    }
-
-    protected List<String> getObject() {
-        List<String> list = Collections.singletonList("string");
-        return Collections.checkedList(list, String.class);
-    }
-
-    protected List<String> getAnotherObject() {
-        List<String> list = Collections.emptyList();
-        return Collections.checkedList(list, String.class);
-    }
-}
--- a/jdk/test/java/beans/XMLEncoder/java_util_Collections_CheckedMap.java	Fri Sep 30 02:52:38 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6505888
- * @summary Tests CheckedMap encoding
- * @author Sergey Malenkov
- */
-
-import java.util.Collections;
-import java.util.Map;
-
-public final class java_util_Collections_CheckedMap extends AbstractTest<Map<String, String>> {
-    public static void main(String[] args) {
-        new java_util_Collections_CheckedMap().test(true);
-    }
-
-    protected Map<String, String> getObject() {
-        Map<String, String> map = Collections.singletonMap("key", "value");
-        return Collections.checkedMap(map, String.class, String.class);
-    }
-
-    protected Map<String, String> getAnotherObject() {
-        Map<String, String> map = Collections.emptyMap();
-        return Collections.checkedMap(map, String.class, String.class);
-    }
-}
--- a/jdk/test/java/beans/XMLEncoder/java_util_Collections_CheckedRandomAccessList.java	Fri Sep 30 02:52:38 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6505888
- * @summary Tests CheckedRandomAccessList encoding
- * @author Sergey Malenkov
- */
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-public final class java_util_Collections_CheckedRandomAccessList extends AbstractTest<List<String>> {
-    public static void main(String[] args) {
-        new java_util_Collections_CheckedRandomAccessList().test(true);
-    }
-
-    protected List<String> getObject() {
-        List<String> list = new ArrayList<String>();
-        list.add("string");
-        return Collections.checkedList(list, String.class);
-    }
-
-    protected List<String> getAnotherObject() {
-        List<String> list = new ArrayList<String>();
-        return Collections.checkedList(list, String.class);
-    }
-}
--- a/jdk/test/java/beans/XMLEncoder/java_util_Collections_CheckedSet.java	Fri Sep 30 02:52:38 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6505888
- * @summary Tests CheckedSet encoding
- * @author Sergey Malenkov
- */
-
-import java.util.Collections;
-import java.util.Set;
-
-public final class java_util_Collections_CheckedSet extends AbstractTest<Set<String>> {
-    public static void main(String[] args) {
-        new java_util_Collections_CheckedSet().test(true);
-    }
-
-    protected Set<String> getObject() {
-        Set<String> set = Collections.singleton("string");
-        return Collections.checkedSet(set, String.class);
-    }
-
-    protected Set<String> getAnotherObject() {
-        Set<String> set = Collections.emptySet();
-        return Collections.checkedSet(set, String.class);
-    }
-}
--- a/jdk/test/java/beans/XMLEncoder/java_util_Collections_CheckedSortedMap.java	Fri Sep 30 02:52:38 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6505888
- * @summary Tests CheckedSortedMap encoding
- * @author Sergey Malenkov
- */
-
-import java.util.Collections;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-public final class java_util_Collections_CheckedSortedMap extends AbstractTest<SortedMap<String, String>> {
-    public static void main(String[] args) {
-        new java_util_Collections_CheckedSortedMap().test(true);
-    }
-
-    protected SortedMap<String, String> getObject() {
-        SortedMap<String, String> map = new TreeMap<String, String>();
-        map.put("key", "value");
-        return Collections.checkedSortedMap(map, String.class, String.class);
-    }
-
-    protected SortedMap<String, String> getAnotherObject() {
-        SortedMap<String, String> map = new TreeMap<String, String>();
-        return Collections.checkedSortedMap(map, String.class, String.class);
-    }
-}
--- a/jdk/test/java/beans/XMLEncoder/java_util_Collections_CheckedSortedSet.java	Fri Sep 30 02:52:38 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6505888
- * @summary Tests CheckedSortedSet encoding
- * @author Sergey Malenkov
- */
-
-import java.util.Collections;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-public final class java_util_Collections_CheckedSortedSet extends AbstractTest<SortedSet<String>> {
-    public static void main(String[] args) {
-        new java_util_Collections_CheckedSortedSet().test(true);
-    }
-
-    protected SortedSet<String> getObject() {
-        SortedSet<String> set = new TreeSet<String>();
-        set.add("string");
-        return Collections.checkedSortedSet(set, String.class);
-    }
-
-    protected SortedSet<String> getAnotherObject() {
-        SortedSet<String> set = new TreeSet<String>();
-        return Collections.checkedSortedSet(set, String.class);
-    }
-}
--- a/jdk/test/java/beans/XMLEncoder/java_util_EnumMap.java	Fri Sep 30 02:52:38 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6536295
- * @summary Tests EnumMap encoding
- * @author Sergey Malenkov
- */
-
-import java.util.EnumMap;
-import java.util.Map;
-
-public final class java_util_EnumMap extends AbstractTest<Map<EnumPublic, String>> {
-    public static void main(String[] args) {
-        new java_util_EnumMap().test(true);
-    }
-
-    protected Map<EnumPublic, String> getObject() {
-        return new EnumMap<EnumPublic, String>(EnumPublic.class);
-    }
-
-    protected Map<EnumPublic, String> getAnotherObject() {
-        Map<EnumPublic, String> map = new EnumMap<EnumPublic, String>(EnumPublic.class);
-        map.put(EnumPublic.A, "value");
-        map.put(EnumPublic.Z, null);
-        return map;
-    }
-}
--- a/jdk/test/java/beans/XMLEncoder/java_util_JumboEnumSet.java	Fri Sep 30 02:52:38 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6536295
- * @summary Tests JumboEnumSet encoding
- * @author Sergey Malenkov
- */
-
-import java.util.EnumSet;
-import java.util.Set;
-
-public final class java_util_JumboEnumSet extends AbstractTest<Set<EnumPrivate>> {
-    public static void main(String[] args) {
-        new java_util_JumboEnumSet().test(true);
-    }
-
-    protected Set<EnumPrivate> getObject() {
-        return EnumSet.noneOf(EnumPrivate.class);
-    }
-
-    protected Set<EnumPrivate> getAnotherObject() {
-        Set<EnumPrivate> set = EnumSet.noneOf(EnumPrivate.class);
-        set.add(EnumPrivate.A0);
-        set.add(EnumPrivate.Z9);
-        return set;
-    }
-}
--- a/jdk/test/java/beans/XMLEncoder/java_util_RegularEnumSet.java	Fri Sep 30 02:52:38 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @bug 6536295
- * @summary Tests RegularEnumSet encoding
- * @author Sergey Malenkov
- */
-
-import java.util.EnumSet;
-import java.util.Set;
-
-public final class java_util_RegularEnumSet extends AbstractTest<Set<EnumPublic>> {
-    public static void main(String[] args) {
-        new java_util_RegularEnumSet().test(true);
-    }
-
-    protected Set<EnumPublic> getObject() {
-        return EnumSet.noneOf(EnumPublic.class);
-    }
-
-    protected Set<EnumPublic> getAnotherObject() {
-        Set<EnumPublic> set = EnumSet.noneOf(EnumPublic.class);
-        set.add(EnumPublic.A);
-        set.add(EnumPublic.Z);
-        return set;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/Serializable/serialFilter/CheckInputOrderTest.java	Wed Oct 05 06:28:22 2016 -0700
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.InvalidClassException;
+import java.io.ObjectInputFilter;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.security.Security;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.assertFalse;
+
+/* @test
+ * @build CheckInputOrderTest SerialFilterTest
+ * @run testng/othervm CheckInputOrderTest
+ *
+ * @summary Test that when both global filter and specific filter are set,
+ *          global filter will not affect specific filter.
+ */
+
+public class CheckInputOrderTest implements Serializable {
+    private static final long serialVersionUID = 12345678901L;
+
+    @DataProvider(name="Patterns")
+    Object[][] patterns() {
+        return new Object[][] {
+                new Object[] { SerialFilterTest.genTestObject("maxarray=1", true), "java.**;java.lang.*;java.lang.Long;maxarray=0", false },
+                new Object[] { SerialFilterTest.genTestObject("maxarray=1", true), "java.**;java.lang.*;java.lang.Long", true },
+                new Object[] { Long.MAX_VALUE, "java.**;java.lang.*;java.lang.Long;maxdepth=0", false },
+                new Object[] { Long.MAX_VALUE, "java.**;java.lang.*;java.lang.Long;maxbytes=0", false },
+                new Object[] { Long.MAX_VALUE, "java.**;java.lang.*;java.lang.Long;maxrefs=0", false },
+
+                new Object[] { Long.MAX_VALUE, "java.**;java.lang.*;java.lang.Long", true },
+
+                new Object[] { Long.MAX_VALUE, "!java.**;java.lang.*;java.lang.Long", false },
+                new Object[] { Long.MAX_VALUE, "java.**;!java.lang.*;java.lang.Long", true },
+
+                new Object[] { Long.MAX_VALUE, "!java.lang.*;java.**;java.lang.Long", false },
+                new Object[] { Long.MAX_VALUE, "java.lang.*;!java.**;java.lang.Long", true },
+
+                new Object[] { Long.MAX_VALUE, "!java.lang.Long;java.**;java.lang.*", false },
+                new Object[] { Long.MAX_VALUE, "java.lang.Long;java.**;!java.lang.*", true },
+
+                new Object[] { Long.MAX_VALUE, "java.lang.Long;!java.**;java.lang.*", false },
+                new Object[] { Long.MAX_VALUE, "java.lang.Long;java.lang.Number;!java.**;java.lang.*", true },
+        };
+    }
+
+    /**
+     * Test:
+     *   "global filter reject" + "specific ObjectInputStream filter is empty" => should reject
+     *   "global filter reject" + "specific ObjectInputStream filter allow"    => should allow
+     */
+    @Test(dataProvider="Patterns")
+    public void testRejectedInGlobal(Object toDeserialized, String pattern, boolean allowed) throws Exception {
+        byte[] bytes = SerialFilterTest.writeObjects(toDeserialized);
+        ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(pattern);
+
+        try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+                ObjectInputStream ois = new ObjectInputStream(bais)) {
+            ois.setObjectInputFilter(filter);
+            Object o = ois.readObject();
+            assertTrue(allowed, "filter should have thrown an exception");
+        } catch (InvalidClassException ice) {
+            assertFalse(allowed, "filter should have thrown an exception");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/Serializable/serialFilter/FilterWithSecurityManagerTest.java	Wed Oct 05 06:28:22 2016 -0700
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.ObjectInputFilter;
+import java.io.ObjectInputStream;
+import java.security.AccessControlException;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+/* @test
+ * @build FilterWithSecurityManagerTest SerialFilterTest
+ * @run testng/othervm FilterWithSecurityManagerTest
+ * @run testng/othervm/policy=security.policy.without.globalFilter
+ *          -Djava.security.manager=default FilterWithSecurityManagerTest
+ * @run testng/othervm/policy=security.policy
+ *          -Djava.security.manager=default
+ *          -Djdk.serialFilter=java.lang.Integer FilterWithSecurityManagerTest
+ *
+ * @summary Test that setting specific filter is checked by security manager,
+ *          setting process-wide filter is checked by security manager.
+ */
+
+@Test
+public class FilterWithSecurityManagerTest {
+
+    byte[] bytes;
+    boolean setSecurityManager;
+    ObjectInputFilter filter;
+
+    @BeforeClass
+    public void setup() throws Exception {
+        setSecurityManager = System.getSecurityManager() != null;
+        Object toDeserialized = Long.MAX_VALUE;
+        bytes = SerialFilterTest.writeObjects(toDeserialized);
+        filter = ObjectInputFilter.Config.createFilter("java.lang.Long");
+    }
+
+    /**
+     * Test that setting process-wide filter is checked by security manager.
+     */
+    @Test
+    public void testGlobalFilter() throws Exception {
+        if (ObjectInputFilter.Config.getSerialFilter() == null) {
+            return;
+        }
+        try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+                ObjectInputStream ois = new ObjectInputStream(bais)) {
+            ObjectInputFilter.Config.setSerialFilter(filter);
+            assertFalse(setSecurityManager,
+                    "When SecurityManager exists, without "
+                    + "java.security.SerializablePermission(serialFilter) Exception should be thrown");
+            Object o = ois.readObject();
+        } catch (AccessControlException ex) {
+            assertTrue(setSecurityManager);
+            assertTrue(ex.getMessage().contains("java.io.SerializablePermission"));
+            assertTrue(ex.getMessage().contains("serialFilter"));
+        }
+    }
+
+    /**
+     * Test that setting specific filter is checked by security manager.
+     */
+    @Test(dependsOnMethods = { "testGlobalFilter" })
+    public void testSpecificFilter() throws Exception {
+        try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+                ObjectInputStream ois = new ObjectInputStream(bais)) {
+            ois.setObjectInputFilter(filter);
+            Object o = ois.readObject();
+        } catch (AccessControlException ex) {
+            assertTrue(setSecurityManager);
+            assertTrue(ex.getMessage().contains("java.io.SerializablePermission"));
+            assertTrue(ex.getMessage().contains("serialFilter"));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/Serializable/serialFilter/GlobalFilterTest.java	Wed Oct 05 06:28:22 2016 -0700
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertSame;
+import static org.testng.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InvalidClassException;
+import java.io.ObjectInputFilter;
+import java.io.ObjectInputStream;
+
+import java.io.SerializablePermission;
+import java.security.Security;
+import java.util.Objects;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+
+/* @test
+ * @build GlobalFilterTest SerialFilterTest
+ * @run testng/othervm GlobalFilterTest
+ * @run testng/othervm -Djdk.serialFilter=java.** GlobalFilterTest
+ * @run testng/othervm/policy=security.policy GlobalFilterTest
+ * @run testng/othervm/policy=security.policy
+ *        -Djava.security.properties=${test.src}/java.security-extra1
+ *        -Djava.security.debug=properties GlobalFilterTest
+ *
+ * @summary Test Global Filters
+ */
+@Test
+public class GlobalFilterTest {
+
+    /**
+     * DataProvider of patterns and objects derived from the configured process-wide filter.
+     * @return Array of arrays of pattern, object, allowed boolean, and API factory
+     */
+    @DataProvider(name="globalPatternElements")
+    Object[][] globalPatternElements() {
+        String globalFilter =
+                System.getProperty("jdk.serialFilter",
+                        Security.getProperty("jdk.serialFilter"));
+        if (globalFilter == null) {
+            return new Object[0][];
+        }
+
+        String[] patterns = globalFilter.split(";");
+        Object[][] objects = new Object[patterns.length][];
+
+        for (int i = 0; i < patterns.length; i++) {
+            Object o;
+            boolean allowed;
+            String pattern = patterns[i].trim();
+            if (pattern.contains("=")) {
+                allowed = false;
+                o = SerialFilterTest.genTestObject(pattern, false);
+            } else {
+                allowed = !pattern.startsWith("!");
+                o = (allowed)
+                    ? SerialFilterTest.genTestObject(pattern, true)
+                    : SerialFilterTest.genTestObject(pattern.substring(1), false);
+
+                Assert.assertNotNull(o, "fail generation failed");
+            }
+            objects[i] = new Object[3];
+            objects[i][0] = pattern;
+            objects[i][1] = allowed;
+            objects[i][2] = o;
+        }
+        return objects;
+    }
+
+    /**
+     * Test that the process-wide filter is set when the properties are set
+     * and has the toString matching the configured pattern.
+     */
+    @Test()
+    static void globalFilter() {
+        String pattern =
+                System.getProperty("jdk.serialFilter",
+                        Security.getProperty("jdk.serialFilter"));
+        ObjectInputFilter filter = ObjectInputFilter.Config.getSerialFilter();
+        System.out.printf("global pattern: %s, filter: %s%n", pattern, filter);
+        Assert.assertEquals(pattern, Objects.toString(filter, null),
+                "process-wide filter pattern does not match");
+    }
+
+    /**
+     * If the Global filter is already set, it should always refuse to be
+     * set again.
+     * If there is a security manager, setting the serialFilter should fail
+     * without the appropriate permission.
+     * If there is no security manager then setting it should work.
+     */
+    @Test()
+    static void setGlobalFilter() {
+        SecurityManager sm = System.getSecurityManager();
+        ObjectInputFilter filter = new SerialFilterTest.Validator();
+        ObjectInputFilter global = ObjectInputFilter.Config.getSerialFilter();
+        if (global != null) {
+            // once set, can never be re-set
+            try {
+                ObjectInputFilter.Config.setSerialFilter(filter);
+                Assert.fail("set only once process-wide filter");
+            } catch (IllegalStateException ise) {
+                if (sm != null) {
+                    Assert.fail("wrong exception when security manager is set", ise);
+                }
+            } catch (SecurityException se) {
+                if (sm == null) {
+                    Assert.fail("wrong exception when security manager is not set", se);
+                }
+            }
+        } else {
+            if (sm == null) {
+                // no security manager
+                try {
+                    ObjectInputFilter.Config.setSerialFilter(filter);
+                    // Note once set, it can not be reset; so other tests
+                    System.out.printf("Global Filter set to Validator%n");
+                } catch (SecurityException se) {
+                    Assert.fail("setGlobalFilter should not get SecurityException", se);
+                }
+                try {
+                    // Try to set it again, expecting it to throw
+                    ObjectInputFilter.Config.setSerialFilter(filter);
+                    Assert.fail("set only once process-wide filter");
+                } catch (IllegalStateException ise) {
+                    // Normal case
+                }
+            } else {
+                // Security manager
+                SecurityException expectSE = null;
+                try {
+                    sm.checkPermission(new SerializablePermission("serialFilter"));
+                } catch (SecurityException se1) {
+                    expectSE = se1;
+                }
+                SecurityException actualSE = null;
+                try {
+                    ObjectInputFilter.Config.setSerialFilter(filter);
+                } catch (SecurityException se2) {
+                    actualSE = se2;
+                }
+                if (expectSE == null | actualSE == null) {
+                    Assert.assertEquals(expectSE, actualSE, "SecurityException");
+                } else {
+                    Assert.assertEquals(expectSE.getClass(), actualSE.getClass(),
+                            "SecurityException class");
+                }
+            }
+        }
+    }
+
+    /**
+     * For each pattern in the process-wide filter test a generated object
+     * against the default process-wide filter.
+     *
+     * @param pattern a pattern extracted from the configured global pattern
+     */
+    @Test(dataProvider = "globalPatternElements")
+    static void globalFilterElements(String pattern, boolean allowed,Object obj) {
+        testGlobalPattern(pattern, obj, allowed);
+    }
+
+    /**
+     * Serialize and deserialize an object using the default process-wide filter
+     * and check allowed or reject.
+     *
+     * @param pattern the pattern
+     * @param object the test object
+     * @param allowed the expected result from ObjectInputStream (exception or not)
+     */
+    static void testGlobalPattern(String pattern, Object object, boolean allowed) {
+        try {
+//            System.out.printf("global %s pattern: %s, obj: %s%n", (allowed ? "allowed" : "not allowed"), pattern, object);
+            byte[] bytes = SerialFilterTest.writeObjects(object);
+            try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+                 ObjectInputStream ois = new ObjectInputStream(bais)) {
+                Object o = ois.readObject();
+            } catch (EOFException eof) {
+                // normal completion
+            } catch (ClassNotFoundException cnf) {
+                Assert.fail("Deserializing", cnf);
+            }
+            Assert.assertTrue(allowed, "filter should have thrown an exception");
+        } catch (IllegalArgumentException iae) {
+            Assert.fail("bad format pattern", iae);
+        } catch (InvalidClassException ice) {
+            Assert.assertFalse(allowed, "filter should not have thrown an exception: " + ice);
+        } catch (IOException ioe) {
+            Assert.fail("Unexpected IOException", ioe);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/Serializable/serialFilter/MixedFiltersTest.java	Wed Oct 05 06:28:22 2016 -0700
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.InvalidClassException;
+import java.io.ObjectInputFilter;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.security.Security;
+
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+/* @test
+ * @build MixedFiltersTest SerialFilterTest
+ * @run testng/othervm -Djdk.serialFilter=!java.**;!java.lang.Long;maxdepth=5;maxarray=5;maxbytes=90;maxrefs=5          MixedFiltersTest
+ * @run testng/othervm -Djdk.serialFilter=java.**;java.lang.Long;maxdepth=1000;maxarray=1000;maxbytes=1000;maxrefs=1000 MixedFiltersTest
+ *
+ * @summary Test that when both global filter and specific filter are set,
+ *          global filter will not affect specific filter.
+ */
+
+public class MixedFiltersTest implements Serializable {
+
+    private static final long serialVersionUID = 1234567890L;
+
+
+    boolean globalRejected;
+
+    @BeforeClass
+    public void setup() {
+        String pattern = System.getProperty("jdk.serialFilter",
+                Security.getProperty("jdk.serialFilter"));
+        globalRejected = pattern.startsWith("!");
+    }
+
+    @DataProvider(name="RejectedInGlobal")
+    Object[][] rejectedInGlobal() {
+        if (!globalRejected) {
+            return new Object[0][];
+        }
+        return new Object[][] {
+                new Object[] { Long.MAX_VALUE, "java.**" },
+                new Object[] { Long.MAX_VALUE, "java.lang.Long" },
+                new Object[] { SerialFilterTest.genTestObject("java.lang.**", true), "java.lang.**" },
+                new Object[] { SerialFilterTest.genTestObject("maxdepth=10", true), "maxdepth=100" },
+                new Object[] { SerialFilterTest.genTestObject("maxarray=10", true), "maxarray=100" },
+                new Object[] { SerialFilterTest.genTestObject("maxbytes=100", true), "maxbytes=1000" },
+                new Object[] { SerialFilterTest.genTestObject("maxrefs=10", true), "maxrefs=100" },
+        };
+    }
+
+    /**
+     * Test:
+     *   "global filter reject" + "specific ObjectInputStream filter is empty" => should reject
+     *   "global filter reject" + "specific ObjectInputStream filter allow"    => should allow
+     */
+    @Test(dataProvider="RejectedInGlobal")
+    public void testRejectedInGlobal(Object toDeserialized, String pattern) throws Exception {
+        byte[] bytes = SerialFilterTest.writeObjects(toDeserialized);
+        try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+                ObjectInputStream ois = new ObjectInputStream(bais)) {
+            Object o = ois.readObject();
+            fail("filter should have thrown an exception");
+        } catch (InvalidClassException expected) { }
+
+        ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(pattern);
+        try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+                ObjectInputStream ois = new ObjectInputStream(bais)) {
+            ois.setObjectInputFilter(filter);
+            Object o = ois.readObject();
+        }
+    }
+
+    @DataProvider(name="AllowedInGlobal")
+    Object[][] allowedInGlobal() {
+        if (globalRejected) {
+            return new Object[0][];
+        }
+
+        return new Object[][] {
+                new Object[] { Long.MAX_VALUE, "!java.**" },
+                new Object[] { Long.MAX_VALUE, "!java.lang.Long" },
+                new Object[] { SerialFilterTest.genTestObject("java.lang.**", true), "!java.lang.**" },
+                new Object[] { SerialFilterTest.genTestObject("maxdepth=10", true), "maxdepth=5" },
+                new Object[] { SerialFilterTest.genTestObject("maxarray=10", true), "maxarray=5" },
+                new Object[] { SerialFilterTest.genTestObject("maxbytes=100", true), "maxbytes=5" },
+                new Object[] { SerialFilterTest.genTestObject("maxrefs=10", true), "maxrefs=5" },
+            };
+    }
+
+    /**
+     * Test:
+     *   "global filter allow" + "specific ObjectInputStream filter is empty" => should allow
+     *   "global filter allow" + "specific ObjectInputStream filter reject"   => should reject
+     */
+    @Test(dataProvider="AllowedInGlobal")
+    public void testAllowedInGlobal(Object toDeserialized, String pattern) throws Exception {
+        byte[] bytes = SerialFilterTest.writeObjects(toDeserialized);
+        try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+                ObjectInputStream ois = new ObjectInputStream(bais)) {
+            Object o = ois.readObject();
+        }
+
+        ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(pattern);
+        try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+                ObjectInputStream ois = new ObjectInputStream(bais)) {
+            ois.setObjectInputFilter(filter);
+            Object o = ois.readObject();
+            assertTrue(false, "filter should have thrown an exception");
+        } catch (InvalidClassException expected) { }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/Serializable/serialFilter/SerialFilterTest.java	Wed Oct 05 06:28:22 2016 -0700
@@ -0,0 +1,752 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InvalidClassException;
+import java.io.ObjectInputStream;
+import java.io.ObjectInputFilter;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.invoke.SerializedLambda;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Proxy;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+import java.util.concurrent.atomic.LongAdder;
+
+import javax.lang.model.SourceVersion;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+
+/* @test
+ * @build SerialFilterTest
+ * @run testng/othervm  SerialFilterTest
+ *
+ * @summary Test ObjectInputFilters
+ */
+@Test
+public class SerialFilterTest implements Serializable {
+
+    private static final long serialVersionUID = -6999613679881262446L;
+
+    /**
+     * Enable three arg lambda.
+     * @param <T> The pattern
+     * @param <U> The test object
+     * @param <V> Boolean for if the filter should allow or reject
+     */
+    interface TriConsumer< T, U, V> {
+        void accept(T t, U u, V v);
+    }
+
+    /**
+     * Misc object to use that should always be accepted.
+     */
+    private static final Object otherObject = Integer.valueOf(0);
+
+    /**
+     * DataProvider for the individual patterns to test.
+     * Expand the patterns into cases for each of the Std and Compatibility APIs.
+     * @return an array of arrays of the parameters including factories
+     */
+    @DataProvider(name="Patterns")
+    static Object[][] patterns() {
+        Object[][] patterns = new Object[][]{
+                {"java.util.Hashtable"},
+                {"java.util.Hash*"},
+                {"javax.lang.model.*"},
+                {"javax.lang.**"},
+                {"*"},
+                {"maxarray=47"},
+                {"maxdepth=5"},
+                {"maxrefs=10"},
+                {"maxbytes=100"},
+                {"maxbytes=72"},
+                {"maxbytes=+1024"},
+                {"java.base/java.util.Hashtable"},
+        };
+        return patterns;
+    }
+
+    @DataProvider(name="InvalidPatterns")
+    static Object[][] invalidPatterns() {
+        return new Object [][] {
+                {"maxrefs=-1"},
+                {"maxdepth=-1"},
+                {"maxbytes=-1"},
+                {"maxarray=-1"},
+                {"xyz=0"},
+                {"xyz=-1"},
+                {"maxrefs=0xabc"},
+                {"maxrefs=abc"},
+                {"maxrefs="},
+                {"maxrefs=+"},
+                {".*"},
+                {".**"},
+                {"!"},
+                {"/java.util.Hashtable"},
+                {"java.base/"},
+                {"/"},
+        };
+    }
+
+    @DataProvider(name="Limits")
+    static Object[][] limits() {
+        // The numbers are arbitrary > 1
+        return new Object[][]{
+                {"maxrefs", 10},
+                {"maxdepth", 5},
+                {"maxbytes", 100},
+                {"maxarray", 16},
+        };
+    }
+
+    /**
+     * DataProvider of individual objects. Used to check the information
+     * available to the filter.
+     * @return  Arrays of parameters with objects
+     */
+    @DataProvider(name="Objects")
+    static Object[][] objects() {
+        byte[] byteArray = new byte[0];
+        Object[] objArray = new Object[7];
+        objArray[objArray.length - 1] = objArray;
+
+        Class<?> serClass = null;
+        String className = "java.util.concurrent.atomic.LongAdder$SerializationProxy";
+        try {
+            serClass = Class.forName(className);
+        } catch (Exception e) {
+            Assert.fail("missing class: " + className, e);
+        }
+
+        Class<?>[] interfaces = {Runnable.class};
+        Runnable proxy = (Runnable) Proxy.newProxyInstance(null,
+                interfaces, (p, m, args) -> p);
+
+        Runnable runnable = (Runnable & Serializable) SerialFilterTest::noop;
+        Object[][] objects = {
+                { null, 0, -1, 0, 0, 0,
+                        new HashSet<>()},        // no callback, no values
+                { objArray, 3, 7, 8, 2, 55,
+                        new HashSet<>(Arrays.asList(objArray.getClass()))},
+                { Object[].class, 1, -1, 1, 1, 40,
+                        new HashSet<>(Arrays.asList(Object[].class))},
+                { new SerialFilterTest(), 1, -1, 1, 1, 37,
+                        new HashSet<>(Arrays.asList(SerialFilterTest.class))},
+                { new LongAdder(), 2, -1, 1, 1, 93,
+                        new HashSet<>(Arrays.asList(LongAdder.class, serClass))},
+                { new byte[14], 2, 14, 1, 1, 27,
+                        new HashSet<>(Arrays.asList(byteArray.getClass()))},
+                { runnable, 13, 0, 10, 2, 514,
+                        new HashSet<>(Arrays.asList(java.lang.invoke.SerializedLambda.class,
+                                SerialFilterTest.class,
+                                objArray.getClass()))},
+                { deepHashSet(10), 48, -1, 49, 11, 619,
+                        new HashSet<>(Arrays.asList(HashSet.class))},
+                { proxy.getClass(), 3, -1, 1, 1, 114,
+                        new HashSet<>(Arrays.asList(Runnable.class,
+                                java.lang.reflect.Proxy.class))},
+        };
+        return objects;
+    }
+
+    @DataProvider(name="Arrays")
+    static Object[][] arrays() {
+        return new Object[][]{
+                {new Object[16], 16},
+                {new boolean[16], 16},
+                {new byte[16], 16},
+                {new char[16], 16},
+                {new int[16], 16},
+                {new long[16], 16},
+                {new short[16], 16},
+                {new float[16], 16},
+                {new double[16], 16},
+        };
+    }
+
+
+    /**
+     * Test each object and verify the classes identified by the filter,
+     * the count of calls to the filter, the max array size, max refs, max depth,
+     * max bytes.
+     * This test ignores/is not dependent on the global filter settings.
+     *
+     * @param object a Serializable object
+     * @param count the expected count of calls to the filter
+     * @param maxArray the maximum array size
+     * @param maxRefs the maximum references
+     * @param maxDepth the maximum depth
+     * @param maxBytes the maximum stream size
+     * @param classes  the expected (unique) classes
+     * @throws IOException
+     */
+    @Test(dataProvider="Objects")
+    public static void t1(Object object,
+                          long count, long maxArray, long maxRefs, long maxDepth, long maxBytes,
+                          Set<Class<?>> classes) throws IOException {
+        byte[] bytes = writeObjects(object);
+        Validator validator = new Validator();
+        validate(bytes, validator);
+        System.out.printf("v: %s%n", validator);
+        Assert.assertEquals(validator.count, count, "callback count wrong");
+        Assert.assertEquals(validator.classes, classes, "classes mismatch");
+        Assert.assertEquals(validator.maxArray, maxArray, "maxArray mismatch");
+        Assert.assertEquals(validator.maxRefs, maxRefs, "maxRefs wrong");
+        Assert.assertEquals(validator.maxDepth, maxDepth, "depth wrong");
+        Assert.assertEquals(validator.maxBytes, maxBytes, "maxBytes wrong");
+    }
+
+    /**
+     * Test each pattern with an appropriate object.
+     * A filter is created from the pattern and used to serialize and
+     * deserialize a generated object with both the positive and negative case.
+     * This test ignores/is not dependent on the global filter settings.
+     *
+     * @param pattern a pattern
+     */
+    @Test(dataProvider="Patterns")
+    static void testPatterns(String pattern) {
+        evalPattern(pattern, (p, o, neg) -> testPatterns(p, o, neg));
+    }
+
+    /**
+     * Test that the filter on a OIS can be set only on a fresh OIS,
+     * before deserializing any objects.
+     * This test is agnostic the global filter being set or not.
+     */
+    @Test
+    static void nonResettableFilter() {
+        Validator validator1 = new Validator();
+        Validator validator2 = new Validator();
+
+        try {
+            byte[] bytes = writeObjects("text1");    // an object
+
+            try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+                 ObjectInputStream ois = new ObjectInputStream(bais)) {
+                // Check the initial filter is the global filter; may be null
+                ObjectInputFilter global = ObjectInputFilter.Config.getSerialFilter();
+                ObjectInputFilter initial = ois.getObjectInputFilter();
+                Assert.assertEquals(global, initial, "initial filter should be the global filter");
+
+                // Check if it can be set to null
+                ois.setObjectInputFilter(null);
+                ObjectInputFilter filter = ois.getObjectInputFilter();
+                Assert.assertNull(filter, "set to null should be null");
+
+                ois.setObjectInputFilter(validator1);
+                Object o = ois.readObject();
+                try {
+                    ois.setObjectInputFilter(validator2);
+                    Assert.fail("Should not be able to set filter twice");
+                } catch (IllegalStateException ise) {
+                    // success, the exception was expected
+                }
+            } catch (EOFException eof) {
+                Assert.fail("Should not reach end-of-file", eof);
+            } catch (ClassNotFoundException cnf) {
+                Assert.fail("Deserializing", cnf);
+            }
+        } catch (IOException ex) {
+            Assert.fail("Unexpected IOException", ex);
+        }
+    }
+
+    /**
+     * Test that if an Objects readReadResolve method returns an array
+     * that the callback to the filter includes the proper array length.
+     * @throws IOException if an error occurs
+     */
+    @Test(dataProvider="Arrays")
+    static void testReadResolveToArray(Object array, int length) throws IOException {
+        ReadResolveToArray object = new ReadResolveToArray(array, length);
+        byte[] bytes = writeObjects(object);
+        Object o = validate(bytes, object);    // the object is its own filter
+        Assert.assertEquals(o.getClass(), array.getClass(), "Filter not called with the array");
+    }
+
+
+    /**
+     * Test repeated limits use the last value.
+     * Construct a filter with the limit and the limit repeated -1.
+     * Invoke the filter with the limit to make sure it is rejected.
+     * Invoke the filter with the limit -1 to make sure it is accepted.
+     * @param name the name of the limit to test
+     * @param value a test value
+     */
+    @Test(dataProvider="Limits")
+    static void testLimits(String name, int value) {
+        Class<?> arrayClass = new int[0].getClass();
+        String pattern = String.format("%s=%d;%s=%d", name, value, name, value - 1);
+        ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(pattern);
+        Assert.assertEquals(
+                filter.checkInput(new FilterValues(arrayClass, value, value, value, value)),
+                ObjectInputFilter.Status.REJECTED,
+                "last limit value not used: " + filter);
+        Assert.assertEquals(
+                filter.checkInput(new FilterValues(arrayClass, value-1, value-1, value-1, value-1)),
+                ObjectInputFilter.Status.UNDECIDED,
+                "last limit value not used: " + filter);
+    }
+
+    /**
+     * Test that returning null from a filter causes deserialization to fail.
+     */
+    @Test(expectedExceptions=InvalidClassException.class)
+    static void testNullStatus() throws IOException {
+        byte[] bytes = writeObjects(0); // an Integer
+        try {
+            Object o = validate(bytes, new ObjectInputFilter() {
+                public ObjectInputFilter.Status checkInput(ObjectInputFilter.FilterInfo f) {
+                    return null;
+                }
+            });
+        } catch (InvalidClassException ice) {
+            System.out.printf("Success exception: %s%n", ice);
+            throw ice;
+        }
+    }
+
+    /**
+     * Verify that malformed patterns throw IAE.
+     * @param pattern pattern from the data source
+     */
+    @Test(dataProvider="InvalidPatterns", expectedExceptions=IllegalArgumentException.class)
+    static void testInvalidPatterns(String pattern) {
+        try {
+            ObjectInputFilter.Config.createFilter(pattern);
+        } catch (IllegalArgumentException iae) {
+            System.out.printf("    success exception: %s%n", iae);
+            throw iae;
+        }
+    }
+
+    /**
+     * Test that Config.create returns null if the argument does not contain any patterns or limits.
+     */
+    @Test()
+    static void testEmptyPattern() {
+        ObjectInputFilter filter = ObjectInputFilter.Config.createFilter("");
+        Assert.assertNull(filter, "empty pattern did not return null");
+
+        filter = ObjectInputFilter.Config.createFilter(";;;;");
+        Assert.assertNull(filter, "pattern with only delimiters did not return null");
+    }
+
+    /**
+     * Read objects from the serialized stream, validated with the filter.
+     *
+     * @param bytes a byte array to read objects from
+     * @param filter the ObjectInputFilter
+     * @return the object deserialized if any
+     * @throws IOException can be thrown
+     */
+    static Object validate(byte[] bytes,
+                         ObjectInputFilter filter) throws IOException {
+        try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+             ObjectInputStream ois = new ObjectInputStream(bais)) {
+            ois.setObjectInputFilter(filter);
+
+            Object o = ois.readObject();
+            return o;
+        } catch (EOFException eof) {
+            // normal completion
+        } catch (ClassNotFoundException cnf) {
+            Assert.fail("Deserializing", cnf);
+        }
+        return null;
+    }
+
+    /**
+     * Write objects and return a byte array with the bytes.
+     *
+     * @param objects zero or more objects to serialize
+     * @return the byte array of the serialized objects
+     * @throws IOException if an exception occurs
+     */
+    static byte[] writeObjects(Object... objects)  throws IOException {
+        byte[] bytes;
+        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
+             ObjectOutputStream oos = new ObjectOutputStream(baos)) {
+            for (Object o : objects) {
+                oos.writeObject(o);
+            }
+            bytes = baos.toByteArray();
+        }
+        return bytes;
+    }
+
+    /**
+     * A filter that accumulates information about the checkInput callbacks
+     * that can be checked after readObject completes.
+     */
+    static class Validator implements ObjectInputFilter {
+        long count;          // Count of calls to checkInput
+        HashSet<Class<?>> classes = new HashSet<>();
+        long maxArray = -1;
+        long maxRefs;
+        long maxDepth;
+        long maxBytes;
+
+        Validator() {
+        }
+
+        @Override
+        public ObjectInputFilter.Status checkInput(FilterInfo filter) {
+            count++;
+            if (filter.serialClass() != null) {
+                if (filter.serialClass().getName().contains("$$Lambda$")) {
+                    // TBD: proper identification of serialized Lambdas?
+                    // Fold the serialized Lambda into the SerializedLambda type
+                    classes.add(SerializedLambda.class);
+                } else if (Proxy.isProxyClass(filter.serialClass())) {
+                    classes.add(Proxy.class);
+                } else {
+                    classes.add(filter.serialClass());
+                }
+
+            }
+            this.maxArray = Math.max(this.maxArray, filter.arrayLength());
+            this.maxRefs = Math.max(this.maxRefs, filter.references());
+            this.maxDepth = Math.max(this.maxDepth, filter.depth());
+            this.maxBytes = Math.max(this.maxBytes, filter.streamBytes());
+            return ObjectInputFilter.Status.UNDECIDED;
+        }
+
+        public String toString(){
+            return "count: " + count
+                    + ", classes: " + classes.toString()
+                    + ", maxArray: " + maxArray
+                    + ", maxRefs: " + maxRefs
+                    + ", maxDepth: " + maxDepth
+