changeset 41368:b99d40d57eb6

Merge
author amurillo
date Wed, 05 Oct 2016 06:28:23 -0700
parents 9a11eddf3f82 910288d26d83
children 1b1baa484935
files jdk/make/Import.gmk jdk/make/lib/CoreLibraries.gmk jdk/test/ProblemList.txt 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 212 files changed, 8236 insertions(+), 2874 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Fri Sep 30 02:52:42 2016 -0700
+++ b/.hgtags	Wed Oct 05 06:28:23 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:42 2016 -0700
+++ b/.hgtags-top-repo	Wed Oct 05 06:28:23 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:42 2016 -0700
+++ b/common/autoconf/buildjdk-spec.gmk.in	Wed Oct 05 06:28:23 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:42 2016 -0700
+++ b/common/autoconf/generated-configure.sh	Wed Oct 05 06:28:23 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,17 +53086,18 @@
 
 
   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; }
+    # 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="-static-libstdc++ -static-libgcc"
     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++"
+    OLD_LIBS="$LIBS"
+    LIBS="$STATIC_STDCXX_FLAGS"
     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -53110,118 +53110,50 @@
 }
 _ACEOF
 if ac_fn_cxx_try_link "$LINENO"; then :
-  has_dynamic_libstdcxx=yes
-else
-  has_dynamic_libstdcxx=no
+  has_static_libstdcxx=yes
+else
+  has_static_libstdcxx=no
 fi
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
-    CXXFLAGS="$OLD_CXXFLAGS"
+    LIBS="$OLD_LIBS"
     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"
-    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_LIBS="$LIBS"
-    OLD_CXX="$CXX"
-    LIBS="$STATIC_STDCXX_FLAGS"
-    CXX="$CC"
-    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_static_libstdcxx=yes
-else
-  has_static_libstdcxx=no
-fi
-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'
-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_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"
+    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_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_LIBS="-lstdc++ $OPENJDK_BUILD_JVM_LIBS"
-      LDCXX="$CXX"
-      STATIC_CXX_SETTING="STATIC_CXX=false"
-      { $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"
-      # 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:42 2016 -0700
+++ b/common/autoconf/lib-std.m4	Wed Oct 05 06:28:23 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:42 2016 -0700
+++ b/corba/.hgtags	Wed Oct 05 06:28:23 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:42 2016 -0700
+++ b/corba/make/gensrc/Gensrc-java.corba.gmk	Wed Oct 05 06:28:23 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/.hgtags	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/.hgtags	Wed Oct 05 06:28:23 2016 -0700
@@ -540,3 +540,4 @@
 3b1c4562953db47e36b237a500f368d5c9746d47 jdk-9+135
 a20da289f646ee44440695b81abc0548330e4ca7 jdk-9+136
 dfcbf839e299e7e2bba1da69bdb347617ea4c7e8 jdk-9+137
+fc0956308c7a586267c5dd35dff74f773aa9c3eb jdk-9+138
--- a/hotspot/make/lib/CompileGtest.gmk	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/make/lib/CompileGtest.gmk	Wed Oct 05 06:28:23 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:42 2016 -0700
+++ b/hotspot/make/lib/CompileJvm.gmk	Wed Oct 05 06:28:23 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)
@@ -194,7 +187,7 @@
 # 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), \
     SRC := $(JVM_SRC_DIRS), \
--- a/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java	Wed Oct 05 06:28:23 2016 -0700
@@ -68,6 +68,7 @@
     Type type            = db.lookupType("InstanceKlass");
     arrayKlasses         = new MetadataField(type.getAddressField("_array_klasses"), 0);
     methods              = type.getAddressField("_methods");
+    defaultMethods       = type.getAddressField("_default_methods");
     methodOrdering       = type.getAddressField("_method_ordering");
     localInterfaces      = type.getAddressField("_local_interfaces");
     transitiveInterfaces = type.getAddressField("_transitive_interfaces");
@@ -128,6 +129,7 @@
 
   private static MetadataField arrayKlasses;
   private static AddressField  methods;
+  private static AddressField  defaultMethods;
   private static AddressField  methodOrdering;
   private static AddressField  localInterfaces;
   private static AddressField  transitiveInterfaces;
@@ -335,6 +337,20 @@
   // Accessors for declared fields
   public Klass     getArrayKlasses()        { return (Klass)        arrayKlasses.getValue(this); }
   public MethodArray  getMethods()              { return new MethodArray(methods.getValue(getAddress())); }
+
+  public MethodArray  getDefaultMethods() {
+    if (defaultMethods != null) {
+      Address addr = defaultMethods.getValue(getAddress());
+      if ((addr != null) && (addr.getAddressAt(0) != null)) {
+        return new MethodArray(addr);
+      } else {
+        return null;
+      }
+    } else {
+      return null;
+    }
+  }
+
   public KlassArray   getLocalInterfaces()      { return new KlassArray(localInterfaces.getValue(getAddress())); }
   public KlassArray   getTransitiveInterfaces() { return new KlassArray(transitiveInterfaces.getValue(getAddress())); }
   public int       getJavaFieldsCount()     { return                (int) javaFieldsCount.getValue(this); }
--- a/hotspot/src/share/vm/classfile/classLoader.cpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/classfile/classLoader.cpp	Wed Oct 05 06:28:23 2016 -0700
@@ -1358,7 +1358,7 @@
   if (!Universe::is_module_initialized() &&
       !ModuleEntryTable::javabase_defined() &&
       mod_entry == NULL) {
-    mod_entry = ModuleEntryTable::javabase_module();
+    mod_entry = ModuleEntryTable::javabase_moduleEntry();
   }
 
   // The module must be a named module
@@ -1708,7 +1708,7 @@
     if (jb_module == NULL) {
       vm_exit_during_initialization("Unable to create ModuleEntry for java.base");
     }
-    ModuleEntryTable::set_javabase_module(jb_module);
+    ModuleEntryTable::set_javabase_moduleEntry(jb_module);
   }
 }
 
--- a/hotspot/src/share/vm/classfile/javaClasses.cpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/classfile/javaClasses.cpp	Wed Oct 05 06:28:23 2016 -0700
@@ -773,6 +773,41 @@
   InstanceKlass::cast(k())->do_local_static_fields(&initialize_static_field, mirror, CHECK);
 }
 
+// Set the java.lang.reflect.Module module field in the java_lang_Class mirror
+void java_lang_Class::set_mirror_module_field(KlassHandle k, Handle mirror, Handle module, TRAPS) {
+  if (module.is_null()) {
+    // During startup, the module may be NULL only if java.base has not been defined yet.
+    // Put the class on the fixup_module_list to patch later when the java.lang.reflect.Module
+    // for java.base is known.
+    assert(!Universe::is_module_initialized(), "Incorrect java.lang.reflect.Module pre module system initialization");
+    MutexLocker m1(Module_lock, THREAD);
+    // Keep list of classes needing java.base module fixup
+    if (!ModuleEntryTable::javabase_defined()) {
+      if (fixup_module_field_list() == NULL) {
+        GrowableArray<Klass*>* list =
+          new (ResourceObj::C_HEAP, mtModule) GrowableArray<Klass*>(500, true);
+        set_fixup_module_field_list(list);
+      }
+      k->class_loader_data()->inc_keep_alive();
+      fixup_module_field_list()->push(k());
+    } else {
+      // java.base was defined at some point between calling create_mirror()
+      // and obtaining the Module_lock, patch this particular class with java.base.
+      ModuleEntry *javabase_entry = ModuleEntryTable::javabase_moduleEntry();
+      assert(javabase_entry != NULL && javabase_entry->module() != NULL,
+             "Setting class module field, java.base should be defined");
+      Handle javabase_handle(THREAD, JNIHandles::resolve(javabase_entry->module()));
+      set_module(mirror(), javabase_handle());
+    }
+  } else {
+    assert(Universe::is_module_initialized() ||
+           (ModuleEntryTable::javabase_defined() &&
+            (module() == JNIHandles::resolve(ModuleEntryTable::javabase_moduleEntry()->module()))),
+           "Incorrect java.lang.reflect.Module specification while creating mirror");
+    set_module(mirror(), module());
+  }
+}
+
 void java_lang_Class::create_mirror(KlassHandle k, Handle class_loader,
                                     Handle module, Handle protection_domain, TRAPS) {
   assert(k->java_mirror() == NULL, "should only assign mirror once");
@@ -835,25 +870,13 @@
     set_class_loader(mirror(), class_loader());
 
     // set the module field in the java_lang_Class instance
-    // This may be null during bootstrap but will get fixed up later on.
-    set_module(mirror(), module());
+    set_mirror_module_field(k, mirror, module, THREAD);
 
     // Setup indirection from klass->mirror last
     // after any exceptions can happen during allocations.
     if (!k.is_null()) {
       k->set_java_mirror(mirror());
     }
-
-    // Keep list of classes needing java.base module fixup.
-    if (!ModuleEntryTable::javabase_defined()) {
-      if (fixup_module_field_list() == NULL) {
-        GrowableArray<Klass*>* list =
-          new (ResourceObj::C_HEAP, mtModule) GrowableArray<Klass*>(500, true);
-        set_fixup_module_field_list(list);
-      }
-      k->class_loader_data()->inc_keep_alive();
-      fixup_module_field_list()->push(k());
-    }
   } else {
     if (fixup_mirror_list() == NULL) {
       GrowableArray<Klass*>* list =
--- a/hotspot/src/share/vm/classfile/javaClasses.hpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/classfile/javaClasses.hpp	Wed Oct 05 06:28:23 2016 -0700
@@ -219,6 +219,7 @@
   static void set_class_loader(oop java_class, oop class_loader);
   static void set_component_mirror(oop java_class, oop comp_mirror);
   static void initialize_mirror_fields(KlassHandle k, Handle mirror, Handle protection_domain, TRAPS);
+  static void set_mirror_module_field(KlassHandle K, Handle mirror, Handle module, TRAPS);
  public:
   static void compute_offsets();
 
--- a/hotspot/src/share/vm/classfile/klassFactory.cpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/classfile/klassFactory.cpp	Wed Oct 05 06:28:23 2016 -0700
@@ -25,12 +25,85 @@
 #include "precompiled.hpp"
 #include "classfile/classFileParser.hpp"
 #include "classfile/classFileStream.hpp"
+#include "classfile/classLoader.hpp"
 #include "classfile/classLoaderData.hpp"
+#include "classfile/classLoaderData.inline.hpp"
 #include "classfile/klassFactory.hpp"
+#include "classfile/sharedClassUtil.hpp"
+#include "memory/metaspaceShared.hpp"
 #include "memory/resourceArea.hpp"
 #include "prims/jvmtiEnvBase.hpp"
+#include "prims/jvmtiRedefineClasses.hpp"
 #include "trace/traceMacros.hpp"
 
+// called during initial loading of a shared class
+instanceKlassHandle KlassFactory::check_shared_class_file_load_hook(
+                                          instanceKlassHandle ik,
+                                          Symbol* class_name,
+                                          Handle class_loader,
+                                          Handle protection_domain, TRAPS) {
+#if INCLUDE_CDS && INCLUDE_JVMTI
+  assert(ik.not_null(), "sanity");
+  assert(ik()->is_shared(), "expecting a shared class");
+
+  if (JvmtiExport::should_post_class_file_load_hook()) {
+    assert(THREAD->is_Java_thread(), "must be JavaThread");
+
+    // Post the CFLH
+    JvmtiCachedClassFileData* cached_class_file = NULL;
+    JvmtiCachedClassFileData* archived_class_data = ik->get_archived_class_data();
+    assert(archived_class_data != NULL, "shared class has no archived class data");
+    unsigned char* ptr =
+        VM_RedefineClasses::get_cached_class_file_bytes(archived_class_data);
+    unsigned char* end_ptr =
+        ptr + VM_RedefineClasses::get_cached_class_file_len(archived_class_data);
+    unsigned char* old_ptr = ptr;
+    JvmtiExport::post_class_file_load_hook(class_name,
+                                           class_loader,
+                                           protection_domain,
+                                           &ptr,
+                                           &end_ptr,
+                                           &cached_class_file);
+    if (old_ptr != ptr) {
+      // JVMTI agent has modified class file data.
+      // Set new class file stream using JVMTI agent modified class file data.
+      ClassLoaderData* loader_data =
+        ClassLoaderData::class_loader_data(class_loader());
+      int path_index = ik->shared_classpath_index();
+      SharedClassPathEntry* ent =
+        (SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index);
+      ClassFileStream* stream = new ClassFileStream(ptr,
+                                                    end_ptr - ptr,
+                                                    ent->_name,
+                                                    ClassFileStream::verify);
+      ClassFileParser parser(stream,
+                             class_name,
+                             loader_data,
+                             protection_domain,
+                             NULL,
+                             NULL,
+                             ClassFileParser::BROADCAST, // publicity level
+                             CHECK_NULL);
+      instanceKlassHandle new_ik = parser.create_instance_klass(true /* changed_by_loadhook */,
+                                                                CHECK_NULL);
+      if (cached_class_file != NULL) {
+        new_ik->set_cached_class_file(cached_class_file);
+      }
+
+      if (class_loader.is_null()) {
+        ResourceMark rm;
+        ClassLoader::add_package(class_name->as_C_string(), path_index, THREAD);
+      }
+
+      return new_ik;
+    }
+  }
+#endif
+
+  return NULL;
+}
+
+
 static ClassFileStream* check_class_file_load_hook(ClassFileStream* stream,
                                                    Symbol* name,
                                                    ClassLoaderData* loader_data,
@@ -97,7 +170,6 @@
                                                      const InstanceKlass* host_klass,
                                                      GrowableArray<Handle>* cp_patches,
                                                      TRAPS) {
-
   assert(stream != NULL, "invariant");
   assert(loader_data != NULL, "invariant");
   assert(THREAD->is_Java_thread(), "must be a JavaThread");
@@ -142,5 +214,27 @@
 
   TRACE_KLASS_CREATION(result, parser, THREAD);
 
+#if INCLUDE_CDS && INCLUDE_JVMTI
+  if (DumpSharedSpaces) {
+    assert(cached_class_file == NULL, "Sanity");
+    // Archive the class stream data into the optional data section
+    JvmtiCachedClassFileData *p;
+    int len;
+    const unsigned char *bytes;
+    // event based tracing might set cached_class_file
+    if ((bytes = result->get_cached_class_file_bytes()) != NULL) {
+      len = result->get_cached_class_file_len();
+    } else {
+      len = stream->length();
+      bytes = stream->buffer();
+    }
+    p = (JvmtiCachedClassFileData*)MetaspaceShared::optional_data_space_alloc(
+                    offset_of(JvmtiCachedClassFileData, data) + len);
+    p->length = len;
+    memcpy(p->data, bytes, len);
+    result->set_archived_class_data(p);
+  }
+#endif
+
   return result;
 }
--- a/hotspot/src/share/vm/classfile/klassFactory.hpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/classfile/klassFactory.hpp	Wed Oct 05 06:28:23 2016 -0700
@@ -75,6 +75,12 @@
                                                 const InstanceKlass* host_klass,
                                                 GrowableArray<Handle>* cp_patches,
                                                 TRAPS);
+ public:
+  static instanceKlassHandle check_shared_class_file_load_hook(
+                                          instanceKlassHandle ik,
+                                          Symbol* class_name,
+                                          Handle class_loader,
+                                          Handle protection_domain, TRAPS);
 };
 
 #endif // SHARE_VM_CLASSFILE_KLASSFACTORY_HPP
--- a/hotspot/src/share/vm/classfile/moduleEntry.cpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/classfile/moduleEntry.cpp	Wed Oct 05 06:28:23 2016 -0700
@@ -92,7 +92,7 @@
   // read java.base.  If either of these conditions
   // hold, readability has been established.
   if (!this->is_named() ||
-      (m == ModuleEntryTable::javabase_module())) {
+      (m == ModuleEntryTable::javabase_moduleEntry())) {
     return true;
   }
 
@@ -358,16 +358,27 @@
   }
 
   // Set java.lang.reflect.Module, version and location for java.base
-  ModuleEntry* jb_module = javabase_module();
+  ModuleEntry* jb_module = javabase_moduleEntry();
   assert(jb_module != NULL, "java.base ModuleEntry not defined");
-  jb_module->set_module(boot_loader_data->add_handle(module_handle));
   jb_module->set_version(version);
   jb_module->set_location(location);
+  // Once java.base's ModuleEntry _module field is set with the known
+  // java.lang.reflect.Module, java.base is considered "defined" to the VM.
+  jb_module->set_module(boot_loader_data->add_handle(module_handle));
+
   // Store pointer to the ModuleEntry for java.base in the java.lang.reflect.Module object.
   java_lang_reflect_Module::set_module_entry(module_handle(), jb_module);
+
+  // Patch any previously loaded classes' module field with java.base's java.lang.reflect.Module.
+  patch_javabase_entries(module_handle);
 }
 
+// Within java.lang.Class instances there is a java.lang.reflect.Module field
+// that must be set with the defining module.  During startup, prior to java.base's
+// definition, classes needing their module field set are added to the fixup_module_list.
+// Their module field is set once java.base's java.lang.reflect.Module is known to the VM.
 void ModuleEntryTable::patch_javabase_entries(Handle module_handle) {
+  assert(Module_lock->owned_by_self(), "should have the Module_lock");
   if (module_handle.is_null()) {
     fatal("Unable to patch the module field of classes loaded prior to java.base's definition, invalid java.lang.reflect.Module");
   }
@@ -389,9 +400,7 @@
   for (int i = 0; i < list_length; i++) {
     Klass* k = list->at(i);
     assert(k->is_klass(), "List should only hold classes");
-    Thread* THREAD = Thread::current();
-    KlassHandle kh(THREAD, k);
-    java_lang_Class::fixup_module_field(kh, module_handle);
+    java_lang_Class::fixup_module_field(KlassHandle(k), module_handle);
     k->class_loader_data()->dec_keep_alive();
   }
 
--- a/hotspot/src/share/vm/classfile/moduleEntry.hpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/classfile/moduleEntry.hpp	Wed Oct 05 06:28:23 2016 -0700
@@ -78,11 +78,11 @@
     _must_walk_reads = false;
   }
 
-  Symbol*          name() const          { return literal(); }
-  void             set_name(Symbol* n)   { set_literal(n); }
+  Symbol*          name() const                        { return literal(); }
+  void             set_name(Symbol* n)                 { set_literal(n); }
 
-  jobject          module() const        { return _module; }
-  void             set_module(jobject j) { _module = j; }
+  jobject          module() const                      { return _module; }
+  void             set_module(jobject j)               { _module = j; }
 
   // The shared ProtectionDomain reference is set once the VM loads a shared class
   // originated from the current Module. The referenced ProtectionDomain object is
@@ -217,13 +217,13 @@
 
   // Special handling for unnamed module, one per class loader's ModuleEntryTable
   void create_unnamed_module(ClassLoaderData* loader_data);
-  ModuleEntry* unnamed_module()                           { return _unnamed_module; }
+  ModuleEntry* unnamed_module()                                { return _unnamed_module; }
 
   // Special handling for java.base
-  static ModuleEntry* javabase_module()                   { return _javabase_module; }
-  static void set_javabase_module(ModuleEntry* java_base) { _javabase_module = java_base; }
-  static bool javabase_defined()                          { return ((_javabase_module != NULL) &&
-                                                                    (_javabase_module->module() != NULL)); }
+  static ModuleEntry* javabase_moduleEntry()                   { return _javabase_module; }
+  static void set_javabase_moduleEntry(ModuleEntry* java_base) { _javabase_module = java_base; }
+  static bool javabase_defined()                               { return ((_javabase_module != NULL) &&
+                                                                         (_javabase_module->module() != NULL)); }
   static void finalize_javabase(Handle module_handle, Symbol* version, Symbol* location);
   static void patch_javabase_entries(Handle module_handle);
 
--- a/hotspot/src/share/vm/classfile/modules.cpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/classfile/modules.cpp	Wed Oct 05 06:28:23 2016 -0700
@@ -206,7 +206,7 @@
   assert(pkg_list->length() == 0 || package_table != NULL, "Bad package_table");
 
   // Ensure java.base's ModuleEntry has been created
-  assert(ModuleEntryTable::javabase_module() != NULL, "No ModuleEntry for java.base");
+  assert(ModuleEntryTable::javabase_moduleEntry() != NULL, "No ModuleEntry for java.base");
 
   bool duplicate_javabase = false;
   {
@@ -226,7 +226,7 @@
       for (int x = 0; x < pkg_list->length(); x++) {
         // Some of java.base's packages were added early in bootstrapping, ignore duplicates.
         if (package_table->lookup_only(pkg_list->at(x)) == NULL) {
-          pkg = package_table->locked_create_entry_or_null(pkg_list->at(x), ModuleEntryTable::javabase_module());
+          pkg = package_table->locked_create_entry_or_null(pkg_list->at(x), ModuleEntryTable::javabase_moduleEntry());
           assert(pkg != NULL, "Unable to create a java.base package entry");
         }
         // Unable to have a GrowableArray of TempNewSymbol.  Must decrement the refcount of
@@ -255,9 +255,6 @@
     log_trace(modules)("define_javabase_module(): creation of package %s for module java.base",
                        (pkg_list->at(x))->as_C_string());
   }
-
-  // Patch any previously loaded classes' module field with java.base's jlr.Module.
-  ModuleEntryTable::patch_javabase_entries(module_handle);
 }
 
 void Modules::define_module(jobject module, jstring version,
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp	Wed Oct 05 06:28:23 2016 -0700
@@ -1210,16 +1210,12 @@
 
 instanceKlassHandle SystemDictionary::load_shared_class(
                  Symbol* class_name, Handle class_loader, TRAPS) {
-  // Don't load shared class when JvmtiExport::should_post_class_file_load_hook()
-  // is enabled since posting CFLH is not supported when loading shared class.
-  if (!JvmtiExport::should_post_class_file_load_hook()) {
-    instanceKlassHandle ik (THREAD, find_shared_class(class_name));
-    // Make sure we only return the boot class for the NULL classloader.
-    if (ik.not_null() &&
-        ik->is_shared_boot_class() && class_loader.is_null()) {
-      Handle protection_domain;
-      return load_shared_class(ik, class_loader, protection_domain, THREAD);
-    }
+  instanceKlassHandle ik (THREAD, find_shared_class(class_name));
+  // Make sure we only return the boot class for the NULL classloader.
+  if (ik.not_null() &&
+      ik->is_shared_boot_class() && class_loader.is_null()) {
+    Handle protection_domain;
+    return load_shared_class(ik, class_loader, protection_domain, THREAD);
   }
   return instanceKlassHandle();
 }
@@ -1303,11 +1299,6 @@
                                                         Handle class_loader,
                                                         Handle protection_domain, TRAPS) {
   instanceKlassHandle nh = instanceKlassHandle(); // null Handle
-  if (JvmtiExport::should_post_class_file_load_hook()) {
-    // Don't load shared class when JvmtiExport::should_post_class_file_load_hook()
-    // is enabled since posting CFLH is not supported when loading shared class.
-    return nh;
-  }
 
   if (ik.not_null()) {
     Symbol* class_name = ik->name();
@@ -1358,6 +1349,14 @@
       }
     }
 
+    instanceKlassHandle new_ik = KlassFactory::check_shared_class_file_load_hook(
+        ik, class_name, class_loader, protection_domain, CHECK_(nh));
+    if (new_ik.not_null()) {
+      // The class is changed by CFLH. Return the new class. The shared class is
+      // not used.
+      return new_ik;
+    }
+
     // Adjust methods to recover missing data.  They need addresses for
     // interpreter entry points and their default native method address
     // must be reset.
--- a/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/cms/parNewGeneration.cpp	Wed Oct 05 06:28:23 2016 -0700
@@ -1366,22 +1366,25 @@
      return false;
   }
   assert(prefix != NULL && prefix != BUSY, "Error");
-  size_t i = 1;
   oop cur = prefix;
-  while (i < objsFromOverflow && cur->klass_or_null() != NULL) {
-    i++; cur = cur->list_ptr_from_klass();
+  for (size_t i = 1; i < objsFromOverflow; ++i) {
+    oop next = cur->list_ptr_from_klass();
+    if (next == NULL) break;
+    cur = next;
   }
+  assert(cur != NULL, "Loop postcondition");
 
   // Reattach remaining (suffix) to overflow list
-  if (cur->klass_or_null() == NULL) {
+  oop suffix = cur->list_ptr_from_klass();
+  if (suffix == NULL) {
     // Write back the NULL in lieu of the BUSY we wrote
     // above and it is still the same value.
     if (_overflow_list == BUSY) {
       (void) Atomic::cmpxchg_ptr(NULL, &_overflow_list, BUSY);
     }
   } else {
-    assert(cur->klass_or_null() != (Klass*)(address)BUSY, "Error");
-    oop suffix = cur->list_ptr_from_klass();       // suffix will be put back on global list
+    assert(suffix != BUSY, "Error");
+    // suffix will be put back on global list
     cur->set_klass_to_list_ptr(NULL);     // break off suffix
     // It's possible that the list is still in the empty(busy) state
     // we left it in a short while ago; in that case we may be
@@ -1401,8 +1404,10 @@
       // Too bad, someone else got in in between; we'll need to do a splice.
       // Find the last item of suffix list
       oop last = suffix;
-      while (last->klass_or_null() != NULL) {
-        last = last->list_ptr_from_klass();
+      while (true) {
+        oop next = last->list_ptr_from_klass();
+        if (next == NULL) break;
+        last = next;
       }
       // Atomically prepend suffix to current overflow list
       observed_overflow_list = _overflow_list;
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp	Wed Oct 05 06:28:23 2016 -0700
@@ -1479,7 +1479,7 @@
                               "Capacity: " SIZE_FORMAT "B occupancy: " SIZE_FORMAT "B min_desired_capacity: " SIZE_FORMAT "B (" UINTX_FORMAT " %%)",
                               capacity_after_gc, used_after_gc, minimum_desired_capacity, MinHeapFreeRatio);
 
-    expand(expand_bytes);
+    expand(expand_bytes, _workers);
 
     // No expansion, now see if we want to shrink
   } else if (capacity_after_gc > maximum_desired_capacity) {
@@ -1599,7 +1599,7 @@
                             word_size * HeapWordSize);
 
 
-  if (expand(expand_bytes)) {
+  if (expand(expand_bytes, _workers)) {
     _hrm.verify_optional();
     _verifier->verify_region_sets_optional();
     return attempt_allocation_at_safepoint(word_size,
@@ -1609,7 +1609,7 @@
   return NULL;
 }
 
-bool G1CollectedHeap::expand(size_t expand_bytes, double* expand_time_ms) {
+bool G1CollectedHeap::expand(size_t expand_bytes, WorkGang* pretouch_workers, double* expand_time_ms) {
   size_t aligned_expand_bytes = ReservedSpace::page_align_size_up(expand_bytes);
   aligned_expand_bytes = align_size_up(aligned_expand_bytes,
                                        HeapRegion::GrainBytes);
@@ -1626,7 +1626,7 @@
   uint regions_to_expand = (uint)(aligned_expand_bytes / HeapRegion::GrainBytes);
   assert(regions_to_expand > 0, "Must expand by at least one region");
 
-  uint expanded_by = _hrm.expand_by(regions_to_expand);
+  uint expanded_by = _hrm.expand_by(regions_to_expand, pretouch_workers);
   if (expand_time_ms != NULL) {
     *expand_time_ms = (os::elapsedTime() - expand_heap_start_time_sec) * MILLIUNITS;
   }
@@ -1927,7 +1927,7 @@
   _cmThread = _cm->cmThread();
 
   // Now expand into the initial heap size.
-  if (!expand(init_byte_size)) {
+  if (!expand(init_byte_size, _workers)) {
     vm_shutdown_during_initialization("Failed to allocate initial heap.");
     return JNI_ENOMEM;
   }
@@ -3165,7 +3165,6 @@
 
         assert(_verifier->check_cset_fast_test(), "Inconsistency in the InCSetState table.");
 
-        _cm->note_start_of_gc();
         // We call this after finalize_cset() to
         // ensure that the CSet has been finalized.
         _cm->verify_no_cset_oops();
@@ -3241,7 +3240,7 @@
             // No need for an ergo logging here,
             // expansion_amount() does this when it returns a value > 0.
             double expand_ms;
-            if (!expand(expand_bytes, &expand_ms)) {
+            if (!expand(expand_bytes, _workers, &expand_ms)) {
               // We failed to expand the heap. Cannot do anything about it.
             }
             g1_policy()->phase_times()->record_expand_heap_time(expand_ms);
@@ -3251,7 +3250,6 @@
         // We redo the verification but now wrt to the new CSet which
         // has just got initialized after the previous CSet was freed.
         _cm->verify_no_cset_oops();
-        _cm->note_end_of_gc();
 
         // This timing is only used by the ergonomics to handle our pause target.
         // It is unclear why this should not include the full pause. We will
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp	Wed Oct 05 06:28:23 2016 -0700
@@ -557,7 +557,7 @@
   // Returns true if the heap was expanded by the requested amount;
   // false otherwise.
   // (Rounds up to a HeapRegion boundary.)
-  bool expand(size_t expand_bytes, double* expand_time_ms = NULL);
+  bool expand(size_t expand_bytes, WorkGang* pretouch_workers = NULL, double* expand_time_ms = NULL);
 
   // Returns the PLAB statistics for a given destination.
   inline G1EvacStats* alloc_buffer_stats(InCSetState dest);
--- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.cpp	Wed Oct 05 06:28:23 2016 -0700
@@ -133,129 +133,184 @@
 }
 
 G1CMMarkStack::G1CMMarkStack() :
-  _reserved_space(),
+  _max_chunk_capacity(0),
   _base(NULL),
-  _capacity(0),
-  _saved_index((size_t)AllBits),
+  _chunk_capacity(0),
+  _out_of_memory(false),
   _should_expand(false) {
   set_empty();
 }
 
 bool G1CMMarkStack::resize(size_t new_capacity) {
   assert(is_empty(), "Only resize when stack is empty.");
-  assert(new_capacity <= MarkStackSizeMax,
-         "Trying to resize stack to " SIZE_FORMAT " elements when the maximum is " SIZE_FORMAT, new_capacity, MarkStackSizeMax);
-
-  size_t reservation_size = ReservedSpace::allocation_align_size_up(new_capacity * sizeof(oop));
-
-  ReservedSpace rs(reservation_size);
-  if (!rs.is_reserved()) {
-    log_warning(gc)("Failed to reserve memory for new overflow mark stack with " SIZE_FORMAT " elements and size " SIZE_FORMAT "B.", new_capacity, reservation_size);
+  assert(new_capacity <= _max_chunk_capacity,
+         "Trying to resize stack to " SIZE_FORMAT " chunks when the maximum is " SIZE_FORMAT, new_capacity, _max_chunk_capacity);
+
+  OopChunk* new_base = MmapArrayAllocator<OopChunk, mtGC>::allocate_or_null(new_capacity);
+
+  if (new_base == NULL) {
+    log_warning(gc)("Failed to reserve memory for new overflow mark stack with " SIZE_FORMAT " chunks and size " SIZE_FORMAT "B.", new_capacity, new_capacity * sizeof(OopChunk));
     return false;
   }
-
-  VirtualSpace vs;
-
-  if (!vs.initialize(rs, rs.size())) {
-    rs.release();
-    log_warning(gc)("Failed to commit memory for new overflow mark stack of size " SIZE_FORMAT "B.", rs.size());
-    return false;
+  // Release old mapping.
+  if (_base != NULL) {
+    MmapArrayAllocator<OopChunk, mtGC>::free(_base, _chunk_capacity);
   }
 
-  assert(vs.committed_size() == rs.size(), "Failed to commit all of the mark stack.");
-
-  // Release old mapping.
-  _reserved_space.release();
-
-  // Save new mapping for future unmapping.
-  _reserved_space = rs;
-
-  MemTracker::record_virtual_memory_type((address)_reserved_space.base(), mtGC);
-
-  _base = (oop*) vs.low();
-  _capacity = new_capacity;
+  _base = new_base;
+  _chunk_capacity = new_capacity;
   set_empty();
   _should_expand = false;
 
   return true;
 }
 
-bool G1CMMarkStack::allocate(size_t capacity) {
-  return resize(capacity);
+size_t G1CMMarkStack::capacity_alignment() {
+  return (size_t)lcm(os::vm_allocation_granularity(), sizeof(OopChunk)) / sizeof(void*);
+}
+
+bool G1CMMarkStack::initialize(size_t initial_capacity, size_t max_capacity) {
+  guarantee(_max_chunk_capacity == 0, "G1CMMarkStack already initialized.");
+
+  size_t const OopChunkSizeInVoidStar = sizeof(OopChunk) / sizeof(void*);
+
+  _max_chunk_capacity = (size_t)align_size_up(max_capacity, capacity_alignment()) / OopChunkSizeInVoidStar;
+  size_t initial_chunk_capacity = (size_t)align_size_up(initial_capacity, capacity_alignment()) / OopChunkSizeInVoidStar;
+
+  guarantee(initial_chunk_capacity <= _max_chunk_capacity,
+            "Maximum chunk capacity " SIZE_FORMAT " smaller than initial capacity " SIZE_FORMAT,
+            _max_chunk_capacity,
+            initial_chunk_capacity);
+
+  log_debug(gc)("Initialize mark stack with " SIZE_FORMAT " chunks, maximum " SIZE_FORMAT,
+                initial_chunk_capacity, _max_chunk_capacity);
+
+  return resize(initial_chunk_capacity);
 }
 
 void G1CMMarkStack::expand() {
   // Clear expansion flag
   _should_expand = false;
 
-  if (_capacity == MarkStackSizeMax) {
-    log_debug(gc)("Can not expand overflow mark stack further, already at maximum capacity of " SIZE_FORMAT " elements.", _capacity);
+  if (_chunk_capacity == _max_chunk_capacity) {
+    log_debug(gc)("Can not expand overflow mark stack further, already at maximum capacity of " SIZE_FORMAT " chunks.", _chunk_capacity);
     return;
   }
-  size_t old_capacity = _capacity;
+  size_t old_capacity = _chunk_capacity;
   // Double capacity if possible
-  size_t new_capacity = MIN2(old_capacity * 2, MarkStackSizeMax);
+  size_t new_capacity = MIN2(old_capacity * 2, _max_chunk_capacity);
 
   if (resize(new_capacity)) {
-    log_debug(gc)("Expanded marking stack capacity from " SIZE_FORMAT " to " SIZE_FORMAT " elements",
+    log_debug(gc)("Expanded mark stack capacity from " SIZE_FORMAT " to " SIZE_FORMAT " chunks",
                   old_capacity, new_capacity);
   } else {
-    log_warning(gc)("Failed to expand marking stack capacity from " SIZE_FORMAT " to " SIZE_FORMAT " elements",
+    log_warning(gc)("Failed to expand mark stack capacity from " SIZE_FORMAT " to " SIZE_FORMAT " chunks",
                     old_capacity, new_capacity);
   }
 }
 
 G1CMMarkStack::~G1CMMarkStack() {
   if (_base != NULL) {
-    _base = NULL;
-    _reserved_space.release();
+    MmapArrayAllocator<OopChunk, mtGC>::free(_base, _chunk_capacity);
   }
 }
 
-void G1CMMarkStack::par_push_arr(oop* buffer, size_t n) {
-  MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag);
-  size_t start = _index;
-  size_t next_index = start + n;
-  if (next_index > _capacity) {
-    _overflow = true;
-    return;
+void G1CMMarkStack::add_chunk_to_list(OopChunk* volatile* list, OopChunk* elem) {
+  elem->next = *list;
+  *list = elem;
+}
+
+void G1CMMarkStack::add_chunk_to_chunk_list(OopChunk* elem) {
+  MutexLockerEx x(MarkStackChunkList_lock, Mutex::_no_safepoint_check_flag);
+  add_chunk_to_list(&_chunk_list, elem);
+  _chunks_in_chunk_list++;
+}
+
+void G1CMMarkStack::add_chunk_to_free_list(OopChunk* elem) {
+  MutexLockerEx x(MarkStackFreeList_lock, Mutex::_no_safepoint_check_flag);
+  add_chunk_to_list(&_free_list, elem);
+}
+
+G1CMMarkStack::OopChunk* G1CMMarkStack::remove_chunk_from_list(OopChunk* volatile* list) {
+  OopChunk* result = *list;
+  if (result != NULL) {
+    *list = (*list)->next;
   }
-  // Otherwise.
-  _index = next_index;
-  for (size_t i = 0; i < n; i++) {
-    size_t ind = start + i;
-    assert(ind < _capacity, "By overflow test above.");
-    _base[ind] = buffer[i];
+  return result;
+}
+
+G1CMMarkStack::OopChunk* G1CMMarkStack::remove_chunk_from_chunk_list() {
+  MutexLockerEx x(MarkStackChunkList_lock, Mutex::_no_safepoint_check_flag);
+  OopChunk* result = remove_chunk_from_list(&_chunk_list);
+  if (result != NULL) {
+    _chunks_in_chunk_list--;
   }
+  return result;
 }
 
-bool G1CMMarkStack::par_pop_arr(oop* buffer, size_t max, size_t* n) {
-  MutexLockerEx x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag);
-  size_t index = _index;
-  if (index == 0) {
-    *n = 0;
+G1CMMarkStack::OopChunk* G1CMMarkStack::remove_chunk_from_free_list() {
+  MutexLockerEx x(MarkStackFreeList_lock, Mutex::_no_safepoint_check_flag);
+  return remove_chunk_from_list(&_free_list);
+}
+
+G1CMMarkStack::OopChunk* G1CMMarkStack::allocate_new_chunk() {
+  // This dirty read of _hwm is okay because we only ever increase the _hwm in parallel code.
+  // Further this limits _hwm to a value of _chunk_capacity + #threads, avoiding
+  // wraparound of _hwm.
+  if (_hwm >= _chunk_capacity) {
+    return NULL;
+  }
+
+  size_t cur_idx = Atomic::add(1, &_hwm) - 1;
+  if (cur_idx >= _chunk_capacity) {
+    return NULL;
+  }
+
+  OopChunk* result = ::new (&_base[cur_idx]) OopChunk;
+  result->next = NULL;
+  return result;
+}
+
+bool G1CMMarkStack::par_push_chunk(oop* ptr_arr) {
+  // Get a new chunk.
+  OopChunk* new_chunk = remove_chunk_from_free_list();
+
+  if (new_chunk == NULL) {
+    // Did not get a chunk from the free list. Allocate from backing memory.
+    new_chunk = allocate_new_chunk();
+  }
+
+  if (new_chunk == NULL) {
+    _out_of_memory = true;
     return false;
-  } else {
-    size_t k = MIN2(max, index);
-    size_t new_ind = index - k;
-    for (size_t j = 0; j < k; j++) {
-      buffer[j] = _base[new_ind + j];
-    }
-    _index = new_ind;
-    *n = k;
-    return true;
   }
+
+  Copy::conjoint_memory_atomic(ptr_arr, new_chunk->data, OopsPerChunk * sizeof(oop));
+
+  add_chunk_to_chunk_list(new_chunk);
+
+  return true;
 }
 
-void G1CMMarkStack::note_start_of_gc() {
-  assert(_saved_index == (size_t)AllBits, "note_start_of_gc()/end_of_gc() calls bracketed incorrectly");
-  _saved_index = _index;
+bool G1CMMarkStack::par_pop_chunk(oop* ptr_arr) {
+  OopChunk* cur = remove_chunk_from_chunk_list();
+
+  if (cur == NULL) {
+    return false;
+  }
+
+  Copy::conjoint_memory_atomic(cur->data, ptr_arr, OopsPerChunk * sizeof(oop));
+
+  add_chunk_to_free_list(cur);
+  return true;
 }
 
-void G1CMMarkStack::note_end_of_gc() {
-  guarantee(!stack_modified(), "Saved index " SIZE_FORMAT " must be the same as " SIZE_FORMAT, _saved_index, _index);
-
-  _saved_index = (size_t)AllBits;
+void G1CMMarkStack::set_empty() {
+  _chunks_in_chunk_list = 0;
+  _hwm = 0;
+  clear_out_of_memory();
+  _chunk_list = NULL;
+  _free_list = NULL;
 }
 
 G1CMRootRegions::G1CMRootRegions() :
@@ -483,9 +538,8 @@
     }
   }
 
-  if (!_global_mark_stack.allocate(MarkStackSize)) {
+  if (!_global_mark_stack.initialize(MarkStackSize, MarkStackSizeMax)) {
     vm_exit_during_initialization("Failed to allocate initial concurrent mark overflow mark stack.");
-    return;
   }
 
   _tasks = NEW_C_HEAP_ARRAY(G1CMTask*, _max_worker_id, mtGC);
@@ -1695,10 +1749,10 @@
     // oop closures will set the has_overflown flag if we overflow the
     // global marking stack.
 
-    assert(_global_mark_stack.overflow() || _global_mark_stack.is_empty(),
-            "mark stack should be empty (unless it overflowed)");
-
-    if (_global_mark_stack.overflow()) {
+    assert(_global_mark_stack.is_out_of_memory() || _global_mark_stack.is_empty(),
+            "Mark stack should be empty (unless it is out of memory)");
+
+    if (_global_mark_stack.is_out_of_memory()) {
       // This should have been done already when we tried to push an
       // entry on to the global mark stack. But let's do it again.
       set_has_overflown();
@@ -2343,49 +2397,54 @@
 }
 
 void G1CMTask::move_entries_to_global_stack() {
-  // local array where we'll store the entries that will be popped
-  // from the local queue
-  oop buffer[global_stack_transfer_size];
-
-  int n = 0;
+  // Local array where we'll store the entries that will be popped
+  // from the local queue.
+  oop buffer[G1CMMarkStack::OopsPerChunk];
+
+  size_t n = 0;
   oop obj;
-  while (n < global_stack_transfer_size && _task_queue->pop_local(obj)) {
+  while (n < G1CMMarkStack::OopsPerChunk && _task_queue->pop_local(obj)) {
     buffer[n] = obj;
     ++n;
   }
+  if (n < G1CMMarkStack::OopsPerChunk) {
+    buffer[n] = NULL;
+  }
 
   if (n > 0) {
-    // we popped at least one entry from the local queue
-
-    if (!_cm->mark_stack_push(buffer, n)) {
+    if (!_cm->mark_stack_push(buffer)) {
       set_has_aborted();
     }
   }
 
-  // this operation was quite expensive, so decrease the limits
+  // This operation was quite expensive, so decrease the limits.
   decrease_limits();
 }
 
-void G1CMTask::get_entries_from_global_stack() {
-  // local array where we'll store the entries that will be popped
+bool G1CMTask::get_entries_from_global_stack() {
+  // Local array where we'll store the entries that will be popped
   // from the global stack.
-  oop buffer[global_stack_transfer_size];
-  size_t n;
-  _cm->mark_stack_pop(buffer, global_stack_transfer_size, &n);
-  assert(n <= global_stack_transfer_size,
-         "we should not pop more than the given limit");
-  if (n > 0) {
-    // yes, we did actually pop at least one entry
-    for (size_t i = 0; i < n; ++i) {
-      bool success = _task_queue->push(buffer[i]);
-      // We only call this when the local queue is empty or under a
-      // given target limit. So, we do not expect this push to fail.
-      assert(success, "invariant");
+  oop buffer[G1CMMarkStack::OopsPerChunk];
+
+  if (!_cm->mark_stack_pop(buffer)) {
+    return false;
+  }
+
+  // We did actually pop at least one entry.
+  for (size_t i = 0; i < G1CMMarkStack::OopsPerChunk; ++i) {
+    oop elem = buffer[i];
+    if (elem == NULL) {
+      break;
     }
+    bool success = _task_queue->push(elem);
+    // We only call this when the local queue is empty or under a
+    // given target limit. So, we do not expect this push to fail.
+    assert(success, "invariant");
   }
 
-  // this operation was quite expensive, so decrease the limits
+  // This operation was quite expensive, so decrease the limits
   decrease_limits();
+  return true;
 }
 
 void G1CMTask::drain_local_queue(bool partially) {
@@ -2429,20 +2488,21 @@
 
   // Decide what the target size is, depending whether we're going to
   // drain it partially (so that other tasks can steal if they run out
-  // of things to do) or totally (at the very end).  Notice that,
-  // because we move entries from the global stack in chunks or
-  // because another task might be doing the same, we might in fact
-  // drop below the target. But, this is not a problem.
-  size_t target_size;
+  // of things to do) or totally (at the very end).
+  // Notice that when draining the global mark stack partially, due to the racyness
+  // of the mark stack size update we might in fact drop below the target. But,
+  // this is not a problem.
+  // In case of total draining, we simply process until the global mark stack is
+  // totally empty, disregarding the size counter.
   if (partially) {
-    target_size = _cm->partial_mark_stack_size_target();
+    size_t const target_size = _cm->partial_mark_stack_size_target();
+    while (!has_aborted() && _cm->mark_stack_size() > target_size) {
+      if (get_entries_from_global_stack()) {
+        drain_local_queue(partially);
+      }
+    }
   } else {
-    target_size = 0;
-  }
-
-  if (_cm->mark_stack_size() > target_size) {
-    while (!has_aborted() && _cm->mark_stack_size() > target_size) {
-      get_entries_from_global_stack();
+    while (!has_aborted() && get_entries_from_global_stack()) {
       drain_local_queue(partially);
     }
   }
--- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.hpp	Wed Oct 05 06:28:23 2016 -0700
@@ -149,42 +149,98 @@
 //
 // Stores oops in a huge buffer in virtual memory that is always fully committed.
 // Resizing may only happen during a STW pause when the stack is empty.
+//
+// Memory is allocated on a "chunk" basis, i.e. a set of oops. For this, the mark
+// stack memory is split into evenly sized chunks of oops. Users can only
+// add or remove entries on that basis.
+// Chunks are filled in increasing address order. Not completely filled chunks
+// have a NULL element as a terminating element.
+//
+// Every chunk has a header containing a single pointer element used for memory
+// management. This wastes some space, but is negligible (< .1% with current sizing).
+//
+// Memory management is done using a mix of tracking a high water-mark indicating
+// that all chunks at a lower address are valid chunks, and a singly linked free
+// list connecting all empty chunks.
 class G1CMMarkStack VALUE_OBJ_CLASS_SPEC {
-  ReservedSpace _reserved_space; // Space currently reserved for the mark stack.
+public:
+  // Number of oops that can fit in a single chunk.
+  static const size_t OopsPerChunk = 1024 - 1 /* One reference for the next pointer */;
+private:
+  struct OopChunk {
+    OopChunk* next;
+    oop data[OopsPerChunk];
+  };
 
-  oop* _base;                    // Bottom address of allocated memory area.
-  size_t _capacity;              // Maximum number of elements.
-  size_t _index;                 // One more than last occupied index.
+  size_t _max_chunk_capacity;    // Maximum number of OopChunk elements on the stack.
 
-  size_t _saved_index;           // Value of _index saved at start of GC to detect mark stack modifications during that time.
+  OopChunk* _base;               // Bottom address of allocated memory area.
+  size_t _chunk_capacity;        // Current maximum number of OopChunk elements.
 
-  bool  _overflow;
+  char _pad0[DEFAULT_CACHE_LINE_SIZE];
+  OopChunk* volatile _free_list;  // Linked list of free chunks that can be allocated by users.
+  char _pad1[DEFAULT_CACHE_LINE_SIZE - sizeof(OopChunk*)];
+  OopChunk* volatile _chunk_list; // List of chunks currently containing data.
+  volatile size_t _chunks_in_chunk_list;
+  char _pad2[DEFAULT_CACHE_LINE_SIZE - sizeof(OopChunk*) - sizeof(size_t)];
+
+  volatile size_t _hwm;          // High water mark within the reserved space.
+  char _pad4[DEFAULT_CACHE_LINE_SIZE - sizeof(size_t)];
+
+  // Allocate a new chunk from the reserved memory, using the high water mark. Returns
+  // NULL if out of memory.
+  OopChunk* allocate_new_chunk();
+
+  volatile bool _out_of_memory;
+
+  // Atomically add the given chunk to the list.
+  void add_chunk_to_list(OopChunk* volatile* list, OopChunk* elem);
+  // Atomically remove and return a chunk from the given list. Returns NULL if the
+  // list is empty.
+  OopChunk* remove_chunk_from_list(OopChunk* volatile* list);
+
+  void add_chunk_to_chunk_list(OopChunk* elem);
+  void add_chunk_to_free_list(OopChunk* elem);
+
+  OopChunk* remove_chunk_from_chunk_list();
+  OopChunk* remove_chunk_from_free_list();
+
   bool  _should_expand;
 
   // Resizes the mark stack to the given new capacity. Releases any previous
   // memory if successful.
   bool resize(size_t new_capacity);
 
-  bool stack_modified() const { return _index != _saved_index; }
  public:
   G1CMMarkStack();
   ~G1CMMarkStack();
 
-  bool allocate(size_t capacity);
+  // Alignment and minimum capacity of this mark stack in number of oops.
+  static size_t capacity_alignment();
 
-  // Pushes the first "n" elements of the given buffer on the stack.
-  void par_push_arr(oop* buffer, size_t n);
+  // Allocate and initialize the mark stack with the given number of oops.
+  bool initialize(size_t initial_capacity, size_t max_capacity);
 
-  // Moves up to max elements from the stack into the given buffer. Returns
-  // the number of elements pushed, and false if the array has been empty.
-  // Returns true if the buffer contains at least one element.
-  bool par_pop_arr(oop* buffer, size_t max, size_t* n);
+  // Pushes the given buffer containing at most OopsPerChunk elements on the mark
+  // stack. If less than OopsPerChunk elements are to be pushed, the array must
+  // be terminated with a NULL.
+  // Returns whether the buffer contents were successfully pushed to the global mark
+  // stack.
+  bool par_push_chunk(oop* buffer);
 
-  bool is_empty() const { return _index == 0; }
-  size_t capacity() const  { return _capacity; }
+  // Pops a chunk from this mark stack, copying them into the given buffer. This
+  // chunk may contain up to OopsPerChunk elements. If there are less, the last
+  // element in the array is a NULL pointer.
+  bool par_pop_chunk(oop* buffer);
 
-  bool overflow() const { return _overflow; }
-  void clear_overflow() { _overflow = false; }
+  // Return whether the chunk list is empty. Racy due to unsynchronized access to
+  // _chunk_list.
+  bool is_empty() const { return _chunk_list == NULL; }
+
+  size_t capacity() const  { return _chunk_capacity; }
+
+  bool is_out_of_memory() const { return _out_of_memory; }
+  void clear_out_of_memory() { _out_of_memory = false; }
 
   bool should_expand() const { return _should_expand; }
   void set_should_expand(bool value) { _should_expand = value; }
@@ -192,20 +248,15 @@
   // Expand the stack, typically in response to an overflow condition
   void expand();
 
-  size_t size() const { return _index; }
+  // Return the approximate number of oops on this mark stack. Racy due to
+  // unsynchronized access to _chunks_in_chunk_list.
+  size_t size() const { return _chunks_in_chunk_list * OopsPerChunk; }
 
-  void set_empty() { _index = 0; clear_overflow(); }
+  void set_empty();
 
-  // Record the current index.
-  void note_start_of_gc();
-
-  // Make sure that we have not added any entries to the stack during GC.
-  void note_end_of_gc();
-
-  // Apply fn to each oop in the mark stack, up to the bound recorded
-  // via one of the above "note" functions.  The mark stack must not
+  // Apply Fn to every oop on the mark stack. The mark stack must not
   // be modified while iterating.
-  template<typename Fn> void iterate(Fn fn);
+  template<typename Fn> void iterate(Fn fn) const PRODUCT_RETURN;
 };
 
 // Root Regions are regions that are not empty at the beginning of a
@@ -278,7 +329,6 @@
   friend class G1CMDrainMarkingStackClosure;
   friend class G1CMBitMapClosure;
   friend class G1CMConcurrentMarkingTask;
-  friend class G1CMMarkStack;
   friend class G1CMRemarkTask;
   friend class G1CMTask;
 
@@ -479,22 +529,20 @@
 public:
   // Manipulation of the global mark stack.
   // The push and pop operations are used by tasks for transfers
-  // between task-local queues and the global mark stack, and use
-  // locking for concurrency safety.
-  bool mark_stack_push(oop* arr, size_t n) {
-    _global_mark_stack.par_push_arr(arr, n);
-    if (_global_mark_stack.overflow()) {
+  // between task-local queues and the global mark stack.
+  bool mark_stack_push(oop* arr) {
+    if (!_global_mark_stack.par_push_chunk(arr)) {
       set_has_overflown();
       return false;
     }
     return true;
   }
-  void mark_stack_pop(oop* arr, size_t max, size_t* n) {
-    _global_mark_stack.par_pop_arr(arr, max, n);
+  bool mark_stack_pop(oop* arr) {
+    return _global_mark_stack.par_pop_chunk(arr);
   }
   size_t mark_stack_size()                { return _global_mark_stack.size(); }
   size_t partial_mark_stack_size_target() { return _global_mark_stack.capacity()/3; }
-  bool mark_stack_overflow()              { return _global_mark_stack.overflow(); }
+  bool mark_stack_overflow()              { return _global_mark_stack.is_out_of_memory(); }
   bool mark_stack_empty()                 { return _global_mark_stack.is_empty(); }
 
   G1CMRootRegions* root_regions() { return &_root_regions; }
@@ -599,16 +647,6 @@
   // read-only, so use this carefully!
   void clearRangePrevBitmap(MemRegion mr);
 
-  // Notify data structures that a GC has started.
-  void note_start_of_gc() {
-    _global_mark_stack.note_start_of_gc();
-  }
-
-  // Notify data structures that a GC is finished.
-  void note_end_of_gc() {
-    _global_mark_stack.note_end_of_gc();
-  }
-
   // Verify that there are no CSet oops on the stacks (taskqueues /
   // global mark stack) and fingers (global / per-task).
   // If marking is not in progress, it's a no-op.
@@ -670,10 +708,7 @@
     // references reaches this limit
     refs_reached_period           = 384,
     // Initial value for the hash seed, used in the work stealing code
-    init_hash_seed                = 17,
-    // How many entries will be transferred between global stack and
-    // local queues at once.
-    global_stack_transfer_size    = 1024
+    init_hash_seed                = 17
   };
 
   uint                        _worker_id;
@@ -858,9 +893,10 @@
   // It pushes an object on the local queue.
   inline void push(oop obj);
 
-  // These two move entries to/from the global stack.
+  // Move entries to the global stack.
   void move_entries_to_global_stack();
-  void get_entries_from_global_stack();
+  // Move entries from the global stack, return true if we were successful to do so.
+  bool get_entries_from_global_stack();
 
   // It pops and scans objects from the local queue. If partially is
   // true, then it stops when the queue size is of a given limit. If
--- a/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1ConcurrentMark.inline.hpp	Wed Oct 05 06:28:23 2016 -0700
@@ -89,14 +89,28 @@
 
 #undef check_mark
 
+#ifndef PRODUCT
 template<typename Fn>
-inline void G1CMMarkStack::iterate(Fn fn) {
+inline void G1CMMarkStack::iterate(Fn fn) const {
   assert_at_safepoint(true);
-  assert(!stack_modified(), "Saved index " SIZE_FORMAT " must be the same as " SIZE_FORMAT, _saved_index, _index);
-  for (size_t i = 0; i < _index; ++i) {
-    fn(_base[i]);
+
+  size_t num_chunks = 0;
+
+  OopChunk* cur = _chunk_list;
+  while (cur != NULL) {
+    guarantee(num_chunks <= _chunks_in_chunk_list, "Found " SIZE_FORMAT " oop chunks which is more than there should be", num_chunks);
+
+    for (size_t i = 0; i < OopsPerChunk; ++i) {
+      if (cur->data[i] == NULL) {
+        break;
+      }
+      fn(cur->data[i]);
+    }
+    cur = cur->next;
+    num_chunks++;
   }
 }
+#endif
 
 // It scans an object and visits its children.
 inline void G1CMTask::scan_object(oop obj) { process_grey_object<true>(obj); }
--- a/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp	Wed Oct 05 06:28:23 2016 -0700
@@ -34,7 +34,6 @@
 class G1ConcurrentMark;
 class DirtyCardToOopClosure;
 class G1CMBitMap;
-class G1CMMarkStack;
 class G1ParScanThreadState;
 class G1CMTask;
 class ReferenceProcessor;
--- a/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.cpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.cpp	Wed Oct 05 06:28:23 2016 -0700
@@ -24,8 +24,10 @@
 
 #include "precompiled.hpp"
 #include "gc/g1/g1PageBasedVirtualSpace.hpp"
+#include "gc/shared/workgroup.hpp"
 #include "oops/markOop.hpp"
 #include "oops/oop.inline.hpp"
+#include "runtime/atomic.hpp"
 #include "runtime/os.inline.hpp"
 #include "services/memTracker.hpp"
 #include "utilities/bitMap.inline.hpp"
@@ -177,7 +179,7 @@
   guarantee(start_page < end_page,
             "Given start page " SIZE_FORMAT " is larger or equal to end page " SIZE_FORMAT, start_page, end_page);
 
-  os::pretouch_memory(page_start(start_page), bounded_end_addr(end_page));
+  os::pretouch_memory(page_start(start_page), bounded_end_addr(end_page), _page_size);
 }
 
 bool G1PageBasedVirtualSpace::commit(size_t start_page, size_t size_in_pages) {
@@ -198,9 +200,6 @@
   }
   _committed.set_range(start_page, end_page);
 
-  if (AlwaysPreTouch) {
-    pretouch_internal(start_page, end_page);
-  }
   return zero_filled;
 }
 
@@ -227,6 +226,53 @@
   _committed.clear_range(start_page, end_page);
 }
 
+class G1PretouchTask : public AbstractGangTask {
+private:
+  char* volatile _cur_addr;
+  char* const _start_addr;
+  char* const _end_addr;
+  size_t const _page_size;
+public:
+  G1PretouchTask(char* start_address, char* end_address, size_t page_size) :
+    AbstractGangTask("G1 PreTouch",
+                     Universe::is_fully_initialized() ? GCId::current_raw() :
+                                                        // During VM initialization there is
+                                                        // no GC cycle that this task can be
+                                                        // associated with.
+                                                        GCId::undefined()),
+    _cur_addr(start_address),
+    _start_addr(start_address),
+    _end_addr(end_address),
+    _page_size(page_size) {
+  }
+
+  virtual void work(uint worker_id) {
+    size_t const actual_chunk_size = MAX2(chunk_size(), _page_size);
+    while (true) {
+      char* touch_addr = (char*)Atomic::add_ptr((intptr_t)actual_chunk_size, (volatile void*) &_cur_addr) - actual_chunk_size;
+      if (touch_addr < _start_addr || touch_addr >= _end_addr) {
+        break;
+      }
+      char* end_addr = touch_addr + MIN2(actual_chunk_size, pointer_delta(_end_addr, touch_addr, sizeof(char)));
+      os::pretouch_memory(touch_addr, end_addr, _page_size);
+    }
+  }
+
+  static size_t chunk_size() { return PreTouchParallelChunkSize; }
+};
+
+void G1PageBasedVirtualSpace::pretouch(size_t start_page, size_t size_in_pages, WorkGang* pretouch_gang) {
+  guarantee(pretouch_gang != NULL, "No pretouch gang specified.");
+
+  size_t num_chunks = MAX2((size_t)1, size_in_pages * _page_size / MAX2(G1PretouchTask::chunk_size(), _page_size));
+
+  uint num_workers = MIN2((uint)num_chunks, pretouch_gang->active_workers());
+  G1PretouchTask cl(page_start(start_page), bounded_end_addr(start_page + size_in_pages), _page_size);
+  log_debug(gc, heap)("Running %s with %u workers for " SIZE_FORMAT " work units pre-touching " SIZE_FORMAT "B.",
+                      cl.name(), num_workers, num_chunks, size_in_pages * _page_size);
+  pretouch_gang->run_task(&cl, num_workers);
+}
+
 bool G1PageBasedVirtualSpace::contains(const void* p) const {
   return _low_boundary <= (const char*) p && (const char*) p < _high_boundary;
 }
--- a/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.hpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1PageBasedVirtualSpace.hpp	Wed Oct 05 06:28:23 2016 -0700
@@ -30,6 +30,8 @@
 #include "memory/virtualspace.hpp"
 #include "utilities/bitMap.hpp"
 
+class WorkGang;
+
 // Virtual space management helper for a virtual space with an OS page allocation
 // granularity.
 // (De-)Allocation requests are always OS page aligned by passing a page index
@@ -117,6 +119,8 @@
   // Uncommit the given area of pages starting at start being size_in_pages large.
   void uncommit(size_t start_page, size_t size_in_pages);
 
+  void pretouch(size_t start_page, size_t size_in_pages, WorkGang* pretouch_gang = NULL);
+
   // Initialize the given reserved space with the given base address and the size
   // actually used.
   // Prefer to commit in page_size chunks.
--- a/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.cpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.cpp	Wed Oct 05 06:28:23 2016 -0700
@@ -66,8 +66,12 @@
     guarantee(alloc_granularity >= page_size, "allocation granularity smaller than commit granularity");
   }
 
-  virtual void commit_regions(uint start_idx, size_t num_regions) {
-    bool zero_filled = _storage.commit((size_t)start_idx * _pages_per_region, num_regions * _pages_per_region);
+  virtual void commit_regions(uint start_idx, size_t num_regions, WorkGang* pretouch_gang) {
+    size_t const start_page = (size_t)start_idx * _pages_per_region;
+    bool zero_filled = _storage.commit(start_page, num_regions * _pages_per_region);
+    if (AlwaysPreTouch) {
+      _storage.pretouch(start_page, num_regions * _pages_per_region, pretouch_gang);
+    }
     _commit_map.set_range(start_idx, start_idx + num_regions);
     fire_on_commit(start_idx, num_regions, zero_filled);
   }
@@ -110,19 +114,38 @@
     _refcounts.initialize((HeapWord*)rs.base(), (HeapWord*)(rs.base() + align_size_up(rs.size(), page_size)), page_size);
   }
 
-  virtual void commit_regions(uint start_idx, size_t num_regions) {
+  virtual void commit_regions(uint start_idx, size_t num_regions, WorkGang* pretouch_gang) {
+    size_t const NoPage = ~(size_t)0;
+
+    size_t first_committed = NoPage;
+    size_t num_committed = 0;
+
+    bool all_zero_filled = true;
+
     for (uint i = start_idx; i < start_idx + num_regions; i++) {
       assert(!_commit_map.at(i), "Trying to commit storage at region %u that is already committed", i);
       size_t idx = region_idx_to_page_idx(i);
       uint old_refcount = _refcounts.get_by_index(idx);
+
       bool zero_filled = false;
       if (old_refcount == 0) {
+        if (first_committed == NoPage) {
+          first_committed = idx;
+          num_committed = 1;
+        } else {
+          num_committed++;
+        }
         zero_filled = _storage.commit(idx, 1);
       }
+      all_zero_filled &= zero_filled;
+
       _refcounts.set_by_index(idx, old_refcount + 1);
       _commit_map.set_bit(i);
-      fire_on_commit(i, 1, zero_filled);
     }
+    if (AlwaysPreTouch && num_committed > 0) {
+      _storage.pretouch(first_committed, num_committed, pretouch_gang);
+    }
+    fire_on_commit(start_idx, num_regions, all_zero_filled);
   }
 
   virtual void uncommit_regions(uint start_idx, size_t num_regions) {
--- a/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.hpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/g1RegionToSpaceMapper.hpp	Wed Oct 05 06:28:23 2016 -0700
@@ -29,6 +29,8 @@
 #include "memory/allocation.hpp"
 #include "utilities/debug.hpp"
 
+class WorkGang;
+
 class G1MappingChangedListener VALUE_OBJ_CLASS_SPEC {
  public:
   // Fired after commit of the memory, i.e. the memory this listener is registered
@@ -68,7 +70,7 @@
     return _commit_map.at(idx);
   }
 
-  virtual void commit_regions(uint start_idx, size_t num_regions = 1) = 0;
+  virtual void commit_regions(uint start_idx, size_t num_regions = 1, WorkGang* pretouch_workers = NULL) = 0;
   virtual void uncommit_regions(uint start_idx, size_t num_regions = 1) = 0;
 
   // Creates an appropriate G1RegionToSpaceMapper for the given parameters.
--- a/hotspot/src/share/vm/gc/g1/heapRegion.cpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.cpp	Wed Oct 05 06:28:23 2016 -0700
@@ -353,35 +353,6 @@
 }
 
 HeapWord*
-HeapRegion::object_iterate_mem_careful(MemRegion mr,
-                                                 ObjectClosure* cl) {
-  G1CollectedHeap* g1h = G1CollectedHeap::heap();
-  // We used to use "block_start_careful" here.  But we're actually happy
-  // to update the BOT while we do this...
-  HeapWord* cur = block_start(mr.start());
-  mr = mr.intersection(used_region());
-  if (mr.is_empty()) return NULL;
-  // Otherwise, find the obj that extends onto mr.start().
-
-  assert(cur <= mr.start()
-         && (oop(cur)->klass_or_null() == NULL ||
-             cur + oop(cur)->size() > mr.start()),
-         "postcondition of block_start");
-  oop obj;
-  while (cur < mr.end()) {
-    obj = oop(cur);
-    if (obj->klass_or_null() == NULL) {
-      // Ran into an unparseable point.
-      return cur;
-    } else if (!g1h->is_obj_dead(obj)) {
-      cl->do_object(obj);
-    }
-    cur += block_size(cur);
-  }
-  return NULL;
-}
-
-HeapWord*
 HeapRegion::
 oops_on_card_seq_iterate_careful(MemRegion mr,
                                  FilterOutOfRegionClosure* cl,
--- a/hotspot/src/share/vm/gc/g1/heapRegion.hpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.hpp	Wed Oct 05 06:28:23 2016 -0700
@@ -653,17 +653,6 @@
     }
   }
 
-  // Requires that "mr" be entirely within the region.
-  // Apply "cl->do_object" to all objects that intersect with "mr".
-  // If the iteration encounters an unparseable portion of the region,
-  // or if "cl->abort()" is true after a closure application,
-  // terminate the iteration and return the address of the start of the
-  // subregion that isn't done.  (The two can be distinguished by querying
-  // "cl->abort()".)  Return of "NULL" indicates that the iteration
-  // completed.
-  HeapWord*
-  object_iterate_mem_careful(MemRegion mr, ObjectClosure* cl);
-
   // filter_young: if true and the region is a young region then we
   // skip the iteration.
   // card_ptr: if not NULL, and we decide that the card is not young
--- a/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/heapRegionManager.cpp	Wed Oct 05 06:28:23 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 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
@@ -72,22 +72,22 @@
   return g1h->new_heap_region(hrm_index, mr);
 }
 
-void HeapRegionManager::commit_regions(uint index, size_t num_regions) {
+void HeapRegionManager::commit_regions(uint index, size_t num_regions, WorkGang* pretouch_gang) {
   guarantee(num_regions > 0, "Must commit more than zero regions");
   guarantee(_num_committed + num_regions <= max_length(), "Cannot commit more than the maximum amount of regions");
 
   _num_committed += (uint)num_regions;
 
-  _heap_mapper->commit_regions(index, num_regions);
+  _heap_mapper->commit_regions(index, num_regions, pretouch_gang);
 
   // Also commit auxiliary data
-  _prev_bitmap_mapper->commit_regions(index, num_regions);
-  _next_bitmap_mapper->commit_regions(index, num_regions);
+  _prev_bitmap_mapper->commit_regions(index, num_regions, pretouch_gang);
+  _next_bitmap_mapper->commit_regions(index, num_regions, pretouch_gang);
 
-  _bot_mapper->commit_regions(index, num_regions);
-  _cardtable_mapper->commit_regions(index, num_regions);
+  _bot_mapper->commit_regions(index, num_regions, pretouch_gang);
+  _cardtable_mapper->commit_regions(index, num_regions, pretouch_gang);
 
-  _card_counts_mapper->commit_regions(index, num_regions);
+  _card_counts_mapper->commit_regions(index, num_regions, pretouch_gang);
 }
 
 void HeapRegionManager::uncommit_regions(uint start, size_t num_regions) {
@@ -117,9 +117,9 @@
   _card_counts_mapper->uncommit_regions(start, num_regions);
 }
 
-void HeapRegionManager::make_regions_available(uint start, uint num_regions) {
+void HeapRegionManager::make_regions_available(uint start, uint num_regions, WorkGang* pretouch_gang) {
   guarantee(num_regions > 0, "No point in calling this for zero regions");
-  commit_regions(start, num_regions);
+  commit_regions(start, num_regions, pretouch_gang);
   for (uint i = start; i < start + num_regions; i++) {
     if (_regions.get_by_index(i) == NULL) {
       HeapRegion* new_hr = new_heap_region(i);
@@ -163,11 +163,11 @@
   return MemoryUsage(0, used_sz, committed_sz, committed_sz);
 }
 
-uint HeapRegionManager::expand_by(uint num_regions) {
-  return expand_at(0, num_regions);
+uint HeapRegionManager::expand_by(uint num_regions, WorkGang* pretouch_workers) {
+  return expand_at(0, num_regions, pretouch_workers);
 }
 
-uint HeapRegionManager::expand_at(uint start, uint num_regions) {
+uint HeapRegionManager::expand_at(uint start, uint num_regions, WorkGang* pretouch_workers) {
   if (num_regions == 0) {
     return 0;
   }
@@ -181,7 +181,7 @@
   while (expanded < num_regions &&
          (num_last_found = find_unavailable_from_idx(cur, &idx_last_found)) > 0) {
     uint to_expand = MIN2(num_regions - expanded, num_last_found);
-    make_regions_available(idx_last_found, to_expand);
+    make_regions_available(idx_last_found, to_expand, pretouch_workers);
     expanded += to_expand;
     cur = idx_last_found + num_last_found + 1;
   }
--- a/hotspot/src/share/vm/gc/g1/heapRegionManager.hpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/g1/heapRegionManager.hpp	Wed Oct 05 06:28:23 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 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
@@ -34,6 +34,7 @@
 class HeapRegionClosure;
 class HeapRegionClaimer;
 class FreeRegionList;
+class WorkGang;
 
 class G1HeapRegionTable : public G1BiasedMappedArray<HeapRegion*> {
  protected:
@@ -94,10 +95,10 @@
   HeapWord* heap_bottom() const { return _regions.bottom_address_mapped(); }
   HeapWord* heap_end() const {return _regions.end_address_mapped(); }
 
-  void make_regions_available(uint index, uint num_regions = 1);
+  void make_regions_available(uint index, uint num_regions = 1, WorkGang* pretouch_gang = NULL);
 
   // Pass down commit calls to the VirtualSpace.
-  void commit_regions(uint index, size_t num_regions = 1);
+  void commit_regions(uint index, size_t num_regions = 1, WorkGang* pretouch_gang = NULL);
   void uncommit_regions(uint index, size_t num_regions = 1);
 
   // Notify other data structures about change in the heap layout.
@@ -209,12 +210,12 @@
   // HeapRegions, or re-use existing ones. Returns the number of regions the
   // sequence was expanded by. If a HeapRegion allocation fails, the resulting
   // number of regions might be smaller than what's desired.
-  uint expand_by(uint num_regions);
+  uint expand_by(uint num_regions, WorkGang* pretouch_workers = NULL);
 
   // Makes sure that the regions from start to start+num_regions-1 are available
   // for allocation. Returns the number of regions that were committed to achieve
   // this.
-  uint expand_at(uint start, uint num_regions);
+  uint expand_at(uint start, uint num_regions, WorkGang* pretouch_workers = NULL);
 
   // Find a contiguous set of empty regions of length num. Returns the start index of
   // that set, or G1_NO_HRM_INDEX.
--- a/hotspot/src/share/vm/gc/shared/collectedHeap.hpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/shared/collectedHeap.hpp	Wed Oct 05 06:28:23 2016 -0700
@@ -304,9 +304,6 @@
   inline static oop array_allocate_nozero(KlassHandle klass, int size, int length, TRAPS);
   inline static oop class_allocate(KlassHandle klass, int size, TRAPS);
 
-  inline static void post_allocation_install_obj_klass(KlassHandle klass,
-                                                       oop obj);
-
   // Raw memory allocation facilities
   // The obj and array allocate methods are covers for these methods.
   // mem_allocate() should never be
--- a/hotspot/src/share/vm/gc/shared/collectedHeap.inline.hpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/shared/collectedHeap.inline.hpp	Wed Oct 05 06:28:23 2016 -0700
@@ -41,14 +41,22 @@
 // Inline allocation implementations.
 
 void CollectedHeap::post_allocation_setup_common(KlassHandle klass,
-                                                 HeapWord* obj) {
-  post_allocation_setup_no_klass_install(klass, obj);
-  post_allocation_install_obj_klass(klass, oop(obj));
+                                                 HeapWord* obj_ptr) {
+  post_allocation_setup_no_klass_install(klass, obj_ptr);
+  oop obj = (oop)obj_ptr;
+#if ! INCLUDE_ALL_GCS
+  obj->set_klass(klass());
+#else
+  // Need a release store to ensure array/class length, mark word, and
+  // object zeroing are visible before setting the klass non-NULL, for
+  // concurrent collectors.
+  obj->release_set_klass(klass());
+#endif
 }
 
 void CollectedHeap::post_allocation_setup_no_klass_install(KlassHandle klass,
-                                                           HeapWord* objPtr) {
-  oop obj = (oop)objPtr;
+                                                           HeapWord* obj_ptr) {
+  oop obj = (oop)obj_ptr;
 
   assert(obj != NULL, "NULL object pointer");
   if (UseBiasedLocking && (klass() != NULL)) {
@@ -59,18 +67,6 @@
   }
 }
 
-void CollectedHeap::post_allocation_install_obj_klass(KlassHandle klass,
-                                                   oop obj) {
-  // These asserts are kind of complicated because of klassKlass
-  // and the beginning of the world.
-  assert(klass() != NULL || !Universe::is_fully_initialized(), "NULL klass");
-  assert(klass() == NULL || klass()->is_klass(), "not a klass");
-  assert(obj != NULL, "NULL object pointer");
-  obj->set_klass(klass());
-  assert(!Universe::is_fully_initialized() || obj->klass() != NULL,
-         "missing klass");
-}
-
 // Support for jvmti and dtrace
 inline void post_allocation_notify(KlassHandle klass, oop obj, int size) {
   // support low memory notifications (no-op if not enabled)
@@ -88,25 +84,26 @@
 }
 
 void CollectedHeap::post_allocation_setup_obj(KlassHandle klass,
-                                              HeapWord* obj,
+                                              HeapWord* obj_ptr,
                                               int size) {
-  post_allocation_setup_common(klass, obj);
+  post_allocation_setup_common(klass, obj_ptr);
+  oop obj = (oop)obj_ptr;
   assert(Universe::is_bootstrapping() ||
-         !((oop)obj)->is_array(), "must not be an array");
+         !obj->is_array(), "must not be an array");
   // notify jvmti and dtrace
-  post_allocation_notify(klass, (oop)obj, size);
+  post_allocation_notify(klass, obj, size);
 }
 
 void CollectedHeap::post_allocation_setup_class(KlassHandle klass,
-                                                HeapWord* obj,
+                                                HeapWord* obj_ptr,
                                                 int size) {
-  // Set oop_size field before setting the _klass field
-  // in post_allocation_setup_common() because the klass field
-  // indicates that the object is parsable by concurrent GC.
-  oop new_cls = (oop)obj;
+  // Set oop_size field before setting the _klass field because a
+  // non-NULL _klass field indicates that the object is parsable by
+  // concurrent GC.
+  oop new_cls = (oop)obj_ptr;
   assert(size > 0, "oop_size must be positive.");
   java_lang_Class::set_oop_size(new_cls, size);
-  post_allocation_setup_common(klass, obj);
+  post_allocation_setup_common(klass, obj_ptr);
   assert(Universe::is_bootstrapping() ||
          !new_cls->is_array(), "must not be an array");
   // notify jvmti and dtrace
@@ -114,15 +111,15 @@
 }
 
 void CollectedHeap::post_allocation_setup_array(KlassHandle klass,
-                                                HeapWord* obj,
+                                                HeapWord* obj_ptr,
                                                 int length) {
-  // Set array length before setting the _klass field
-  // in post_allocation_setup_common() because the klass field
-  // indicates that the object is parsable by concurrent GC.
+  // Set array length before setting the _klass field because a
+  // non-NULL klass field indicates that the object is parsable by
+  // concurrent GC.
   assert(length >= 0, "length should be non-negative");
-  ((arrayOop)obj)->set_length(length);
-  post_allocation_setup_common(klass, obj);
-  oop new_obj = (oop)obj;
+  ((arrayOop)obj_ptr)->set_length(length);
+  post_allocation_setup_common(klass, obj_ptr);
+  oop new_obj = (oop)obj_ptr;
   assert(new_obj->is_array(), "must be an array");
   // notify jvmti and dtrace (must be after length is set for dtrace)
   post_allocation_notify(klass, new_obj, new_obj->size());
--- a/hotspot/src/share/vm/gc/shared/workgroup.hpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/gc/shared/workgroup.hpp	Wed Oct 05 06:28:23 2016 -0700
@@ -62,7 +62,12 @@
   AbstractGangTask(const char* name) :
     _name(name),
     _gc_id(GCId::current_raw())
- {}
+  {}
+
+  AbstractGangTask(const char* name, const uint gc_id) :
+    _name(name),
+    _gc_id(gc_id)
+  {}
 
   // The abstract work method.
   // The argument tells you which member of the gang you are.
--- a/hotspot/src/share/vm/memory/allocation.hpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/memory/allocation.hpp	Wed Oct 05 06:28:23 2016 -0700
@@ -738,6 +738,7 @@
   static size_t size_for(size_t length);
 
  public:
+  static E* allocate_or_null(size_t length);
   static E* allocate(size_t length);
   static void free(E* addr, size_t length);
 };
--- a/hotspot/src/share/vm/memory/allocation.inline.hpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/memory/allocation.inline.hpp	Wed Oct 05 06:28:23 2016 -0700
@@ -153,6 +153,24 @@
 }
 
 template <class E, MEMFLAGS F>
+E* MmapArrayAllocator<E, F>::allocate_or_null(size_t length) {
+  size_t size = size_for(length);
+  int alignment = os::vm_allocation_granularity();
+
+  char* addr = os::reserve_memory(size, NULL, alignment, F);
+  if (addr == NULL) {
+    return NULL;
+  }
+
+  if (os::commit_memory(addr, size, !ExecMem, "Allocator (commit)")) {
+    return (E*)addr;
+  } else {
+    os::release_memory(addr, size);
+    return NULL;
+  }
+}
+
+template <class E, MEMFLAGS F>
 E* MmapArrayAllocator<E, F>::allocate(size_t length) {
   size_t size = size_for(length);
   int alignment = os::vm_allocation_granularity();
--- a/hotspot/src/share/vm/memory/filemap.cpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/memory/filemap.cpp	Wed Oct 05 06:28:23 2016 -0700
@@ -649,7 +649,7 @@
 
 // Memory map a region in the address space.
 static const char* shared_region_name[] = { "ReadOnly", "ReadWrite", "MiscData", "MiscCode",
-                                            "String1", "String2" };
+                                            "String1", "String2", "OptionalData" };
 
 char* FileMapInfo::map_region(int i) {
   assert(!MetaspaceShared::is_string_region(i), "sanity");
--- a/hotspot/src/share/vm/memory/filemap.hpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/memory/filemap.hpp	Wed Oct 05 06:28:23 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
@@ -252,10 +252,27 @@
   bool is_in_shared_region(const void* p, int idx) NOT_CDS_RETURN_(false);
   void print_shared_spaces() NOT_CDS_RETURN;
 
+  // The ro+rw+md+mc spaces size
+  static size_t core_spaces_size() {
+    return align_size_up((SharedReadOnlySize + SharedReadWriteSize +
+                          SharedMiscDataSize + SharedMiscCodeSize),
+                          os::vm_allocation_granularity());
+  }
+
+  // The estimated optional space size.
+  //
+  // Currently the optional space only has archived class bytes.
+  // The core_spaces_size is the size of all class metadata, which is a good
+  // estimate of the total class bytes to be archived. Only the portion
+  // containing data is written out to the archive and mapped at runtime.
+  // There is no memory waste due to unused portion in optional space.
+  static size_t optional_space_size() {
+    return core_spaces_size();
+  }
+
+  // Total shared_spaces size includes the ro, rw, md, mc and od spaces
   static size_t shared_spaces_size() {
-    return align_size_up(SharedReadOnlySize + SharedReadWriteSize +
-                         SharedMiscDataSize + SharedMiscCodeSize,
-                         os::vm_allocation_granularity());
+    return core_spaces_size() + optional_space_size();
   }
 
   // Stop CDS sharing and unmap CDS regions.
--- a/hotspot/src/share/vm/memory/metaspace.cpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/memory/metaspace.cpp	Wed Oct 05 06:28:23 2016 -0700
@@ -3172,36 +3172,28 @@
       address cds_address = NULL;
       FileMapInfo* mapinfo = new FileMapInfo();
 
-      if (JvmtiExport::should_post_class_file_load_hook()) {
-        // Currently CDS does not support JVMTI CFLH when loading shared class.
-        // If JvmtiExport::should_post_class_file_load_hook is already enabled,
-        // just disable UseSharedSpaces.
-        FileMapInfo::fail_continue("Tool agent requires sharing to be disabled.");
-        delete mapinfo;
+      // Open the shared archive file, read and validate the header. If
+      // initialization fails, shared spaces [UseSharedSpaces] are
+      // disabled and the file is closed.
+      // Map in spaces now also
+      if (mapinfo->initialize() && MetaspaceShared::map_shared_spaces(mapinfo)) {
+        cds_total = FileMapInfo::shared_spaces_size();
+        cds_address = (address)mapinfo->header()->region_addr(0);
+#ifdef _LP64
+        if (using_class_space()) {
+          char* cds_end = (char*)(cds_address + cds_total);
+          cds_end = (char *)align_ptr_up(cds_end, _reserve_alignment);
+          // If UseCompressedClassPointers is set then allocate the metaspace area
+          // above the heap and above the CDS area (if it exists).
+          allocate_metaspace_compressed_klass_ptrs(cds_end, cds_address);
+          // Map the shared string space after compressed pointers
+          // because it relies on compressed class pointers setting to work
+          mapinfo->map_string_regions();
+        }
+#endif // _LP64
       } else {
-        // Open the shared archive file, read and validate the header. If
-        // initialization fails, shared spaces [UseSharedSpaces] are
-        // disabled and the file is closed.
-        // Map in spaces now also
-        if (mapinfo->initialize() && MetaspaceShared::map_shared_spaces(mapinfo)) {
-          cds_total = FileMapInfo::shared_spaces_size();
-          cds_address = (address)mapinfo->header()->region_addr(0);
-#ifdef _LP64
-          if (using_class_space()) {
-            char* cds_end = (char*)(cds_address + cds_total);
-            cds_end = (char *)align_ptr_up(cds_end, _reserve_alignment);
-            // If UseCompressedClassPointers is set then allocate the metaspace area
-            // above the heap and above the CDS area (if it exists).
-            allocate_metaspace_compressed_klass_ptrs(cds_end, cds_address);
-            // Map the shared string space after compressed pointers
-            // because it relies on compressed class pointers setting to work
-            mapinfo->map_string_regions();
-          }
-#endif // _LP64
-        } else {
-          assert(!mapinfo->is_open() && !UseSharedSpaces,
-                 "archive file not closed or shared spaces not disabled.");
-        }
+        assert(!mapinfo->is_open() && !UseSharedSpaces,
+               "archive file not closed or shared spaces not disabled.");
       }
     }
 #endif // INCLUDE_CDS
--- a/hotspot/src/share/vm/memory/metaspaceShared.cpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp	Wed Oct 05 06:28:23 2016 -0700
@@ -65,6 +65,7 @@
 size_t MetaspaceShared::_cds_i2i_entry_code_buffers_size = 0;
 SharedMiscRegion MetaspaceShared::_mc;
 SharedMiscRegion MetaspaceShared::_md;
+SharedMiscRegion MetaspaceShared::_od;
 
 void SharedMiscRegion::initialize(ReservedSpace rs, size_t committed_byte_size,  SharedSpaceType space_type) {
   _vs.initialize(rs, committed_byte_size);
@@ -93,16 +94,24 @@
   assert(DumpSharedSpaces, "dump time only");
   _shared_rs = rs;
 
-  // Split up and initialize the misc code and data spaces
+  size_t core_spaces_size = FileMapInfo::core_spaces_size();
   size_t metadata_size = SharedReadOnlySize + SharedReadWriteSize;
-  ReservedSpace shared_ro_rw = _shared_rs->first_part(metadata_size);
-  ReservedSpace misc_section = _shared_rs->last_part(metadata_size);
 
-  // Now split into misc sections.
+  // Split into the core and optional sections
+  ReservedSpace core_data = _shared_rs->first_part(core_spaces_size);
+  ReservedSpace optional_data = _shared_rs->last_part(core_spaces_size);
+
+  // The RO/RW and the misc sections
+  ReservedSpace shared_ro_rw = core_data.first_part(metadata_size);
+  ReservedSpace misc_section = core_data.last_part(metadata_size);
+
+  // Now split the misc code and misc data sections.
   ReservedSpace md_rs   = misc_section.first_part(SharedMiscDataSize);
   ReservedSpace mc_rs   = misc_section.last_part(SharedMiscDataSize);
+
   _md.initialize(md_rs, SharedMiscDataSize, SharedMiscData);
-  _mc.initialize(mc_rs, SharedMiscCodeSize, SharedMiscData);
+  _mc.initialize(mc_rs, SharedMiscCodeSize, SharedMiscCode);
+  _od.initialize(optional_data, metadata_size, SharedOptional);
 }
 
 // Read/write a data stream for restoring/preserving metadata pointers and
@@ -521,6 +530,7 @@
   GrowableArray<Klass*> *_class_promote_order;
   VirtualSpace _md_vs;
   VirtualSpace _mc_vs;
+  VirtualSpace _od_vs;
   GrowableArray<MemRegion> *_string_regions;
 
 public:
@@ -598,15 +608,19 @@
   remove_unshareable_in_classes();
   tty->print_cr("done. ");
 
-  // Set up the share data and shared code segments.
+  // Set up the misc data, misc code and optional data segments.
   _md_vs = *MetaspaceShared::misc_data_region()->virtual_space();
   _mc_vs = *MetaspaceShared::misc_code_region()->virtual_space();
+  _od_vs = *MetaspaceShared::optional_data_region()->virtual_space();
   char* md_low = _md_vs.low();
   char* md_top = MetaspaceShared::misc_data_region()->alloc_top();
   char* md_end = _md_vs.high();
   char* mc_low = _mc_vs.low();
   char* mc_top = MetaspaceShared::misc_code_region()->alloc_top();
   char* mc_end = _mc_vs.high();
+  char* od_low = _od_vs.low();
+  char* od_top = MetaspaceShared::optional_data_region()->alloc_top();
+  char* od_end = _od_vs.high();
 
   // Reserve space for the list of Klass*s whose vtables are used
   // for patching others as needed.
@@ -661,28 +675,32 @@
   const size_t rw_alloced = rw_space->capacity_bytes_slow(Metaspace::NonClassType);
   const size_t md_alloced = md_end-md_low;
   const size_t mc_alloced = mc_end-mc_low;
+  const size_t od_alloced = od_end-od_low;
   const size_t total_alloced = ro_alloced + rw_alloced + md_alloced + mc_alloced
-                             + ss_bytes;
+                             + ss_bytes + od_alloced;
 
   // Occupied size of each space.
   const size_t ro_bytes = ro_space->used_bytes_slow(Metaspace::NonClassType);
   const size_t rw_bytes = rw_space->used_bytes_slow(Metaspace::NonClassType);
   const size_t md_bytes = size_t(md_top - md_low);
   const size_t mc_bytes = size_t(mc_top - mc_low);
+  const size_t od_bytes = size_t(od_top - od_low);
 
   // Percent of total size
-  const size_t total_bytes = ro_bytes + rw_bytes + md_bytes + mc_bytes + ss_bytes;
+  const size_t total_bytes = ro_bytes + rw_bytes + md_bytes + mc_bytes + ss_bytes + od_bytes;
   const double ro_t_perc = ro_bytes / double(total_bytes) * 100.0;
   const double rw_t_perc = rw_bytes / double(total_bytes) * 100.0;
   const double md_t_perc = md_bytes / double(total_bytes) * 100.0;
   const double mc_t_perc = mc_bytes / double(total_bytes) * 100.0;
   const double ss_t_perc = ss_bytes / double(total_bytes) * 100.0;
+  const double od_t_perc = od_bytes / double(total_bytes) * 100.0;
 
   // Percent of fullness of each space
   const double ro_u_perc = ro_bytes / double(ro_alloced) * 100.0;
   const double rw_u_perc = rw_bytes / double(rw_alloced) * 100.0;
   const double md_u_perc = md_bytes / double(md_alloced) * 100.0;
   const double mc_u_perc = mc_bytes / double(mc_alloced) * 100.0;
+  const double od_u_perc = od_bytes / double(od_alloced) * 100.0;
   const double total_u_perc = total_bytes / double(total_alloced) * 100.0;
 
 #define fmt_space "%s space: " SIZE_FORMAT_W(9) " [ %4.1f%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used] at " INTPTR_FORMAT
@@ -691,6 +709,7 @@
   tty->print_cr(fmt_space, "md", md_bytes, md_t_perc, md_alloced, md_u_perc, p2i(md_low));
   tty->print_cr(fmt_space, "mc", mc_bytes, mc_t_perc, mc_alloced, mc_u_perc, p2i(mc_low));
   tty->print_cr(fmt_space, "st", ss_bytes, ss_t_perc, ss_bytes,   100.0,     p2i(ss_low));
+  tty->print_cr(fmt_space, "od", od_bytes, od_t_perc, od_alloced, od_u_perc, p2i(od_low));
   tty->print_cr("total   : " SIZE_FORMAT_W(9) " [100.0%% of total] out of " SIZE_FORMAT_W(9) " bytes [%5.1f%% used]",
                  total_bytes, total_alloced, total_u_perc);
 
@@ -734,6 +753,10 @@
                           SharedMiscCodeSize,
                           true, true);
     mapinfo->write_string_regions(_string_regions);
+    mapinfo->write_region(MetaspaceShared::od, _od_vs.low(),
+                          pointer_delta(od_top, _od_vs.low(), sizeof(char)),
+                          pointer_delta(od_end, _od_vs.low(), sizeof(char)),
+                          true, false);
   }
 
   mapinfo->close();
@@ -1049,8 +1072,6 @@
 
 
 // Map shared spaces at requested addresses and return if succeeded.
-// Need to keep the bounds of the ro and rw space for the Metaspace::contains
-// call, or is_in_shared_space.
 bool MetaspaceShared::map_shared_spaces(FileMapInfo* mapinfo) {
   size_t image_alignment = mapinfo->alignment();
 
@@ -1068,6 +1089,7 @@
   char* _rw_base = NULL;
   char* _md_base = NULL;
   char* _mc_base = NULL;
+  char* _od_base = NULL;
 
   // Map each shared region
   if ((_ro_base = mapinfo->map_region(ro)) != NULL &&
@@ -1078,6 +1100,8 @@
       mapinfo->verify_region_checksum(md) &&
       (_mc_base = mapinfo->map_region(mc)) != NULL &&
       mapinfo->verify_region_checksum(mc) &&
+      (_od_base = mapinfo->map_region(od)) != NULL &&
+      mapinfo->verify_region_checksum(od) &&
       (image_alignment == (size_t)max_alignment()) &&
       mapinfo->validate_classpath_entry_table()) {
     // Success (no need to do anything)
@@ -1089,6 +1113,7 @@
     if (_rw_base != NULL) mapinfo->unmap_region(rw);
     if (_md_base != NULL) mapinfo->unmap_region(md);
     if (_mc_base != NULL) mapinfo->unmap_region(mc);
+    if (_od_base != NULL) mapinfo->unmap_region(od);
 #ifndef _WINDOWS
     // Release the entire mapped region
     shared_rs.release();
--- a/hotspot/src/share/vm/memory/metaspaceShared.hpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp	Wed Oct 05 06:28:23 2016 -0700
@@ -132,6 +132,7 @@
   // Used only during dumping.
   static SharedMiscRegion _md;
   static SharedMiscRegion _mc;
+  static SharedMiscRegion _od;
  public:
   enum {
     vtbl_list_size         = DEFAULT_VTBL_LIST_SIZE,
@@ -148,7 +149,10 @@
     max_strings = 2, // max number of string regions in string space
     num_non_strings = 4, // number of non-string regions
     first_string = num_non_strings, // index of first string region
-    n_regions = max_strings + num_non_strings // total number of regions
+    // The optional data region is the last region.
+    // Currently it only contains class file data.
+    od = max_strings + num_non_strings,
+    n_regions = od + 1 // total number of regions
   };
 
   // Accessor functions to save shared space created for metadata, which has
@@ -222,9 +226,10 @@
   static int count_class(const char* classlist_file);
   static void estimate_regions_size() NOT_CDS_RETURN;
 
-  // Allocate a block of memory from the "mc" or "md" regions.
+  // Allocate a block of memory from the "mc", "md", or "od" regions.
   static char* misc_code_space_alloc(size_t num_bytes) {  return _mc.alloc(num_bytes); }
   static char* misc_data_space_alloc(size_t num_bytes) {  return _md.alloc(num_bytes); }
+  static char* optional_data_space_alloc(size_t num_bytes) { return _od.alloc(num_bytes); }
 
   static address cds_i2i_entry_code_buffers(size_t total_size);
 
@@ -243,5 +248,9 @@
     assert(DumpSharedSpaces, "used during dumping only");
     return &_md;
   }
+  static SharedMiscRegion* optional_data_region() {
+    assert(DumpSharedSpaces, "used during dumping only");
+    return &_od;
+  }
 };
 #endif // SHARE_VM_MEMORY_METASPACESHARED_HPP
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp	Wed Oct 05 06:28:23 2016 -0700
@@ -41,6 +41,7 @@
 #include "memory/heapInspection.hpp"
 #include "memory/iterator.inline.hpp"
 #include "memory/metadataFactory.hpp"
+#include "memory/metaspaceShared.hpp"
 #include "memory/oopFactory.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/fieldStreams.hpp"
@@ -1972,11 +1973,6 @@
     m->remove_unshareable_info();
   }
 
-  // cached_class_file might be pointing to a malloc'ed buffer allocated by
-  // event-based tracing code at CDS dump time. It's not usable at runtime
-  // so let's clear it.
-  set_cached_class_file(NULL);
-
   // do array classes also.
   array_klasses_do(remove_unshareable_in_class);
 }
@@ -2070,6 +2066,7 @@
 }
 
 void InstanceKlass::release_C_heap_structures() {
+  assert(!this->is_shared(), "should not be called for a shared class");
 
   // Can't release the constant pool here because the constant pool can be
   // deallocated separately from the InstanceKlass for default methods and
@@ -2250,8 +2247,8 @@
         // the java.base module.  If a non-java.base package is erroneously placed
         // in the java.base module it will be caught later when java.base
         // is defined by ModuleEntryTable::verify_javabase_packages check.
-        assert(ModuleEntryTable::javabase_module() != NULL, "java.base module is NULL");
-        _package_entry = loader_data->packages()->lookup(pkg_name, ModuleEntryTable::javabase_module());
+        assert(ModuleEntryTable::javabase_moduleEntry() != NULL, "java.base module is NULL");
+        _package_entry = loader_data->packages()->lookup(pkg_name, ModuleEntryTable::javabase_moduleEntry());
       } else {
         assert(loader_data->modules()->unnamed_module() != NULL, "unnamed module is NULL");
         _package_entry = loader_data->packages()->lookup(pkg_name,
@@ -3653,6 +3650,15 @@
 }
 
 #if INCLUDE_JVMTI
+JvmtiCachedClassFileData* InstanceKlass::get_cached_class_file() {
+  if (MetaspaceShared::is_in_shared_space(_cached_class_file)) {
+    // Ignore the archived class stream data
+    return NULL;
+  } else {
+    return _cached_class_file;
+  }
+}
+
 jint InstanceKlass::get_cached_class_file_len() {
   return VM_RedefineClasses::get_cached_class_file_len(_cached_class_file);
 }
@@ -3660,4 +3666,15 @@
 unsigned char * InstanceKlass::get_cached_class_file_bytes() {
   return VM_RedefineClasses::get_cached_class_file_bytes(_cached_class_file);
 }
+
+#if INCLUDE_CDS
+JvmtiCachedClassFileData* InstanceKlass::get_archived_class_data() {
+  assert(this->is_shared(), "class should be shared");
+  if (MetaspaceShared::is_in_shared_space(_cached_class_file)) {
+    return _cached_class_file;
+  } else {
+    return NULL;
+  }
+}
 #endif
+#endif
--- a/hotspot/src/share/vm/oops/instanceKlass.hpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/oops/instanceKlass.hpp	Wed Oct 05 06:28:23 2016 -0700
@@ -783,7 +783,7 @@
   void set_cached_class_file(JvmtiCachedClassFileData *data) {
     _cached_class_file = data;
   }
-  JvmtiCachedClassFileData * get_cached_class_file() { return _cached_class_file; }
+  JvmtiCachedClassFileData * get_cached_class_file();
   jint get_cached_class_file_len();
   unsigned char * get_cached_class_file_bytes();
 
@@ -795,6 +795,13 @@
     return _jvmti_cached_class_field_map;
   }
 
+#if INCLUDE_CDS
+  void set_archived_class_data(JvmtiCachedClassFileData* data) {
+    _cached_class_file = data;
+  }
+
+  JvmtiCachedClassFileData * get_archived_class_data();
+#endif // INCLUDE_CDS
 #else // INCLUDE_JVMTI
 
   static void purge_previous_versions(InstanceKlass* ik) { return; };
--- a/hotspot/src/share/vm/oops/klass.cpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/oops/klass.cpp	Wed Oct 05 06:28:23 2016 -0700
@@ -530,7 +530,7 @@
       InstanceKlass* ik = (InstanceKlass*) k;
       module_entry = ik->module();
     } else {
-      module_entry = ModuleEntryTable::javabase_module();
+      module_entry = ModuleEntryTable::javabase_moduleEntry();
     }
     // Obtain java.lang.reflect.Module, if available
     Handle module_handle(THREAD, ((module_entry != NULL) ? JNIHandles::resolve(module_entry->module()) : (oop)NULL));
--- a/hotspot/src/share/vm/oops/oop.hpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/oops/oop.hpp	Wed Oct 05 06:28:23 2016 -0700
@@ -87,6 +87,7 @@
   inline narrowKlass* compressed_klass_addr();
 
   inline void set_klass(Klass* k);
+  inline void release_set_klass(Klass* k);
 
   // For klass field compression
   inline int klass_gap() const;
--- a/hotspot/src/share/vm/oops/oop.inline.hpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/oops/oop.inline.hpp	Wed Oct 05 06:28:23 2016 -0700
@@ -129,10 +129,14 @@
   return &_metadata._compressed_klass;
 }
 
+#define CHECK_SET_KLASS(k)                                                \
+  do {                                                                    \
+    assert(Universe::is_bootstrapping() || k != NULL, "NULL Klass");      \
+    assert(Universe::is_bootstrapping() || k->is_klass(), "not a Klass"); \
+  } while (0)
+
 void oopDesc::set_klass(Klass* k) {
-  // since klasses are promoted no store check is needed
-  assert(Universe::is_bootstrapping() || k != NULL, "must be a real Klass*");
-  assert(Universe::is_bootstrapping() || k->is_klass(), "not a Klass*");
+  CHECK_SET_KLASS(k);
   if (UseCompressedClassPointers) {
     *compressed_klass_addr() = Klass::encode_klass_not_null(k);
   } else {
@@ -140,6 +144,18 @@
   }
 }
 
+void oopDesc::release_set_klass(Klass* k) {
+  CHECK_SET_KLASS(k);
+  if (UseCompressedClassPointers) {
+    OrderAccess::release_store(compressed_klass_addr(),
+                               Klass::encode_klass_not_null(k));
+  } else {
+    OrderAccess::release_store_ptr(klass_addr(), k);
+  }
+}
+
+#undef CHECK_SET_KLASS
+
 int oopDesc::klass_gap() const {
   return *(int*)(((intptr_t)this) + klass_gap_offset_in_bytes());
 }
--- a/hotspot/src/share/vm/oops/typeArrayKlass.cpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/oops/typeArrayKlass.cpp	Wed Oct 05 06:28:23 2016 -0700
@@ -72,7 +72,7 @@
   null_loader_data->add_class(ak);
 
   // Call complete_create_array_klass after all instance variables have been initialized.
-  complete_create_array_klass(ak, ak->super(), ModuleEntryTable::javabase_module(), CHECK_NULL);
+  complete_create_array_klass(ak, ak->super(), ModuleEntryTable::javabase_moduleEntry(), CHECK_NULL);
 
   return ak;
 }
@@ -347,7 +347,7 @@
 
 // A TypeArrayKlass is an array of a primitive type, its defining module is java.base
 ModuleEntry* TypeArrayKlass::module() const {
-  return ModuleEntryTable::javabase_module();
+  return ModuleEntryTable::javabase_moduleEntry();
 }
 
 PackageEntry* TypeArrayKlass::package() const {
--- a/hotspot/src/share/vm/prims/unsafe.cpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/prims/unsafe.cpp	Wed Oct 05 06:28:23 2016 -0700
@@ -272,6 +272,31 @@
 
 // Get/PutObject must be special-cased, since it works with handles.
 
+// We could be accessing the referent field in a reference
+// object. If G1 is enabled then we need to register non-null
+// referent with the SATB barrier.
+
+#if INCLUDE_ALL_GCS
+static bool is_java_lang_ref_Reference_access(oop o, jlong offset) {
+  if (offset == java_lang_ref_Reference::referent_offset && o != NULL) {
+    Klass* k = o->klass();
+    if (InstanceKlass::cast(k)->reference_type() != REF_NONE) {
+      assert(InstanceKlass::cast(k)->is_subclass_of(SystemDictionary::Reference_klass()), "sanity");
+      return true;
+    }
+  }
+  return false;
+}
+#endif
+
+static void ensure_satb_referent_alive(oop o, jlong offset, oop v) {
+#if INCLUDE_ALL_GCS
+  if (UseG1GC && v != NULL && is_java_lang_ref_Reference_access(o, offset)) {
+    G1SATBCardTableModRefBS::enqueue(v);
+  }
+#endif
+}
+
 // These functions allow a null base pointer with an arbitrary address.
 // But if the base pointer is non-null, the offset should make some sense.
 // That is, it should be in the range [0, MAX_OBJECT_SIZE].
@@ -286,34 +311,9 @@
     v = *(oop*)index_oop_from_field_offset_long(p, offset);
   }
 
-  jobject ret = JNIHandles::make_local(env, v);
+  ensure_satb_referent_alive(p, offset, v);
 
-#if INCLUDE_ALL_GCS
-  // We could be accessing the referent field in a reference
-  // object. If G1 is enabled then we need to register non-null
-  // referent with the SATB barrier.
-  if (UseG1GC) {
-    bool needs_barrier = false;
-
-    if (ret != NULL) {
-      if (offset == java_lang_ref_Reference::referent_offset && obj != NULL) {
-        oop o = JNIHandles::resolve(obj);
-        Klass* k = o->klass();
-        if (InstanceKlass::cast(k)->reference_type() != REF_NONE) {
-          assert(InstanceKlass::cast(k)->is_subclass_of(SystemDictionary::Reference_klass()), "sanity");
-          needs_barrier = true;
-        }
-      }
-    }
-
-    if (needs_barrier) {
-      oop referent = JNIHandles::resolve(ret);
-      G1SATBCardTableModRefBS::enqueue(referent);
-    }
-  }
-#endif // INCLUDE_ALL_GCS
-
-  return ret;
+  return JNIHandles::make_local(env, v);
 } UNSAFE_END
 
 UNSAFE_ENTRY(void, Unsafe_PutObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject x_h)) {
@@ -344,6 +344,8 @@
     (void)const_cast<oop&>(v = *(volatile oop*) addr);
   }
 
+  ensure_satb_referent_alive(p, offset, v);
+
   OrderAccess::acquire();
   return JNIHandles::make_local(env, v);
 } UNSAFE_END
--- a/hotspot/src/share/vm/runtime/globals.hpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/runtime/globals.hpp	Wed Oct 05 06:28:23 2016 -0700
@@ -1596,6 +1596,10 @@
   product(bool, AlwaysPreTouch, false,                                      \
           "Force all freshly committed pages to be pre-touched")            \
                                                                             \
+  product(size_t, PreTouchParallelChunkSize, 1 * G,                         \
+          "Per-thread chunk size for parallel memory pre-touch.")           \
+          range(1, SIZE_MAX / 2)                                            \
+                                                                            \
   product_pd(size_t, CMSYoungGenPerWorker,                                  \
           "The maximum size of young gen chosen by default per GC worker "  \
           "thread available")                                               \
--- a/hotspot/src/share/vm/runtime/mutexLocker.cpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp	Wed Oct 05 06:28:23 2016 -0700
@@ -77,6 +77,8 @@
 Mutex*   DirtyCardQ_FL_lock           = NULL;
 Monitor* DirtyCardQ_CBL_mon           = NULL;
 Mutex*   Shared_DirtyCardQ_lock       = NULL;
+Mutex*   MarkStackFreeList_lock       = NULL;
+Mutex*   MarkStackChunkList_lock      = NULL;
 Mutex*   ParGCRareEvent_lock          = NULL;
 Mutex*   DerivedPointerTableGC_lock   = NULL;
 Mutex*   Compile_lock                 = NULL;
@@ -194,6 +196,9 @@
 
     def(StringDedupQueue_lock      , Monitor, leaf,        true,  Monitor::_safepoint_check_never);
     def(StringDedupTable_lock      , Mutex  , leaf,        true,  Monitor::_safepoint_check_never);
+
+    def(MarkStackFreeList_lock     , Mutex , leaf      ,   true,  Monitor::_safepoint_check_never);
+    def(MarkStackChunkList_lock    , Mutex , leaf      ,   true,  Monitor::_safepoint_check_never);
   }
   def(ParGCRareEvent_lock          , Mutex  , leaf     ,   true,  Monitor::_safepoint_check_sometimes);
   def(DerivedPointerTableGC_lock   , Mutex,   leaf,        true,  Monitor::_safepoint_check_never);
--- a/hotspot/src/share/vm/runtime/mutexLocker.hpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp	Wed Oct 05 06:28:23 2016 -0700
@@ -81,7 +81,8 @@
 extern Mutex*   Shared_DirtyCardQ_lock;          // Lock protecting dirty card
                                                  // queue shared by
                                                  // non-Java threads.
-                                                 // (see option ExplicitGCInvokesConcurrent)
+extern Mutex*   MarkStackFreeList_lock;          // Protects access to the global mark stack free list.
+extern Mutex*   MarkStackChunkList_lock;         // Protects access to the global mark stack chunk list.
 extern Mutex*   ParGCRareEvent_lock;             // Synchronizes various (rare) parallel GC ops.
 extern Mutex*   Compile_lock;                    // a lock held when Compilation is updating code (used to block CodeCache traversal, CHA updates, etc)
 extern Monitor* MethodCompileQueue_lock;         // a lock held when method compilations are enqueued, dequeued
--- a/hotspot/src/share/vm/runtime/os.cpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/runtime/os.cpp	Wed Oct 05 06:28:23 2016 -0700
@@ -1705,8 +1705,8 @@
   return res;
 }
 
-void os::pretouch_memory(void* start, void* end) {
-  for (volatile char *p = (char*)start; p < (char*)end; p += os::vm_page_size()) {
+void os::pretouch_memory(void* start, void* end, size_t page_size) {
+  for (volatile char *p = (char*)start; p < (char*)end; p += page_size) {
     *p = 0;
   }
 }
--- a/hotspot/src/share/vm/runtime/os.hpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/runtime/os.hpp	Wed Oct 05 06:28:23 2016 -0700
@@ -324,7 +324,7 @@
   // to make the OS back the memory range with actual memory.
   // Current implementation may not touch the last page if unaligned addresses
   // are passed.
-  static void   pretouch_memory(void* start, void* end);
+  static void   pretouch_memory(void* start, void* end, size_t page_size = vm_page_size());
 
   enum ProtType { MEM_PROT_NONE, MEM_PROT_READ, MEM_PROT_RW, MEM_PROT_RWX };
   static bool   protect_memory(char* addr, size_t bytes, ProtType prot,
--- a/hotspot/src/share/vm/utilities/debug.cpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/utilities/debug.cpp	Wed Oct 05 06:28:23 2016 -0700
@@ -282,6 +282,12 @@
 }
 
 void report_out_of_shared_space(SharedSpaceType shared_space) {
+  if (shared_space == SharedOptional) {
+    // The estimated shared_optional_space size is large enough
+    // for all class bytes.  It should not run out of space.
+    ShouldNotReachHere();
+  }
+
   static const char* name[] = {
     "shared read only space",
     "shared read write space",
--- a/hotspot/src/share/vm/utilities/debug.hpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/utilities/debug.hpp	Wed Oct 05 06:28:23 2016 -0700
@@ -271,7 +271,8 @@
   SharedReadOnly,
   SharedReadWrite,
   SharedMiscData,
-  SharedMiscCode
+  SharedMiscCode,
+  SharedOptional
 };
 
 void report_out_of_shared_space(SharedSpaceType space_type);
--- a/hotspot/src/share/vm/utilities/hashtable.inline.hpp	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/src/share/vm/utilities/hashtable.inline.hpp	Wed Oct 05 06:28:23 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2012, 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
@@ -79,8 +79,8 @@
 
 
 template <MEMFLAGS F> inline void HashtableBucket<F>::set_entry(BasicHashtableEntry<F>* l) {
-  // Warning: Preserve store ordering.  The SystemDictionary is read
-  //          without locks.  The new SystemDictionaryEntry must be
+  // Warning: Preserve store ordering.  The PackageEntryTable, ModuleEntryTable and
+  //          SystemDictionary are read without locks.  The new entry must be
   //          complete before other threads can be allowed to see it
   //          via a store to _buckets[index].
   OrderAccess::release_store_ptr(&_entry, l);
@@ -88,8 +88,8 @@
 
 
 template <MEMFLAGS F> inline BasicHashtableEntry<F>* HashtableBucket<F>::get_entry() const {
-  // Warning: Preserve load ordering.  The SystemDictionary is read
-  //          without locks.  The new SystemDictionaryEntry must be
+  // Warning: Preserve load ordering.  The PackageEntryTable, ModuleEntryTable and
+  //          SystemDictionary are read without locks.  The new entry must be
   //          complete before other threads can be allowed to see it
   //          via a store to _buckets[index].
   return (BasicHashtableEntry<F>*) OrderAccess::load_ptr_acquire(&_entry);
--- a/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java	Fri Sep 30 02:52:42 2016 -0700
+++ b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java	Wed Oct 05 06:28:23 2016 -0700
@@ -110,10 +110,6 @@
         excludeTestMaxRange("OldSize");
         excludeTestMaxRange("ParallelGCThreads");
 
-        excludeTestMaxRange("CompilerThreadStackSize");
-        excludeTestMaxRange("ThreadStackSize");
-        excludeTestMaxRange("VMThreadStackSize");
-
         /*
          * Remove parameters controlling the code cache. As these
          * parameters have implications on the physical memory
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/CDSTestUtils.java	Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,115 @@
+/*
+ * 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.IOException;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import jdk.test.lib.process.OutputAnalyzer;
+
+
+// This class contains common test utilities for CDS testing
+public class CDSTestUtils {
+
+    // check result of 'dump' operation
+    public static void checkDump(OutputAnalyzer output, String... extraMatches)
+        throws Exception {
+
+        output.shouldContain("Loading classes to share");
+        output.shouldHaveExitValue(0);
+
+        for (String match : extraMatches) {
+            output.shouldContain(match);
+        }
+    }
+
+
+    // check the output for indication that mapping of the archive failed
+    public static boolean isUnableToMap(OutputAnalyzer output) {
+        String outStr = output.getOutput();
+        if ((output.getExitValue() == 1) && (
+            outStr.contains("Unable to reserve shared space at required address") ||
+            outStr.contains("Unable to map ReadOnly shared space at required address") ||
+            outStr.contains("Unable to map ReadWrite shared space at required address") ||
+            outStr.contains("Unable to map MiscData shared space at required address") ||
+            outStr.contains("Unable to map MiscCode shared space at required address") ||
+            outStr.contains("Unable to map shared string space at required address") ||
+            outStr.contains("Could not allocate metaspace at a compatible address") ||
+            outStr.contains("Unable to allocate shared string space: range is not within java heap") ))
+        {
+            return true;
+        }
+
+        return false;
+    }
+
+    // check result of 'exec' operation, that is when JVM is run using the archive
+    public static void checkExec(OutputAnalyzer output, String... extraMatches) throws Exception {
+        if (isUnableToMap(output)) {
+            System.out.println("Unable to map shared archive: test did not complete; assumed PASS");
+            return;
+        }
+        output.shouldContain("sharing");
+        output.shouldHaveExitValue(0);
+
+        for (String match : extraMatches) {
+            output.shouldContain(match);
+        }
+    }
+
+
+    // get the file object for the test artifact
+    private static File getTestArtifactFile(String prefix, String name) {
+        File dir = new File(System.getProperty("test.classes", "."));
+        return new File(dir, prefix + name);
+    }
+
+
+    // create file containing the specified class list
+    public static File makeClassList(String testCaseName, String classes[])
+        throws Exception {
+
+        File classList = getTestArtifactFile(testCaseName, "test.classlist");
+        FileOutputStream fos = new FileOutputStream(classList);
+        PrintStream ps = new PrintStream(fos);
+
+        addToClassList(ps, classes);
+
+        ps.close();
+        fos.close();
+
+        return classList;
+    }
+
+
+    private static void addToClassList(PrintStream ps, String classes[])
+        throws IOException
+    {
+        if (classes != null) {
+            for (String s : classes) {
+                ps.println(s);
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/Implementor.java	Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+public class Implementor implements Interface {
+    public static void main(String[] args) {
+        System.out.println("Implementor: entering main()");
+        test();
+    }
+
+    public static void test() {
+        // from interface
+        (new Implementor()).printString();
+        // from implementor
+        System.out.println(TransformUtil.ChildCheckPattern +
+                           TransformUtil.BeforePattern);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/Interface.java	Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+public interface Interface {
+    public static final String stringToBeTransformed =
+        TransformUtil.ParentCheckPattern + TransformUtil.BeforePattern;
+
+    default void printString() {
+        System.out.println(stringToBeTransformed);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/SubClass.java	Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+public class SubClass extends SuperClazz {
+    public static void main(String[] args) {
+        System.out.println("SubClass: entering main()");
+        test();
+    }
+
+    public static void test() {
+        // The line below will be used to check for successful class transformation
+        System.out.println(TransformUtil.ChildCheckPattern +
+                           TransformUtil.BeforePattern);
+        (new SubClass()).callParent();
+    }
+
+    private void callParent() {
+        super.testParent();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/SuperClazz.java	Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+
+public class SuperClazz {
+    public static void testParent() {
+        System.out.println("SuperClazz: entering testParent()");
+
+        // The line below will be used to check for successful class transformation
+        System.out.println(TransformUtil.ParentCheckPattern + TransformUtil.BeforePattern);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TestEntry.java	Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+
+// Test Entry - a single entry in a test table
+// that defines a test case
+// See TransformRelatedClasses.java for more details
+public class TestEntry {
+    int testCaseId;
+    boolean transformParent;
+    boolean transformChild;
+    boolean isParentExpectedShared;
+    boolean isChildExpectedShared;
+
+    public TestEntry(int testCaseId,
+                     boolean transformParent, boolean transformChild,
+                     boolean isParentExpectedShared, boolean isChildExpectedShared) {
+        this.testCaseId = testCaseId;
+        this.transformParent = transformParent;
+        this.transformChild = transformChild;
+        this.isParentExpectedShared = isParentExpectedShared;
+        this.isChildExpectedShared = isChildExpectedShared;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformInterfaceAndImplementor.java	Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Exercise initial transformation (ClassFileLoadHook)
+ *  with CDS with Interface/Implementor pair
+ * @library /test/lib /runtime/SharedArchiveFile /testlibrary/jvmti
+ * @requires (vm.opt.UseCompressedOops == null) | (vm.opt.UseCompressedOops == true)
+ * @requires vm.flavor != "minimal"
+ * @modules java.base/jdk.internal.misc
+ *          jdk.jartool/sun.tools.jar
+ *          java.management
+ *          java.instrument
+ * @build TransformUtil TransformerAgent Interface Implementor
+ * @run main/othervm TransformRelatedClasses Interface Implementor
+ */
+
+// Clarification on @requires declarations:
+// CDS is not supported w/o the use of Compressed OOPs
+// JVMTI's ClassFileLoadHook is not supported under minimal VM
+
+// This test class uses TransformRelatedClasses to do its work.
+// The goal of this test is to exercise transformation of related interface
+// and its implementor in combination with CDS.
+// The transformation is done via ClassFileLoadHook mechanism.
+// Both superclass and subclass reside in the shared archive.
+// The test consists of 4 test cases where transformation is applied
+// to an interface and an implementor in a combinatorial manner.
+// Please see TransformRelatedClasses.java for details.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformRelatedClasses.java	Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,179 @@
+/*
+ * 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.
+ */
+
+
+// This is the main test class for testing transformation of related classes
+// in combination with CDS, to ensure these features work well together.
+// The relationships that can be tested using this test class are:
+// superclass/subclass, and interface/implementor relationships.
+//
+// The test uses combinatorial approach.
+// For details on test table and test cases see main() method in this class.
+//
+// This test consists of multiple classes for better flexibility and reuse,
+// and also relies on certain common utility code.
+// Here are the details on the structure of the test
+//
+// Structure of the test:
+// TransformRelatedClasses -- common main test driver
+//     The TransformRelatedClasses is invoked from test driver classes:
+//     TransformInterfaceAndImplementor, TransformSuperAndSubClasses
+//     It is responsible for preparing test artifacts (test jar, agent jar
+//     and the shared archive), running test cases and checking the results.
+// The following test classes below are launched in a sub-process with use
+// of shared archive:
+//     SuperClazz, SubClass -- super/sub class pair under test
+//     Interface, Implementor -- classes under test
+// This test will transform these classes, based on the test case data,
+// by changing a predefined unique string in each class.
+// For more details, see the test classes' code and comments.
+//
+// Other related classes:
+//     TestEntry - a class representing a single test case, as test entry in the table
+//     TransformTestCommon - common methods for transformation test cases
+//
+// Other utility/helper classes and files used in this test:
+//     TransformerAgent - an agent that is used when JVM-under-test is executed
+//         to transform specific strings inside specified classes
+//     TransformerAgent.mf - accompanies transformer agent
+//     CDSTestUtils - Test Utilities common to all CDS tests
+
+import java.io.File;
+import java.util.ArrayList;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+
+public class TransformRelatedClasses {
+    static final String archiveName = "./TransformRelatedClasses.jsa";
+    static String agentClasses[] = {
+        "TransformerAgent",
+        "TransformerAgent$SimpleTransformer",
+        "TransformUtil"
+    };
+
+    String parent;
+    String child;
+    String[] testClasses = new String[2];
+    String[] testNames = new String[2];
+    String testJar;
+    String agentJar;
+
+
+    private static void log(String msg) {
+        System.out.println("TransformRelatedClasses: " + msg);
+    }
+
+
+    // This class is intended to test 2 parent-child relationships:
+    // 1. Base Class (parent) and Derived Class (child)
+    // 2. Interface (parent) and Implementor (child)
+    //    Parameters to main(): parent, child
+    public static void main(String args[]) throws Exception {
+        TransformRelatedClasses test = new TransformRelatedClasses(args[0], args[1]);
+        test.prepare();
+
+        // Test Table
+        // TestEntry:  (testCaseId, transformParent, tranformChild,
+        //             isParentExpectedShared, isChildExpectedShared)
+        ArrayList<TestEntry> testTable = new ArrayList<>();
+
+        // base case - no tranformation - all expected to be shared
+        testTable.add(new TestEntry(0, false, false, true, true));
+
+        // transform parent only - both parent and child should not be shared
+        testTable.add(new TestEntry(1, true, false, false, false));
+
+        // transform parent and child - both parent and child should not be shared
+        testTable.add(new TestEntry(2, true, true, false, false));
+
+        // transform child only - parent should still be shared, but not child
+        testTable.add(new TestEntry(3, false, true, true, false));
+
+        // run the tests
+        for (TestEntry entry : testTable) {
+            test.runTest(entry);
+        }
+    }
+
+
+    public TransformRelatedClasses(String parent, String child) {
+        log("Constructor: parent = " + parent + ", child = " + child);
+        this.parent = parent;
+        this.child = child;
+        testClasses[0] = parent;
+        testClasses[1] = child;
+        testNames[0] = parent.replace('.', '/');
+        testNames[1] = child.replace('.', '/');
+    }
+
+
+    // same test jar and archive can be used for all test cases
+    private void prepare() throws Exception {
+        // create agent jar
+        // Agent is the same for all test cases
+        String pathToManifest = "../../../../testlibrary/jvmti/TransformerAgent.mf";
+        agentJar = ClassFileInstaller.writeJar("TransformerAgent.jar",
+                       ClassFileInstaller.Manifest.fromSourceFile(pathToManifest),
+                                           agentClasses);
+
+        // create a test jar
+        testJar =
+            ClassFileInstaller.writeJar(parent + "-" + child + ".jar",
+                                           testClasses);
+
+        // create an archive
+        File classList = CDSTestUtils.makeClassList("transform-" + parent,
+                                                    testNames);
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true,
+                                        "-Xbootclasspath/a:" + testJar,
+                                        "-XX:+UnlockDiagnosticVMOptions",
+                                        "-XX:ExtraSharedClassListFile=" +
+                                        classList.getPath(),
+                                        "-XX:SharedArchiveFile=" + archiveName,
+                                        "-XX:+PrintSharedSpaces",
+                                        "-Xshare:dump");
+        OutputAnalyzer out = new OutputAnalyzer(pb.start());
+        CDSTestUtils.checkDump(out);
+    }
+
+
+    private void runTest(TestEntry entry) throws Exception {
+        log("runTest(): testCaseId = " + entry.testCaseId);
+
+        // execute with archive
+        String agentParam = "-javaagent:" + agentJar + "=" +
+            TransformTestCommon.getAgentParams(entry, parent, child);
+
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(true,
+                                        "-Xbootclasspath/a:" + testJar,
+                                        "-XX:+UnlockDiagnosticVMOptions",
+                                        "-XX:SharedArchiveFile=" + archiveName,
+                                        "-Xlog:class+load=info",
+                                        "-Xshare:on", "-showversion",
+                                        agentParam, child);
+        OutputAnalyzer out = new OutputAnalyzer(pb.start());
+
+        TransformTestCommon.checkResults(entry, out, parent, child);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperAndSubClasses.java	Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+
+/*
+ * @test
+ * @summary Exercise initial transformation (ClassFileLoadHook)
+ *  with CDS with SubClass and SuperClass
+ * @library /test/lib /runtime/SharedArchiveFile /testlibrary/jvmti
+ * @requires (vm.opt.UseCompressedOops == null) | (vm.opt.UseCompressedOops == true)
+ * @requires vm.flavor != "minimal"
+ * @modules java.base/jdk.internal.misc
+ *          jdk.jartool/sun.tools.jar
+ *          java.management
+ *          java.instrument
+ * @build TransformUtil TransformerAgent SubClass SuperClazz
+ * @run main/othervm TransformRelatedClasses SuperClazz SubClass
+*/
+
+// Clarification on @requires declarations:
+// CDS is not supported w/o the use of Compressed OOPs
+// JVMTI's ClassFileLoadHook is not supported under minimal VM
+
+// This test class uses TransformRelatedClasses to do its work.
+// The goal of this test is to exercise transformation of related superclass
+// and subclass in combination with CDS.
+// The transformation is done via ClassFileLoadHook mechanism.
+// Both superclass and subclass reside in the shared archive.
+// The test consists of 4 test cases where transformation is applied
+// to a parent and child in combinatorial manner.
+// Please see TransformRelatedClasses.java for details.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperSubTwoPckgs.java	Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+
+/*
+ * @test
+ * @summary Exercise initial transformation (ClassFileLoadHook)
+ *  with CDS with SubClass and SuperClass, each lives in own separate package
+ * @library /test/lib /runtime/SharedArchiveFile /testlibrary/jvmti
+ * @requires (vm.opt.UseCompressedOops == null) | (vm.opt.UseCompressedOops == true)
+ * @requires vm.flavor != "minimal"
+ * @modules java.base/jdk.internal.misc
+ *          jdk.jartool/sun.tools.jar
+ *          java.management
+ *          java.instrument
+ * @build TransformUtil TransformerAgent SubClass SuperClazz
+ * @compile myPkg2/SubClass.java myPkg1/SuperClazz.java
+ * @run main/othervm TransformRelatedClasses myPkg1.SuperClazz myPkg2.SubClass
+*/
+
+// Clarification on @requires declarations:
+// CDS is not supported w/o the use of Compressed OOPs
+// JVMTI's ClassFileLoadHook is not supported under minimal VM
+
+// This test class uses TransformRelatedClasses to do its work.
+// The goal of this test is to exercise transformation of related superclass
+// and subclass in combination with CDS; each class lives in its own package.
+// The transformation is done via ClassFileLoadHook mechanism.
+// Both superclass and subclass reside in the shared archive.
+// The test consists of 4 test cases where transformation is applied
+// to a parent and child in combinatorial manner.
+// Please see TransformRelatedClasses.java for details.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformTestCommon.java	Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,114 @@
+/*
+ * 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 jdk.test.lib.process.OutputAnalyzer;
+
+
+// This class contains methods common to all transformation test cases
+public class TransformTestCommon {
+
+    // get parameters to an agent depending on the test case
+    // these parameters will instruct the agent which classes should be
+    // transformed
+    public static String getAgentParams(TestEntry entry,
+                                        String parent, String child) {
+
+        if (entry.transformParent && entry.transformChild)
+            return parent + "," + child;
+        if (entry.transformParent)
+            return parent;
+        if (entry.transformChild)
+            return child;
+
+        return "";
+    }
+
+
+    private static void checkTransformationResults(TestEntry entry,
+                                                   OutputAnalyzer out)
+        throws Exception {
+
+        if (entry.transformParent)
+            out.shouldContain(TransformUtil.ParentCheckPattern +
+                              TransformUtil.AfterPattern);
+
+        if (entry.transformChild)
+            out.shouldContain(TransformUtil.ChildCheckPattern +
+                              TransformUtil.AfterPattern);
+    }
+
+
+    private static void checkSharingByClass(TestEntry entry, OutputAnalyzer out,
+                                            String parent, String child)
+        throws Exception {
+
+        String parentSharedMatch = parent + " source: shared objects file";
+        String childSharedMatch =  child +  " source: shared objects file";
+
+        if (entry.isParentExpectedShared)
+            out.shouldContain(parentSharedMatch);
+        else
+            out.shouldNotContain(parentSharedMatch);
+
+        if (entry.isChildExpectedShared)
+            out.shouldContain(childSharedMatch);
+        else
+            out.shouldNotContain(childSharedMatch);
+    }
+
+
+    // Both parent and child classes should be passed to ClassFileTransformer.transform()
+    // exactly once.
+    private static void checkTransformationCounts(TestEntry entry, OutputAnalyzer out,
+                                                  String parent, String child)
+        throws Exception {
+
+        String patternBase = "TransformerAgent: SimpleTransformer called for: ";
+
+        out.shouldContain(patternBase + child + "@1");
+        out.shouldContain(patternBase + parent + "@1");
+
+        out.shouldNotContain(patternBase + child + "@2");
+        out.shouldNotContain(patternBase + parent + "@2");
+    }
+
+
+    public static void checkResults(TestEntry entry, OutputAnalyzer out,
+                                    String parent, String child)
+        throws Exception {
+
+        // If we were not able to map an archive,
+        // then do not perform other checks, since
+        // there was no sharing at all
+        if (CDSTestUtils.isUnableToMap(out))
+            return;
+
+        String childVmName = child.replace('.', '/');
+        String parentVmName = parent.replace('.', '/');
+
+        CDSTestUtils.checkExec(out);
+        checkTransformationCounts(entry, out, parentVmName, childVmName);
+        checkTransformationResults(entry, out);
+        checkSharingByClass(entry, out, parent, child);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/myPkg1/SuperClazz.java	Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+package myPkg1;
+
+public class SuperClazz {
+    public static void testParent() {
+        System.out.println("SuperClazz: entering testParent()");
+
+        // The line below will be used to check for successful class transformation
+        System.out.println("parent-transform-check: this-should-be-transformed");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/myPkg2/SubClass.java	Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+package myPkg2;
+
+import myPkg1.SuperClazz;
+
+public class SubClass extends SuperClazz {
+    public static void main(String[] args) {
+        System.out.println("SubClass: entering main()");
+        test();
+    }
+
+    public static void test() {
+        // The line below will be used to check for successful class transformation
+        System.out.println("child-transform-check: this-should-be-transformed");
+        (new SubClass()).callParent();
+
+        // Get the system packages, which should contain myPkg1 and myPkag2
+        Package[] pkgs = Package.getPackages();
+        for (int i = 0; i < pkgs.length; i++) {
+            if (pkgs[i].getName().equals("myPkg1")) {
+                for (int j = 0; j < pkgs.length; j++) {
+                    if (pkgs[j].getName().equals("myPkg2")) {
+                        return; // found myPkg1 & myPkg1
+                    }
+                }
+            }
+        }
+        throw new RuntimeException("Missing system package");
+    }
+
+    private void callParent() {
+        super.testParent();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/jvmti/TransformUtil.java	Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+
+public class TransformUtil {
+    public static final String BeforePattern = "this-should-be-transformed";
+    public static final String AfterPattern  = "this-has-been--transformed";
+    public static final String ParentCheckPattern = "parent-transform-check: ";
+    public static final String ChildCheckPattern = "child-transform-check: ";
+
+    /**
+     * @return the number of occurrences of the <code>from</code> string that
+     * have been replaced.
+     */
+    public static int replace(byte buff[], String from, String to) {
+        if (to.length() != from.length()) {
+            throw new RuntimeException("bad strings");
+        }
+        byte f[] = asciibytes(from);
+        byte t[] = asciibytes(to);
+        byte f0 = f[0];
+
+        int numReplaced = 0;
+        int max = buff.length - f.length;
+        for (int i = 0; i < max; ) {
+            if (buff[i] == f0 && replace(buff, f, t, i)) {
+                i += f.length;
+                numReplaced++;
+            } else {
+                i++;
+            }
+        }
+        return numReplaced;
+    }
+
+    public static boolean replace(byte buff[], byte f[], byte t[], int i) {
+        for (int x = 0; x < f.length; x++) {
+            if (buff[x+i] != f[x]) {
+                return false;
+            }
+        }
+        for (int x = 0; x < f.length; x++) {
+            buff[x+i] = t[x];
+        }
+        return true;
+    }
+
+    static byte[] asciibytes(String s) {
+        byte b[] = new byte[s.length()];
+        for (int i = 0; i < b.length; i++) {
+            b[i] = (byte)s.charAt(i);
+        }
+        return b;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/jvmti/TransformerAgent.java	Wed Oct 05 06:28:23 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.lang.instrument.ClassFileTransformer;
+import java.lang.instrument.IllegalClassFormatException;
+import java.lang.instrument.Instrumentation;
+import java.security.ProtectionDomain;
+import java.util.HashMap;
+
+// This is a test utility class used to transform
+// specified classes via initial transformation (ClassFileLoadHook).
+// Names of classes to be transformed are supplied as arguments,
+// the phrase to be transformed is a hard-coded predefined
+// fairly unique phrase.
+
+public class TransformerAgent {
+    private static String[] classesToTransform;
+
+
+    private static void log(String msg) {
+        System.out.println("TransformerAgent: " + msg);
+    }
+
+
+    // arguments are comma-separated list of classes to transform
+    public static void premain(String agentArguments, Instrumentation instrumentation) {
+        log("premain() is called, arguments = " + agentArguments);
+        classesToTransform = agentArguments.split(",");
+        instrumentation.addTransformer(new SimpleTransformer(), /*canRetransform=*/true);
+    }
+
+
+    public static void agentmain(String args, Instrumentation inst) throws Exception {
+        log("agentmain() is called");
+        premain(args, inst);
+    }
+
+
+    static class SimpleTransformer implements ClassFileTransformer {
+       public byte[] transform(ClassLoader loader, String name, Class<?> classBeingRedefined,
+                            ProtectionDomain pd, byte[] buffer) throws IllegalClassFormatException {
+
+            log("SimpleTransformer called for: " + name + "@" + incrCounter(name));
+            if (!shouldTransform(name))
+                return null;
+
+            log("transforming: class name = " + name);
+            int nrOfReplacements = TransformUtil.replace(buffer, TransformUtil.BeforePattern,
+                                                         TransformUtil.AfterPattern);
+            log("replaced the string, nrOfReplacements = " + nrOfReplacements);
+            return buffer;
+        }
+
+        // Check class name pattern, since test should only transform certain classes
+        private static boolean shouldTransform(String name) {
+            for (String match : classesToTransform) {
+                if (name.matches(match)) {
+                    log("shouldTransform: match-found, match = " + match);
+                    return true;
+                }
+            }
+
+            return false;
+        }
+    }
+
+
+    static HashMap<String, Integer> counterMap = new HashMap<>();
+
+    static Integer incrCounter(String className) {
+        Integer i = counterMap.get(className);
+        if (i == null) {
+            i = new Integer(1);
+        } else {
+            i = new Integer(i.intValue() + 1);
+        }
+        counterMap.put(className, i);
+        return i;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/jvmti/TransformerAgent.mf	Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,5 @@
+Manifest-Version: 1.0
+Premain-Class: TransformerAgent
+Agent-Class: TransformerAgent
+Can-Retransform-Classes: true
+Can-Redefine-Classes: false
--- a/jaxp/.hgtags	Fri Sep 30 02:52:42 2016 -0700
+++ b/jaxp/.hgtags	Wed Oct 05 06:28:23 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:42 2016 -0700
+++ b/jaxws/.hgtags	Wed Oct 05 06:28:23 2016 -0700
@@ -383,3 +383,4 @@
 22631824f55128a7ab6605493b3001a37af6a168 jdk-9+135
 09ec13a99f50a4a346180d1e3b0fd8bc1ee399ce jdk-9+136
 297c16d401c534cb879809d2a746d21ca99d2954 jdk-9+137
+7d3a8f52b124db26ba8425c2931b748dd9d2791b jdk-9+138
--- a/jdk/make/CompileDemos.gmk	Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/make/CompileDemos.gmk	Wed Oct 05 06:28:23 2016 -0700
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -338,6 +338,7 @@
       OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/demos/native/jvmti/$1, \
       OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/demos/image/jvmti/$1/lib, \
       LIBRARY := $1, \
+      STRIP_SYMBOLS := false, \
   ))
 
   $1 += $$(BUILD_DEMO_JVMTI_NATIVE_$1)
@@ -453,6 +454,7 @@
       OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/demos/native/jni/Poller, \
       OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/demos/native, \
       LIBRARY := Poller, \
+      STRIP_SYMBOLS := false, \
   ))
 
   TARGETS += $(BUILD_DEMO_NATIVE_Poller)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/CompileModuleTools.gmk	Wed Oct 05 06:28:23 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/Import.gmk	Fri Sep 30 02:52:42 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,225 +0,0 @@
-#
-# Copyright (c) 2012, 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.
-#
-
-default: all
-
-include $(SPEC)
-include MakeBase.gmk
-
-################################################################################
-
-# Put the libraries here. Different locations for different target OS types.
-ifneq ($(OPENJDK_TARGET_OS), windows)
-  HOTSPOT_LIB_DIR := $(HOTSPOT_DIST)/lib$(OPENJDK_TARGET_CPU_LIBDIR)
-  BASE_INSTALL_LIBRARIES_HERE := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base$(OPENJDK_TARGET_CPU_LIBDIR)
-else
-  HOTSPOT_LIB_DIR := $(HOTSPOT_DIST)/bin
-  BASE_INSTALL_LIBRARIES_HERE := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base
-endif
-
-################################################################################
-#
-# Import hotspot
-#
-
-# Don't import jsig library for static builds
-ifneq ($(STATIC_BUILD), true)
-  JSIG_IMPORT = jsig.*
-else
-  JSIG_IMPORT =
-endif
-
-HOTSPOT_BASE_IMPORT_FILES := \
-    $(addprefix $(LIBRARY_PREFIX), jvm.* $(JSIG_IMPORT) jvm_db.* jvm_dtrace.*) \
-    Xusage.txt \
-    #
-
-$(eval $(call SetupCopyFiles,COPY_HOTSPOT_BASE, \
-    SRC := $(HOTSPOT_LIB_DIR), \
-    DEST := $(BASE_INSTALL_LIBRARIES_HERE), \
-    FILES := $(shell $(FIND) $(HOTSPOT_LIB_DIR) -type f  \
-        -a \( -name DUMMY $(addprefix -o$(SPACE)-name$(SPACE), $(HOTSPOT_BASE_IMPORT_FILES)) \) )))
-
-ifeq ($(OPENJDK_TARGET_OS), windows)
-  $(eval $(call SetupCopyFiles,COPY_HOTSPOT_BASE_JVMLIB, \
-      SRC := $(HOTSPOT_DIST)/lib, \
-      DEST := $(BASE_INSTALL_LIBRARIES_HERE), \
-      FILES := $(wildcard $(HOTSPOT_DIST)/lib/*.lib)))
-endif
-
-BASE_TARGETS := $(COPY_HOTSPOT_BASE) $(COPY_HOTSPOT_BASE_JVMLIB)
-
-################################################################################
-
-ifneq ($(STATIC_BUILD), true)
-  ifeq ($(OPENJDK_TARGET_OS), macosx)
-    JSIG_DEBUGINFO := $(strip $(wildcard $(HOTSPOT_DIST)/lib$(OPENJDK_TARGET_CPU_LIBDIR)/libjsig$(SHARED_LIBRARY_SUFFIX).dSYM) \
-        $(wildcard $(HOTSPOT_DIST)/lib$(OPENJDK_TARGET_CPU_LIBDIR)/libjsig.diz) )
-  else
-    JSIG_DEBUGINFO := $(strip $(wildcard $(HOTSPOT_DIST)/lib$(OPENJDK_TARGET_CPU_LIBDIR)/libjsig.debuginfo) \
-        $(wildcard $(HOTSPOT_DIST)/lib$(OPENJDK_TARGET_CPU_LIBDIR)/libjsig.diz) )
-  endif
-
-  ifneq ($(OPENJDK_TARGET_OS), windows)
-    ifeq ($(call check-jvm-variant, server), true)
-      BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/server/$(LIBRARY_PREFIX)jsig$(SHARED_LIBRARY_SUFFIX)
-      ifneq (, $(JSIG_DEBUGINFO))
-        BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/server/$(foreach I,$(JSIG_DEBUGINFO),$(notdir $I))
-      endif
-    endif
-    ifeq ($(call check-jvm-variant, client), true)
-      BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/client/$(LIBRARY_PREFIX)jsig$(SHARED_LIBRARY_SUFFIX)
-      ifneq (, $(JSIG_DEBUGINFO))
-        BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/client/$(foreach I,$(JSIG_DEBUGINFO),$(notdir $I))
-      endif
-    endif
-    ifneq ($(OPENJDK_TARGET_OS), macosx)
-      ifeq ($(call check-jvm-variant, minimal), true)
-        BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/minimal/$(LIBRARY_PREFIX)jsig$(SHARED_LIBRARY_SUFFIX)
-        ifneq (,$(JSIG_DEBUGINFO))
-          BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/minimal/$(foreach I,$(JSIG_DEBUGINFO),$(notdir $I))
-        endif
-      endif
-    endif
-  endif
-endif
-
-$(BASE_INSTALL_LIBRARIES_HERE)/server/%$(SHARED_LIBRARY_SUFFIX): $(BASE_INSTALL_LIBRARIES_HERE)/%$(SHARED_LIBRARY_SUFFIX)
-	$(MKDIR) -p $(@D)
-	$(RM) $@
-	$(LN) -s ../$(@F) $@
-
-ifeq ($(OPENJDK_TARGET_OS), macosx)
-  $(BASE_INSTALL_LIBRARIES_HERE)/server/%.dSYM:
-	$(MKDIR) -p $(@D)
-	$(RM) $@
-	$(LN) -s ../$(@F) $@
-
-  $(BASE_INSTALL_LIBRARIES_HERE)/server/%.diz : $(BASE_INSTALL_LIBRARIES_HERE)/%.diz
-	$(MKDIR) -p $(@D)
-	$(RM) $@
-	$(RM) $@.tmp $(basename $@)$(SHARED_LIBRARY_SUFFIX).dSYM
-	$(LN) -s ../$(basename $(@F))$(SHARED_LIBRARY_SUFFIX).dSYM $(basename $@)$(SHARED_LIBRARY_SUFFIX).dSYM
-	$(CD) $(@D) && $(ZIP) -q -y $@.tmp $(basename $(@F))$(SHARED_LIBRARY_SUFFIX).dSYM
-	$(RM) $(basename $@)$(SHARED_LIBRARY_SUFFIX).dSYM
-	$(MV) $@.tmp $@
-else
-  $(BASE_INSTALL_LIBRARIES_HERE)/server/%.debuginfo: $(BASE_INSTALL_LIBRARIES_HERE)/%.debuginfo
-	$(MKDIR) -p $(@D)
-	$(RM) $@
-	$(LN) -s ../$(@F) $@
-
-  $(BASE_INSTALL_LIBRARIES_HERE)/server/%.diz: $(BASE_INSTALL_LIBRARIES_HERE)/%.diz
-	$(MKDIR) -p $(@D)
-	$(RM) $@
-	$(RM) $@.tmp $(basename $@).debuginfo
-	$(LN) -s ../$(basename $(@F)).debuginfo $(basename $@).debuginfo
-	$(CD) $(@D) && $(ZIP) -q -y $@.tmp $(basename $(@F)).debuginfo
-	$(RM) $(basename $@).debuginfo
-	$(MV) $@.tmp $@
-endif
-
-$(BASE_INSTALL_LIBRARIES_HERE)/client/%$(SHARED_LIBRARY_SUFFIX): $(BASE_INSTALL_LIBRARIES_HERE)/%$(SHARED_LIBRARY_SUFFIX)
-	$(MKDIR) -p $(@D)
-	$(RM) $@
-	$(LN) -s ../$(@F) $@
-
-ifeq ($(OPENJDK_TARGET_OS), macosx)
-  $(BASE_INSTALL_LIBRARIES_HERE)/client/%.dSYM : $(BASE_INSTALL_LIBRARIES_HERE)/%.dSYM
-	$(MKDIR) -p $(@D)
-	$(RM) $@
-	$(LN) -s ../$(@F) $@
-
-  $(BASE_INSTALL_LIBRARIES_HERE)/client/%.diz : $(BASE_INSTALL_LIBRARIES_HERE)/%.diz
-	$(MKDIR) -p $(@D)
-	$(RM) $@
-	$(RM) $@.tmp $(basename $@)$(SHARED_LIBRARY_SUFFIX).dSYM
-	$(LN) -s ../$(basename $(@F))$(SHARED_LIBRARY_SUFFIX).dSYM $(basename $@)$(SHARED_LIBRARY_SUFFIX).dSYM
-	$(CD) $(@D) && $(ZIP) -q -y $@.tmp $(basename $(@F))$(SHARED_LIBRARY_SUFFIX).dSYM
-	$(RM) $(basename $@)$(SHARED_LIBRARY_SUFFIX).dSYM
-	$(MV) $@.tmp $@
-else
-  $(BASE_INSTALL_LIBRARIES_HERE)/client/%.debuginfo: $(BASE_INSTALL_LIBRARIES_HERE)/%.debuginfo
-	$(MKDIR) -p $(@D)
-	$(RM) $@
-	$(LN) -s ../$(@F) $@
-
-  $(BASE_INSTALL_LIBRARIES_HERE)/client/%.diz: $(BASE_INSTALL_LIBRARIES_HERE)/%.diz
-	$(MKDIR) -p $(@D)
-	$(RM) $@
-	$(RM) $@.tmp $(basename $@).debuginfo
-	$(LN) -s ../$(basename $(@F)).debuginfo $(basename $@).debuginfo
-	$(CD) $(@D) && $(ZIP) -q -y $@.tmp $(basename $(@F)).debuginfo
-	$(RM) $(basename $@).debuginfo
-	$(MV) $@.tmp $@
-endif
-
-$(BASE_INSTALL_LIBRARIES_HERE)/minimal/%$(SHARED_LIBRARY_SUFFIX): $(BASE_INSTALL_LIBRARIES_HERE)/%$(SHARED_LIBRARY_SUFFIX)
-	$(MKDIR) -p $(@D)
-	$(RM) $@
-	$(LN) -s ../$(@F) $@
-
-ifneq ($(OPENJDK_TARGET_OS), macosx)
-  $(BASE_INSTALL_LIBRARIES_HERE)/minimal/%.debuginfo: $(BASE_INSTALL_LIBRARIES_HERE)/%.debuginfo
-	$(MKDIR) -p $(@D)
-	$(RM) $@
-	$(LN) -s ../$(@F) $@
-
-  $(BASE_INSTALL_LIBRARIES_HERE)/minimal/%.diz: $(BASE_INSTALL_LIBRARIES_HERE)/%.diz
-	$(MKDIR) -p $(@D)
-	$(RM) $@
-	$(RM) $@.tmp $(basename $@).debuginfo
-	$(LN) -s ../$(basename $(@F)).debuginfo $(basename $@).debuginfo
-	$(CD) $(@D) && $(ZIP) -q -y $@.tmp $(basename $(@F)).debuginfo
-	$(RM) $(basename $@).debuginfo
-	$(MV) $@.tmp $@
-endif
-
-################################################################################
-
-ifeq ($(OPENJDK_TARGET_OS), windows)
-  $(eval $(call SetupCopyFiles,BASE_COPY_LIBS_BIN, \
-      SRC := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base, \
-      DEST := $(JDK_OUTPUTDIR)/bin, \
-      FILES := $(filter-out %.lib, $(BASE_TARGETS))))
-
-  $(eval $(call SetupCopyFiles,BASE_COPY_LIBS_LIB, \
-      SRC := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base, \
-      DEST := $(JDK_OUTPUTDIR)/lib, \
-      FILES := $(filter %.lib, $(BASE_TARGETS))))
-
-else
-  $(eval $(call SetupCopyFiles,BASE_COPY_LIBS, \
-      SRC := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base, \
-      DEST := $(JDK_OUTPUTDIR)/lib, \
-      FILES := $(BASE_TARGETS)))
-endif
-
-################################################################################
-
-all: $(BASE_TARGETS) $(BASE_COPY_LIBS_BIN) $(BASE_COPY_LIBS_LIB) \
-    $(BASE_COPY_LIBS)
-
-.PHONY: default all
--- a/jdk/make/ModuleTools.gmk	Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/make/ModuleTools.gmk	Wed Oct 05 06:28:23 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:42 2016 -0700
+++ b/jdk/make/lib/CoreLibraries.gmk	Wed Oct 05 06:28:23 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/rmic/RmicCommon.gmk	Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/make/rmic/RmicCommon.gmk	Wed Oct 05 06:28:23 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:23 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);
+    }
+
+}
--- /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:23 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:42 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java	Wed Oct 05 06:28:23 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:42 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/io/ObjectStreamConstants.java	Wed Oct 05 06:28:23 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:42 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/io/SerializablePermission.java	Wed Oct 05 06:28:23 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:42 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/String.java	Wed Oct 05 06:28:23 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/module/ModulePath.java	Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java	Wed Oct 05 06:28:23 2016 -0700
@@ -56,6 +56,8 @@
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
+import jdk.internal.jmod.JmodFile;
+import jdk.internal.jmod.JmodFile.Section;
 import jdk.internal.module.ConfigurableModuleFinder;
 import jdk.internal.perf.PerfCounter;
 
@@ -294,11 +296,11 @@
 
     // -- jmod files --
 
-    private Set<String> jmodPackages(ZipFile zf) {
-        return zf.stream()
-            .filter(e -> e.getName().startsWith("classes/") &&
-                    e.getName().endsWith(".class"))
-            .map(e -> toPackageName(e.getName().substring(8)))
+    private Set<String> jmodPackages(JmodFile jf) {
+        return jf.stream()
+            .filter(e -> e.section() == Section.CLASSES)
+            .map(JmodFile.Entry::name)
+            .map(this::toPackageName)
             .filter(pkg -> pkg.length() > 0) // module-info
             .collect(Collectors.toSet());
     }
@@ -311,14 +313,10 @@
      * @throws InvalidModuleDescriptorException
      */
     private ModuleReference readJMod(Path file) throws IOException {
-        try (ZipFile zf = new ZipFile(file.toString())) {
-            ZipEntry ze = zf.getEntry("classes/" + MODULE_INFO);
-            if (ze == null) {
-                throw new IOException(MODULE_INFO + " is missing: " + file);
-            }
+        try (JmodFile jf = new JmodFile(file)) {
             ModuleDescriptor md;
-            try (InputStream in = zf.getInputStream(ze)) {
-                md = ModuleDescriptor.read(in, () -> jmodPackages(zf));
+            try (InputStream in = jf.getInputStream(Section.CLASSES, MODULE_INFO)) {
+                md = ModuleDescriptor.read(in, () -> jmodPackages(jf));
             }
             return ModuleReferences.newJModModule(md, file);
         }
--- a/jdk/src/java.base/share/classes/java/net/MulticastSocket.java	Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/net/MulticastSocket.java	Wed Oct 05 06:28:23 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:42 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/text/DecimalFormat.java	Wed Oct 05 06:28:23 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/Locale.java	Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/Locale.java	Wed Oct 05 06:28:23 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) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/jmod/JmodFile.java	Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,206 @@
+/*
+ * 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 jdk.internal.jmod;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.stream.Stream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+/**
+ * Helper class to read JMOD file
+ */
+public class JmodFile implements AutoCloseable {
+    // jmod magic number and version number
+    public static final int JMOD_MAJOR_VERSION = 0x01;
+    public static final int JMOD_MINOR_VERSION = 0x00;
+    public static final byte[] JMOD_MAGIC_NUMBER = {
+        0x4A, 0x4D, /* JM */
+        JMOD_MAJOR_VERSION, JMOD_MINOR_VERSION, /* version 1.0 */
+    };
+
+    public static void checkMagic(Path file) throws IOException {
+        try (InputStream in = Files.newInputStream(file);
+             BufferedInputStream bis = new BufferedInputStream(in)) {
+            // validate the header
+            byte[] magic = new byte[4];
+            bis.read(magic);
+            if (magic[0] != JMOD_MAGIC_NUMBER[0] ||
+                magic[1] != JMOD_MAGIC_NUMBER[1]) {
+                throw new IOException("Invalid jmod file: " + file.toString());
+            }
+            if (magic[2] > JMOD_MAJOR_VERSION ||
+                (magic[2] == JMOD_MAJOR_VERSION && magic[3] > JMOD_MINOR_VERSION)) {
+                throw new IOException("Unsupported jmod version: " +
+                    magic[2] + "." + magic[3] + " in " + file.toString());
+            }
+        }
+    }
+
+    /**
+     * JMOD sections
+     */
+    public static enum Section {
+        NATIVE_LIBS("native"),
+        NATIVE_CMDS("bin"),
+        CLASSES("classes"),
+        CONFIG("conf");
+
+        private final String jmodDir;
+        private Section(String jmodDir) {
+            this.jmodDir = jmodDir;
+        }
+
+        /**
+         * Returns the directory name in the JMOD file corresponding to
+         * this section
+         */
+        public String jmodDir() { return jmodDir; }
+
+    }
+
+    /**
+     * JMOD file entry.
+     *
+     * Each entry corresponds to a ZipEntry whose name is:
+     *   Section::jmodDir + '/' + name
+     */
+    public static class Entry {
+        private final ZipEntry zipEntry;
+        private final Section section;
+        private final String name;
+
+        private Entry(ZipEntry e) {
+            String name = e.getName();
+            int i = name.indexOf('/');
+            if (i <= 1) {
+                throw new RuntimeException("invalid jmod entry: " + name);
+            }
+
+            this.zipEntry = e;
+            this.section = section(name);
+            this.name = name.substring(i+1);
+        }
+
+        /**
+         * Returns the section of this entry.
+         */
+        public Section section() {
+            return section;
+        }
+
+        /**
+         * Returns the name of this entry.
+         */
+        public String name() {
+            return name;
+        }
+
+        /**
+         * Returns the size of this entry.
+         */
+        public long size() {
+            return zipEntry.getSize();
+        }
+
+        public ZipEntry zipEntry() {
+            return zipEntry;
+        }
+
+        @Override
+        public String toString() {
+            return section.jmodDir() + "/" + name;
+        }
+
+        static Section section(String name) {
+            int i = name.indexOf('/');
+            String s = name.substring(0, i);
+            switch (s) {
+                case "native":
+                    return Section.NATIVE_LIBS;
+                case "bin":
+                    return Section.NATIVE_CMDS;
+                case "classes":
+                    return Section.CLASSES;
+                case "conf":
+                    return Section.CONFIG;
+                default:
+                    throw new IllegalArgumentException("invalid section: " + s);
+            }
+        }
+    }
+
+    private final Path file;
+    private final ZipFile zipfile;
+
+    /**
+     * Constructs a {@code JmodFile} from a given path.
+     */
+    public JmodFile(Path file) throws IOException {
+        checkMagic(file);
+        this.file = file;
+        this.zipfile = new ZipFile(file.toFile());
+    }
+
+    /**
+     * Opens an {@code InputStream} for reading the named entry of the given
+     * section in this jmod file.
+     *
+     * @throws IOException if the named entry is not found, or I/O error
+     *         occurs when reading it
+     */
+    public InputStream getInputStream(Section section, String name)
+        throws IOException
+    {
+
+        String entry = section.jmodDir() + "/" + name;
+        ZipEntry e = zipfile.getEntry(entry);
+        if (e == null) {
+            throw new IOException(name + " not found: " + file);
+        }
+        return zipfile.getInputStream(e);
+    }
+
+    /**
+     * Returns a stream of non-directory entries in this jmod file.
+     */
+    public Stream<Entry> stream() {
+        return zipfile.stream()
+                      .filter(e -> !e.isDirectory())
+                      .map(Entry::new);
+    }
+
+    @Override
+    public void close() throws IOException {
+        if (zipfile != null) {
+            zipfile.close();
+        }
+    }
+}
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java	Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java	Wed Oct 05 06:28:23 2016 -0700
@@ -163,6 +163,16 @@
      * be discarded.
      */
     public void write(OutputStream out) throws IOException {
+        // emit to the output stream
+        out.write(toByteArray());
+    }
+
+    /**
+     * Returns the bytes of the modified module-info.class.
+     * Once this method has been called then the Extender object should
+     * be discarded.
+     */
+    public byte[] toByteArray() throws IOException {
         ClassWriter cw
             = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
 
@@ -197,8 +207,7 @@
         // add any attributes that didn't replace previous attributes
         cv.finish();
 
-        // emit to the output stream
-        out.write(cw.toByteArray());
+        return cw.toByteArray();
     }
 
     /**
--- a/jdk/src/java.base/share/classes/module-info.java	Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/java.base/share/classes/module-info.java	Wed Oct 05 06:28:23 2016 -0700
@@ -124,6 +124,9 @@
         jdk.jlink;
     exports jdk.internal.jimage.decompressor to
         jdk.jlink;
+    exports jdk.internal.jmod to
+        jdk.compiler,
+        jdk.jlink;
     exports jdk.internal.logger to
         java.logging;
     exports jdk.internal.org.objectweb.asm to
--- a/jdk/src/java.base/share/conf/security/java.security	Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/java.base/share/conf/security/java.security	Wed Oct 05 06:28:23 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:42 2016 -0700
+++ b/jdk/src/java.base/unix/classes/sun/nio/fs/UnixDirectoryStream.java	Wed Oct 05 06:28:23 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.desktop/share/classes/java/beans/MetaData.java	Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/java/beans/MetaData.java	Wed Oct 05 06:28:23 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:42 2016 -0700
+++ b/jdk/src/java.rmi/share/classes/java/rmi/server/UnicastRemoteObject.java	Wed Oct 05 06:28:23 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:42 2016 -0700
+++ b/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java	Wed Oct 05 06:28:23 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:42 2016 -0700
+++ b/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef2.java	Wed Oct 05 06:28:23 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.jartool/share/classes/sun/tools/jar/Main.java	Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java	Wed Oct 05 06:28:23 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.jlink/share/classes/jdk/tools/jlink/internal/Archive.java	Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Archive.java	Wed Oct 05 06:28:23 2016 -0700
@@ -55,6 +55,13 @@
         private final Archive archive;
         private final String path;
 
+        /**
+         * Constructs an entry of the given archive
+         * @param archive archive
+         * @param path
+         * @param name an entry name that does not contain the module name
+         * @param type
+         */
         public Entry(Archive archive, String path, String name, EntryType type) {
             this.archive = Objects.requireNonNull(archive);
             this.path = Objects.requireNonNull(path);
@@ -62,25 +69,29 @@
             this.type = Objects.requireNonNull(type);
         }
 
-        public Archive archive() {
+        public final Archive archive() {
             return archive;
         }
 
-        public String path() {
-            return path;
-        }
-
-        public EntryType type() {
+        public final EntryType type() {
             return type;
         }
 
-        /*
+        /**
          * Returns the name of this entry.
          */
-        public String name() {
+        public final String name() {
             return name;
         }
 
+        /**
+         * Returns the name representing a ResourcePoolEntry in the form of:
+         *    /$MODULE/$ENTRY_NAME
+         */
+        public final String getResourcePoolEntryName() {
+            return "/" + archive.moduleName() + "/" + name;
+        }
+
         @Override
         public String toString() {
             return "type " + type.name() + " path " + path;
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/DirArchive.java	Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/DirArchive.java	Wed Oct 05 06:28:23 2016 -0700
@@ -50,7 +50,7 @@
 
         FileEntry(Path path, String name) {
             super(DirArchive.this, getPathName(path), name,
-                    Archive.Entry.EntryType.CLASS_OR_RESOURCE);
+                  Archive.Entry.EntryType.CLASS_OR_RESOURCE);
             this.path = path;
             try {
                 size = Files.size(path);
@@ -124,13 +124,7 @@
             return null;
         }
         String name = getPathName(p).substring(chop);
-        if (name.startsWith("_")) {
-            return null;
-        }
         log.accept(moduleName + "/" + name);
-        if (name.equals(MODULE_INFO)) {
-            name = moduleName + "/" + MODULE_INFO;
-        }
         return new FileEntry(p, name);
     }
 
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageFileCreator.java	Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageFileCreator.java	Wed Oct 05 06:28:23 2016 -0700
@@ -40,6 +40,7 @@
 import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
+
 import jdk.tools.jlink.internal.Archive.Entry;
 import jdk.tools.jlink.internal.Archive.Entry.EntryType;
 import jdk.tools.jlink.internal.ResourcePoolManager.CompressedModuleData;
@@ -122,10 +123,6 @@
         });
     }
 
-    public static boolean isClassPackage(String path) {
-        return path.endsWith(".class") && !path.endsWith("module-info.class");
-    }
-
     public static void recreateJimage(Path jimageFile,
             Set<Archive> archives,
             ImagePluginStack pluginSupport)
@@ -265,26 +262,13 @@
                 return writer.getString(id);
             }
         });
+
         for (Archive archive : archives) {
             String mn = archive.moduleName();
-            for (Entry entry : entriesForModule.get(mn)) {
-                String path;
-                if (entry.type() == EntryType.CLASS_OR_RESOURCE) {
-                    // Removal of "classes/" radical.
-                    path = entry.name();
-                    if (path.endsWith("module-info.class")) {
-                        path = "/" + path;
-                    } else {
-                        path = "/" + mn + "/" + path;
-                    }
-                } else {
-                    // Entry.path() contains the kind of file native, conf, bin, ...
-                    // Keep it to avoid naming conflict (eg: native/jvm.cfg and config/jvm.cfg
-                    path = "/" + mn + "/" + entry.path();
-                }
-
-                resources.add(new ArchiveEntryResourcePoolEntry(mn, path, entry));
-            }
+            entriesForModule.get(mn).stream()
+                .map(e -> new ArchiveEntryResourcePoolEntry(mn,
+                                    e.getResourcePoolEntryName(), e))
+                .forEach(resources::add);
         }
         return resources;
     }
@@ -320,6 +304,20 @@
         return result.toArray(array);
     }
 
+    /**
+     * Returns the path of the resource.
+     */
+    public static String resourceName(String path) {
+        Objects.requireNonNull(path);
+        String s = path.substring(1);
+        int index = s.indexOf("/");
+        return s.substring(index + 1);
+    }
+
+    public static String toPackage(String name) {
+        return toPackage(name, false);
+    }
+
     private static String toPackage(String name, boolean log) {
         int index = name.lastIndexOf('/');
         if (index > 0) {
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JarArchive.java	Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JarArchive.java	Wed Oct 05 06:28:23 2016 -0700
@@ -43,7 +43,7 @@
     /**
      * An entry located in a jar file.
      */
-    private class JarEntry extends Entry {
+    public class JarEntry extends Entry {
 
         private final long size;
         private final ZipEntry entry;
@@ -70,12 +70,10 @@
         }
     }
 
-    private static final String MODULE_INFO = "module-info.class";
-
     private final Path file;
     private final String moduleName;
     // currently processed ZipFile
-    private ZipFile zipFile;
+    protected ZipFile zipFile;
 
     protected JarArchive(String mn, Path file) {
         Objects.requireNonNull(mn);
@@ -110,21 +108,7 @@
 
     abstract String getFileName(String entryName);
 
-    private Entry toEntry(ZipEntry ze) {
-        String name = ze.getName();
-        String fn = getFileName(name);
-
-        if (ze.isDirectory() || fn.startsWith("_")) {
-            return null;
-        }
-
-        EntryType rt = toEntryType(name);
-
-        if (fn.equals(MODULE_INFO)) {
-            fn = moduleName + "/" + MODULE_INFO;
-        }
-        return new JarEntry(ze.getName(), fn, rt, zipFile, ze);
-    }
+    abstract Entry toEntry(ZipEntry ze);
 
     @Override
     public void close() throws IOException {
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JmodArchive.java	Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JmodArchive.java	Wed Oct 05 06:28:23 2016 -0700
@@ -25,34 +25,106 @@
 
 package jdk.tools.jlink.internal;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UncheckedIOException;
 import java.nio.file.Path;
 import java.util.Objects;
+import java.util.stream.Stream;
+
+import jdk.internal.jmod.JmodFile;
 import jdk.tools.jlink.internal.Archive.Entry.EntryType;
 
 /**
  * An Archive backed by a jmod file.
  */
-public class JmodArchive extends JarArchive {
+public class JmodArchive implements Archive {
+    private static final String JMOD_EXT    = ".jmod";
 
-    private static final String JMOD_EXT    = ".jmod";
-    private static final String MODULE_NAME = "module";
-    private static final String MODULE_INFO = "module-info.class";
-    private static final String CLASSES     = "classes";
-    private static final String NATIVE_LIBS = "native";
-    private static final String NATIVE_CMDS = "bin";
-    private static final String CONFIG      = "conf";
+    /**
+     * An entry located in a jmod file.
+     */
+    public class JmodEntry extends Entry {
+        private final JmodFile.Entry entry;
+
+        JmodEntry(String path, String name, EntryType type,
+                  JmodFile.Entry entry) {
+            super(JmodArchive.this, path, name, type);
+            this.entry = Objects.requireNonNull(entry);
+        }
+
+        /**
+         * Returns the number of uncompressed bytes for this entry.
+         */
+        @Override
+        public long size() {
+            return entry.size();
+        }
+
+        @Override
+        public InputStream stream() throws IOException {
+            return jmodFile.getInputStream(entry.section(), entry.name());
+        }
+    }
+
+    private final Path file;
+    private final String moduleName;
+    private JmodFile jmodFile;
 
     public JmodArchive(String mn, Path jmod) {
-        super(mn, jmod);
-        String filename = Objects.requireNonNull(jmod.getFileName()).toString();
+        Objects.requireNonNull(mn);
+        Objects.requireNonNull(jmod.getFileName());
+        String filename = jmod.toString();
         if (!filename.endsWith(JMOD_EXT)) {
             throw new UnsupportedOperationException("Unsupported format: " + filename);
         }
+        this.moduleName = mn;
+        this.file = jmod;
     }
 
     @Override
-    EntryType toEntryType(String entryName) {
-        String section = getSection(entryName.replace('\\', '/'));
+    public String moduleName() {
+        return moduleName;
+    }
+
+    @Override
+    public Path getPath() {
+        return file;
+    }
+
+    @Override
+    public Stream<Entry> entries() {
+        ensureOpen();
+        return jmodFile.stream()
+                       .map(this::toEntry);
+    }
+
+    @Override
+    public void open() throws IOException {
+        if (jmodFile != null) {
+            jmodFile.close();
+        }
+        this.jmodFile = new JmodFile(file);
+    }
+
+    @Override
+    public void close() throws IOException {
+        if (jmodFile != null) {
+            jmodFile.close();
+        }
+    }
+
+    private void ensureOpen() {
+        if (jmodFile == null) {
+            try {
+                open();
+            } catch(IOException ioe){
+                throw new UncheckedIOException(ioe);
+            }
+        }
+    }
+
+    private EntryType toEntryType(JmodFile.Section section) {
         switch (section) {
             case CLASSES:
                 return EntryType.CLASS_OR_RESOURCE;
@@ -62,26 +134,23 @@
                 return EntryType.NATIVE_CMD;
             case CONFIG:
                 return EntryType.CONFIG;
-            case MODULE_NAME:
-                return EntryType.MODULE_NAME;
             default:
                 throw new InternalError("unexpected entry: " + section);
         }
     }
 
-    private static String getSection(String entryName) {
-        int i = entryName.indexOf('/');
-        // Unnamed section.
-        String section = "";
-        if (i > 0) {
-            section = entryName.substring(0, entryName.indexOf('/'));
+    private Entry toEntry(JmodFile.Entry entry) {
+        EntryType type = toEntryType(entry.section());
+        String name = entry.name();
+        String path = entry.section().jmodDir() + "/" + name;
+
+        // Entry.path() contains the kind of file native, conf, bin, ...
+        // Keep it to avoid naming conflict (eg: native/jvm.cfg and config/jvm.cfg
+        String resourceName = name;
+        if (type != EntryType.CLASS_OR_RESOURCE) {
+            resourceName = path;
         }
-        return section;
-    }
 
-    @Override
-    String getFileName(String entryName) {
-        entryName = entryName.replace('\\', '/');
-        return entryName.substring(entryName.indexOf('/') + 1);
+        return new JmodEntry(path, resourceName, type, entry);
     }
 }
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModularJarArchive.java	Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModularJarArchive.java	Wed Oct 05 06:28:23 2016 -0700
@@ -27,6 +27,8 @@
 
 import java.nio.file.Path;
 import java.util.Objects;
+import java.util.zip.ZipEntry;
+
 import jdk.tools.jlink.internal.Archive.Entry.EntryType;
 
 /**
@@ -35,6 +37,7 @@
 public class ModularJarArchive extends JarArchive {
 
     private static final String JAR_EXT = ".jar";
+    private static final String MODULE_INFO = "module-info.class";
 
     public ModularJarArchive(String mn, Path jmod) {
         super(mn, jmod);
@@ -50,6 +53,17 @@
     }
 
     @Override
+    Entry toEntry(ZipEntry ze) {
+        if (ze.isDirectory()) {
+            return null;
+        }
+
+        String name = ze.getName();
+        EntryType type = toEntryType(name);
+        return new JarEntry(ze.getName(), getFileName(name), type, zipFile, ze);
+    }
+
+    @Override
     String getFileName(String entryName) {
         return entryName;
     }
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java	Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ResourcePoolManager.java	Wed Oct 05 06:28:23 2016 -0700
@@ -27,15 +27,12 @@
 import java.lang.module.ModuleDescriptor;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
-import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
-import java.util.function.Function;
 import java.util.stream.Stream;
 import jdk.internal.jimage.decompressor.CompressedResourceHeader;
 import jdk.tools.jlink.plugin.ResourcePool;
@@ -44,7 +41,6 @@
 import jdk.tools.jlink.plugin.ResourcePoolModule;
 import jdk.tools.jlink.plugin.ResourcePoolModuleView;
 import jdk.tools.jlink.plugin.PluginException;
-import jdk.tools.jlink.internal.plugins.FileCopierPlugin;
 
 /**
  * A manager for pool of resources.
@@ -100,17 +96,17 @@
         @Override
         public Set<String> packages() {
             Set<String> pkgs = new HashSet<>();
-            moduleContent.values().stream().filter(m -> m.type().
-                    equals(ResourcePoolEntry.Type.CLASS_OR_RESOURCE)).forEach(res -> {
-                // Module metadata only contains packages with .class files
-                if (ImageFileCreator.isClassPackage(res.path())) {
-                    String[] split = ImageFileCreator.splitPath(res.path());
-                    String pkg = split[1];
-                    if (pkg != null && !pkg.isEmpty()) {
-                        pkgs.add(pkg);
+            moduleContent.values().stream()
+                .filter(m -> m.type() == ResourcePoolEntry.Type.CLASS_OR_RESOURCE)
+                .forEach(res -> {
+                    String name = ImageFileCreator.resourceName(res.path());
+                    if (name.endsWith(".class") && !name.endsWith("module-info.class")) {
+                        String pkg = ImageFileCreator.toPackage(name);
+                        if (!pkg.isEmpty()) {
+                            pkgs.add(pkg);
+                        }
                     }
-                }
-            });
+                });
             return pkgs;
         }
 
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java	Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java	Wed Oct 05 06:28:23 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()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodOutputStream.java	Wed Oct 05 06:28:23 2016 -0700
@@ -0,0 +1,116 @@
+/*
+ * 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 jdk.tools.jmod;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import static jdk.internal.jmod.JmodFile.*;
+
+/**
+ * Output stream to write to JMOD file
+ */
+class JmodOutputStream extends OutputStream implements AutoCloseable {
+    /**
+     * This method creates (or overrides, if exists) the JMOD file,
+     * returning the the output stream to write to the JMOD file.
+     */
+    static JmodOutputStream newOutputStream(Path file) throws IOException {
+        OutputStream out = Files.newOutputStream(file);
+        BufferedOutputStream bos = new BufferedOutputStream(out);
+        return new JmodOutputStream(bos);
+    }
+
+    private final ZipOutputStream zos;
+    private JmodOutputStream(OutputStream out) {
+        this.zos = new ZipOutputStream(out);
+        try {
+            out.write(JMOD_MAGIC_NUMBER);
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    /**
+     * Writes the input stream to the named entry of the given section.
+     */
+    public void writeEntry(InputStream in, Section section, String name)
+        throws IOException
+    {
+        ZipEntry ze = newEntry(section, name);
+        zos.putNextEntry(ze);
+        in.transferTo(zos);
+        zos.closeEntry();
+    }
+
+    /**
+     * Writes the given bytes to the named entry of the given section.
+     */
+    public void writeEntry(byte[] bytes, Section section, String path)
+        throws IOException
+    {
+        ZipEntry ze = newEntry(section, path);
+        zos.putNextEntry(ze);
+        zos.write(bytes);
+        zos.closeEntry();
+    }
+
+    /**
+     * Writes the given entry to the given input stream.
+     */
+    public void writeEntry(InputStream in, Entry e) throws IOException {
+        zos.putNextEntry(e.zipEntry());
+        zos.write(in.readAllBytes());
+        zos.closeEntry();
+    }
+
+    private ZipEntry newEntry(Section section, String path) {
+        String prefix = section.jmodDir();
+        String name = Paths.get(prefix, path).toString()
+                           .replace(File.separatorChar, '/');
+        return new ZipEntry(name);
+    }
+
+    @Override
+    public void write(int b) throws IOException {
+        zos.write(b);
+    }
+
+    @Override
+    public void close() throws IOException {
+        zos.close();
+    }
+}
+
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java	Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java	Wed Oct 05 06:28:23 2016 -0700
@@ -25,8 +25,6 @@
 
 package jdk.tools.jmod;
 
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -60,7 +58,6 @@
 import java.text.MessageFormat;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
@@ -80,15 +77,16 @@
 import java.util.function.Supplier;
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
+import java.util.jar.JarOutputStream;
 import java.util.stream.Collectors;
 import java.util.regex.Pattern;
 import java.util.regex.PatternSyntaxException;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipException;
 import java.util.zip.ZipFile;
-import java.util.zip.ZipInputStream;
-import java.util.zip.ZipOutputStream;
 
+import jdk.internal.jmod.JmodFile;
+import jdk.internal.jmod.JmodFile.Section;
 import jdk.internal.joptsimple.BuiltinHelpFormatter;
 import jdk.internal.joptsimple.NonOptionArgumentSpec;
 import jdk.internal.joptsimple.OptionDescriptor;
@@ -250,23 +248,14 @@
     }
 
     private boolean describe() throws IOException {
-        ZipFile zip = null;
-        try {
-            try {
-                zip = new ZipFile(options.jmodFile.toFile());
-            } catch (IOException x) {
-                throw new IOException("error opening jmod file", x);
+        try (JmodFile jf = new JmodFile(options.jmodFile)) {
+            try (InputStream in = jf.getInputStream(Section.CLASSES, MODULE_INFO)) {
+                ModuleDescriptor md = ModuleDescriptor.read(in);
+                printModuleDescriptor(md);
+                return true;
+            } catch (IOException e) {
+                throw new CommandException("err.module.descriptor.not.found");
             }
-
-            try (InputStream in = Files.newInputStream(options.jmodFile)) {
-                boolean found = printModuleDescriptor(in);
-                if (!found)
-                    throw new CommandException("err.module.descriptor.not.found");
-                return found;
-            }
-        } finally {
-            if (zip != null)
-                zip.close();
         }
     }
 
@@ -278,65 +267,52 @@
 
     private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess();
 
-    private boolean printModuleDescriptor(InputStream in)
+    private void printModuleDescriptor(ModuleDescriptor md)
         throws IOException
     {
-        final String mi = Section.CLASSES.jmodDir() + "/" + MODULE_INFO;
-        try (BufferedInputStream bis = new BufferedInputStream(in);
-             ZipInputStream zis = new ZipInputStream(bis)) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("\n").append(md.toNameAndVersion());
 
-            ZipEntry e;
-            while ((e = zis.getNextEntry()) != null) {
-                if (e.getName().equals(mi)) {
-                    ModuleDescriptor md = ModuleDescriptor.read(zis);
-                    StringBuilder sb = new StringBuilder();
-                    sb.append("\n").append(md.toNameAndVersion());
+        md.requires().stream()
+            .sorted(Comparator.comparing(Requires::name))
+            .forEach(r -> {
+                sb.append("\n  requires ");
+                if (!r.modifiers().isEmpty())
+                    sb.append(toString(r.modifiers())).append(" ");
+                sb.append(r.name());
+            });
 
-                    md.requires().stream()
-                        .sorted(Comparator.comparing(Requires::name))
-                        .forEach(r -> {
-                            sb.append("\n  requires ");
-                            if (!r.modifiers().isEmpty())
-                                sb.append(toString(r.modifiers())).append(" ");
-                            sb.append(r.name());
-                        });
+        md.uses().stream().sorted()
+            .forEach(s -> sb.append("\n  uses ").append(s));
 
-                    md.uses().stream().sorted()
-                        .forEach(s -> sb.append("\n  uses ").append(s));
+        md.exports().stream()
+            .sorted(Comparator.comparing(Exports::source))
+            .forEach(p -> sb.append("\n  exports ").append(p));
 
-                    md.exports().stream()
-                        .sorted(Comparator.comparing(Exports::source))
-                        .forEach(p -> sb.append("\n  exports ").append(p));
+        md.conceals().stream().sorted()
+            .forEach(p -> sb.append("\n  conceals ").append(p));
 
-                    md.conceals().stream().sorted()
-                        .forEach(p -> sb.append("\n  conceals ").append(p));
+        md.provides().values().stream()
+            .sorted(Comparator.comparing(Provides::service))
+            .forEach(p -> sb.append("\n  provides ").append(p.service())
+                .append(" with ")
+                .append(toString(p.providers())));
 
-                    md.provides().values().stream()
-                        .sorted(Comparator.comparing(Provides::service))
-                        .forEach(p -> sb.append("\n  provides ").append(p.service())
-                                        .append(" with ")
-                                        .append(toString(p.providers())));
+        md.mainClass().ifPresent(v -> sb.append("\n  main-class " + v));
 
-                    md.mainClass().ifPresent(v -> sb.append("\n  main-class " + v));
+        md.osName().ifPresent(v -> sb.append("\n  operating-system-name " + v));
 
-                    md.osName().ifPresent(v -> sb.append("\n  operating-system-name " + v));
+        md.osArch().ifPresent(v -> sb.append("\n  operating-system-architecture " + v));
 
-                    md.osArch().ifPresent(v -> sb.append("\n  operating-system-architecture " + v));
+        md.osVersion().ifPresent(v -> sb.append("\n  operating-system-version " + v));
 
-                    md.osVersion().ifPresent(v -> sb.append("\n  operating-system-version " + v));
+        JLMA.hashes(md).ifPresent(
+            hashes -> hashes.names().stream().sorted().forEach(
+                mod -> sb.append("\n  hashes ").append(mod).append(" ")
+                    .append(hashes.algorithm()).append(" ")
+                    .append(hashes.hashFor(mod))));
 
-                    JLMA.hashes(md).ifPresent(
-                            hashes -> hashes.names().stream().sorted().forEach(
-                                    mod -> sb.append("\n  hashes ").append(mod).append(" ")
-                                             .append(hashes.algorithm()).append(" ")
-                                             .append(hashes.hashFor(mod))));
-
-                    out.println(sb.toString());
-                    return true;
-                }
-            }
-        }
-        return false;
+        out.println(sb.toString());
     }
 
     private boolean create() throws IOException {
@@ -347,9 +323,8 @@
         Path target = options.jmodFile;
         Path tempTarget = target.resolveSibling(target.getFileName() + ".tmp");
         try {
-            try (OutputStream out = Files.newOutputStream(tempTarget);
-                 BufferedOutputStream bos = new BufferedOutputStream(out)) {
-                jmod.write(bos);
+            try (JmodOutputStream jos = JmodOutputStream.newOutputStream(tempTarget)) {
+                jmod.write(jos);
             }
             Files.move(tempTarget, target);
         } catch (Exception e) {
@@ -383,19 +358,16 @@
         /**
          * Writes the jmod to the given output stream.
          */
-        void write(OutputStream out) throws IOException {
-            try (ZipOutputStream zos = new ZipOutputStream(out)) {
+        void write(JmodOutputStream out) throws IOException {
+            // module-info.class
+            writeModuleInfo(out, findPackages(classpath));
 
-                // module-info.class
-                writeModuleInfo(zos, findPackages(classpath));
+            // classes
+            processClasses(out, classpath);
 
-                // classes
-                processClasses(zos, classpath);
-
-                processSection(zos, Section.NATIVE_CMDS, cmds);
-                processSection(zos, Section.NATIVE_LIBS, libs);
-                processSection(zos, Section.CONFIG, configs);
-            }
+            processSection(out, Section.NATIVE_CMDS, cmds);
+            processSection(out, Section.NATIVE_LIBS, libs);
+            processSection(out, Section.CONFIG, configs);
         }
 
         /**
@@ -441,7 +413,7 @@
          * then the corresponding class file attributes are added to the
          * module-info here.
          */
-        void writeModuleInfo(ZipOutputStream zos, Set<String> packages)
+        void writeModuleInfo(JmodOutputStream out, Set<String> packages)
             throws IOException
         {
             Supplier<InputStream> miSupplier = newModuleInfoSupplier();
@@ -492,11 +464,7 @@
                 }
 
                 // write the (possibly extended or modified) module-info.class
-                String e = Section.CLASSES.jmodDir() + "/" + MODULE_INFO;
-                ZipEntry ze = new ZipEntry(e);
-                zos.putNextEntry(ze);
-                extender.write(zos);
-                zos.closeEntry();
+                out.writeEntry(extender.toByteArray(), Section.CLASSES, MODULE_INFO);
             }
         }
 
@@ -627,7 +595,7 @@
                 return "";
         }
 
-        void processClasses(ZipOutputStream zos, List<Path> classpaths)
+        void processClasses(JmodOutputStream zos, List<Path> classpaths)
             throws IOException
         {
             if (classpaths == null)
@@ -645,7 +613,7 @@
             }
         }
 
-        void processSection(ZipOutputStream zos, Section section, List<Path> paths)
+        void processSection(JmodOutputStream zos, Section section, List<Path> paths)
             throws IOException
         {
             if (paths == null)
@@ -655,11 +623,9 @@
                 processSection(zos, section, p);
         }
 
-        void processSection(ZipOutputStream zos, Section section, Path top)
+        void processSection(JmodOutputStream out, Section section, Path top)
             throws IOException
         {
-            final String prefix = section.jmodDir();
-
             Files.walkFileTree(top, new SimpleFileVisitor<Path>() {
                 @Override
                 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
@@ -667,13 +633,19 @@
                 {
                     Path relPath = top.relativize(file);
                     if (relPath.toString().equals(MODULE_INFO)
-                            && !Section.CLASSES.equals(section))
+                        && !Section.CLASSES.equals(section))
                         warning("warn.ignore.entry", MODULE_INFO, section);
 
                     if (!relPath.toString().equals(MODULE_INFO)
-                            && !matches(relPath, excludes)) {
+                        && !matches(relPath, excludes)) {
                         try (InputStream in = Files.newInputStream(file)) {
-                            writeZipEntry(zos, in, prefix, relPath.toString());
+                            out.writeEntry(in, section, relPath.toString());
+                        } catch (IOException x) {
+                            if (x.getMessage().contains("duplicate entry")) {
+                                warning("warn.ignore.duplicate.entry", relPath.toString(), section);
+                                return FileVisitResult.CONTINUE;
+                            }
+                            throw x;
                         }
                     }
                     return FileVisitResult.CONTINUE;
@@ -691,36 +663,17 @@
             return false;
         }
 
-        void writeZipEntry(ZipOutputStream zos, InputStream in, String prefix, String other)
-            throws IOException
-        {
-            String name = Paths.get(prefix, other).toString()
-                               .replace(File.separatorChar, '/');
-            ZipEntry ze = new ZipEntry(name);
-            try {
-                zos.putNextEntry(ze);
-                in.transferTo(zos);
-                zos.closeEntry();
-            } catch (ZipException x) {
-                if (x.getMessage().contains("duplicate entry")) {
-                    warning("warn.ignore.duplicate.entry", name, prefix);
-                    return;
-                }
-                throw x;
-            }
-        }
-
         class JarEntryConsumer implements Consumer<JarEntry>, Predicate<JarEntry> {
-            final ZipOutputStream zos;
+            final JmodOutputStream out;
             final JarFile jarfile;
-            JarEntryConsumer(ZipOutputStream zos, JarFile jarfile) {
-                this.zos = zos;
+            JarEntryConsumer(JmodOutputStream out, JarFile jarfile) {
+                this.out = out;
                 this.jarfile = jarfile;
             }
             @Override
             public void accept(JarEntry je) {
                 try (InputStream in = jarfile.getInputStream(je)) {
-                    writeZipEntry(zos, in, Section.CLASSES.jmodDir(), je.getName());
+                    out.writeEntry(in, Section.CLASSES, je.getName());
                 } catch (IOException e) {
                     throw new UncheckedIOException(e);
                 }
@@ -947,29 +900,11 @@
         {
             Path target = moduleNameToPath.get(name);
             Path tempTarget = target.resolveSibling(target.getFileName() + ".tmp");
-            ZipFile zip = new ZipFile(target.toFile());
             try {
-                try (OutputStream out = Files.newOutputStream(tempTarget);
-                     ZipOutputStream zos = new ZipOutputStream(out)) {
-                    zip.stream().forEach(e -> {
-                        try {
-                            InputStream in = zip.getInputStream(e);
-                            if (e.getName().equals(MODULE_INFO) ||
-                                e.getName().equals(Section.CLASSES.jmodDir() + "/" + MODULE_INFO)) {
-                                ZipEntry ze = new ZipEntry(e.getName());
-                                ze.setTime(System.currentTimeMillis());
-                                zos.putNextEntry(ze);
-                                recordHashes(in, zos, moduleHashes);
-                                zos.closeEntry();
-                            } else {
-                                zos.putNextEntry(e);
-                                zos.write(in.readAllBytes());
-                                zos.closeEntry();
-                            }
-                        } catch (IOException x) {
-                            throw new UncheckedIOException(x);
-                        }
-                    });
+                if (target.getFileName().toString().endsWith(".jmod")) {
+                    updateJmodFile(target, tempTarget, moduleHashes);
+                } else {
+                    updateModularJar(target, tempTarget, moduleHashes);
                 }
             } catch (IOException|RuntimeException e) {
                 if (Files.exists(tempTarget)) {
@@ -980,13 +915,67 @@
                     }
                 }
                 throw e;
-            } finally {
-                zip.close();
             }
+
             out.println(getMessage("module.hashes.recorded", name));
             Files.move(tempTarget, target, StandardCopyOption.REPLACE_EXISTING);
         }
 
+        private void updateModularJar(Path target, Path tempTarget,
+                                      ModuleHashes moduleHashes)
+            throws IOException
+        {
+            try (JarFile jf = new JarFile(target.toFile());
+                 OutputStream out = Files.newOutputStream(tempTarget);
+                 JarOutputStream jos = new JarOutputStream(out))
+            {
+                jf.stream().forEach(e -> {
+                    try (InputStream in = jf.getInputStream(e)) {
+                        if (e.getName().equals(MODULE_INFO)) {
+                            // what about module-info.class in versioned entries?
+                            ZipEntry ze = new ZipEntry(e.getName());
+                            ze.setTime(System.currentTimeMillis());
+                            jos.putNextEntry(ze);
+                            recordHashes(in, jos, moduleHashes);
+                            jos.closeEntry();
+                        } else {
+                            jos.putNextEntry(e);
+                            jos.write(in.readAllBytes());
+                            jos.closeEntry();
+                        }
+                    } catch (IOException x) {
+                        throw new UncheckedIOException(x);
+                    }
+                });
+            }
+        }
+
+        private void updateJmodFile(Path target, Path tempTarget,
+                                    ModuleHashes moduleHashes)
+            throws IOException
+        {
+
+            try (JmodFile jf = new JmodFile(target);
+                 JmodOutputStream jos = JmodOutputStream.newOutputStream(tempTarget))
+            {
+                jf.stream().forEach(e -> {
+                    try (InputStream in = jf.getInputStream(e.section(), e.name())) {
+                        if (e.name().equals(MODULE_INFO)) {
+                            // replace module-info.class
+                            ModuleInfoExtender extender =
+                                ModuleInfoExtender.newExtender(in);
+                            extender.hashes(moduleHashes);
+                            jos.writeEntry(extender.toByteArray(), e.section(), e.name());
+                        } else {
+                            jos.writeEntry(in, e);
+                        }
+                    } catch (IOException x) {
+                        throw new UncheckedIOException(x);
+                    }
+                });
+            }
+        }
+
         private Path moduleToPath(String name) {
             ModuleReference mref = moduleFinder.find(name).orElseThrow(
                 () -> new InternalError("Selected module " + name + " not on module path"));
@@ -1001,22 +990,6 @@
         }
     }
 
-    enum Section {
-        NATIVE_LIBS("native"),
-        NATIVE_CMDS("bin"),
-        CLASSES("classes"),
-        CONFIG("conf"),
-        UNKNOWN("unknown");
-
-        private final String jmodDir;
-
-        Section(String jmodDir) {
-            this.jmodDir = jmodDir;
-        }
-
-        String jmodDir() { return jmodDir; }
-    }
-
     static class ClassPathConverter implements ValueConverter<Path> {
         static final ValueConverter<Path> INSTANCE = new ClassPathConverter();
 
--- a/jdk/test/ProblemList.txt	Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/test/ProblemList.txt	Wed Oct 05 06:28:23 2016 -0700
@@ -134,6 +134,8 @@
 
 java/lang/instrument/BootClassPath/BootClassPathTest.sh         8072130 macosx-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
 
--- a/jdk/test/com/sun/crypto/provider/Cipher/PBE/TestCipherPBECons.java	Fri Sep 30 02:52:42 2016 -0700
+++ b/jdk/test/com/sun/crypto/provider/Cipher/PBE/TestCipherPBECons.java	Wed Oct 05 06:28:23 2016 -0700
@@ -36,7 +36,6 @@
  * @author Yun Ke
  * @author Bill Situ
  * @author Yu-Ching (Valerie) PENG
- * @run main TestCipherKeyWrapperPBEKey
  */
 public class TestCipherPBECons {
 
--- a/jdk/test/java/beans/XMLEncoder/EnumPrivate.java	Fri Sep 30 02:52:42 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:42 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:42 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:42 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:42 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:42 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:42 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:42 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:42 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:42 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:42 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:42 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:23 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:23 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:23 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:23 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:23 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},